« Back to Development

Service Builder

The official documentation for Service Builder is at the Liferay Developer Network: https://dev.liferay.com/develop/tutorials/-/knowledge_base/6-2/service-builder

Introduction #

The Service Builder is a tool built by Liferay to automate the creation of interfaces and classes that are used by a given portal or portlet. This includes code for EJBs, Spring, Persistence, and Model.

The input to the Service Builder is an XML file, typically /ext/ext-ejb/service.xml. For a complete description of the service.xml syntax refer to the well documented DTD at http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd

Value Object Model Classes #

Since 4.2, the Service Builder has changed the way value object model classes are generated. Now, interfaces for all model classes are placed into the portal-service.jar. Why would you want to do this? So that the portal-service.jar can be made accessible by WARs that are deployed outside of the classpath of the main code base.

Take for instance the Contact family of classes:

All the classes are generated by Service Builder and should not be modified, with the exception of ContactImpl. Let's look at what each of these classes does.

com.liferay.portal.model.BaseModel #

This interface is the base interface for all model classes found in Liferay. The only methods defined in this interface identify whether or not this value object model is new. Ultimately, the persistent layer uses this method to determine whether to update or add a new entry in the persistence.

com.liferay.portal.model.impl.BaseModelImpl #

This abstract class simply implements BaseModel.

com.liferay.portal.model.ContactModel #

This interface provides a representation of a particular entry in the persistence. For example, there can be one ContactModel representing Joe Bloggs and another representing John Smith.

com.liferay.portal.model.impl.ContactModelImpl #

This class has the implementation of the methods defined in ContactModel. Note that there is no direct connection to one another.

com.liferay.portal.model.Contact #

This interface describes extra helper methods that a developer may find useful when dealing with a given contact. Hence, the developer may want to get the first name or last name of the contact. Note that these entries are not persisted in the Contact_ table but are simply helper methods. This is the value object model that most developers will see -- both returned by the various services and accessible in a separate WAR.

com.liferay.portal.model.impl.ContactImpl #

It is here that the developer actually implements the helper methods found in the Contact interface. What is really happening when a helper method is called?

 public static String getFullName(
         String firstName, String middleName, String lastName) {
     if (Validator.isNull(middleName)) {
         return firstName + StringPool.SPACE + lastName;
     }
     else {
         return firstName + StringPool.SPACE + middleName +
             StringPool.SPACE + lastName;
     }
 }
 public String getFullName() {
     return getFullName(getFirstName(), getMiddleName(), getLastName());
 }

The getFullName() helper method is actually combining the first name, middle name, and last name of a given contact to form a full name.

So, how do you actually get these method signatures defined in the Contact interface if you are never to edit that file? Service Builder. You simply add the new method to the ContactImpl class, run the build-service target for the corresponding service.xml file and the Service Builder will propagate all the needed signatures.

Service Classes #

The class diagram of the MODEL, PERSISTENCE & SERVICE

Persistence Classes #

Create your own service.xml #

The input to the Service Builder is an XML file, typically /ext/ext-ejb/service.xml. For a complete description of the service.xml syntax refer to the well documented DTD at http://www.liferay.com/dtd/liferay-service-builder_6_0_0.dtd

Create a column with no default datatype #

If you look at portal/portal-ejb/classes/com/liferay/portal/service.xml you'll find many examples like this one

<column name="groups" type="Collection" entity="Group" mapping-table="Groups_Orgs" />

from the entity "Organization".

If you'd like to create your own service.xml (e.g. ext/ext-ejb/service.xml) don't reuse this line as it is within your own entity. You'll get this output

     [java] java.lang.ArrayIndexOutOfBoundsException: -1
     [java]     at java.util.ArrayList.get(ArrayList.java:323)
     [java]     at com.liferay.portal.tools.ServiceBuilder.getEntity(ServiceBuilder.java:713)
     [java]     at com.liferay.portal.tools.ServiceBuilder._createPersistence(ServiceBuilder.java:2283)
     [java]     at com.liferay.portal.tools.ServiceBuilder.<init>(ServiceBuilder.java:646)
     [java]     at com.liferay.portal.tools.ServiceBuilder.<init>(ServiceBuilder.java:330)
     [java]     at com.liferay.portal.tools.ServiceBuilder.main(ServiceBuilder.java:86)

while running 'ant service-build' and your entity won't be created. The reason is, that the Service-Builder will look for each entity, that does not contain a '.' within it's name, within your 'service.xml'. The entity Group is specified within 'portal/portal-ejb/classes/com/liferay/portal/service.xml', so you have to set up the full qualified name of 'Group' within the entity attribute.

<column name="groups" type="Collection" entity="com.liferay.portal.Group" mapping-table="Groups_Orgs" />

The full qualified name is not the full qualified name of the generated interface

com.liferay.portal.model.Group

It is the path, where the Service-Builder will look after the service.xml.

com.liferay.portal.Group

will be resolved to relativ path

src/com/liferay/portal/service.xml

The Service-Builder assumes, that within this service.xml, the entity Group is declared. If you get an output like this

     [java] java.lang.NullPointerException
     [java]     at java.io.Reader.<init>(Reader.java:61)
     [java]     at java.io.InputStreamReader.<init>(InputStreamReader.java:55)
     [java]     at com.liferay.util.StringUtil.read(StringUtil.java:320)
     [java]     at com.liferay.util.StringUtil.read(StringUtil.java:316)
     [java]     at com.liferay.portal.tools.ServiceBuilder.getEntity(ServiceBuilder.java:731)
     [java]     at com.liferay.portal.tools.ServiceBuilder._createPersistence(ServiceBuilder.java:2283)
     [java]     at com.liferay.portal.tools.ServiceBuilder.<init>(ServiceBuilder.java:646)
     [java]     at com.liferay.portal.tools.ServiceBuilder.<init>(ServiceBuilder.java:330)
     [java]     at com.liferay.portal.tools.ServiceBuilder.main(ServiceBuilder.java:86)

while running ant build-service, the service.xml could not be found in the path you specified.

Permissions Filtering #

Finder methods are created automatically but these will return all the results. FilterFindBy method can also be generated under certain conditions and they will return the results filtered by permissions. The conditions are:

  1. the entity has a simple primitive pk
  2. the entity has permission checke registered in resource-actions/....xml
  3. the entity has user id an group id fields
  4. the finder method has group id in it

See Also #

0 Attachments
147343 Views
Average (8 Votes)
The average rating is 2.25 stars out of 5.
Comments
Threaded Replies Author Date
i am getting this error. it do create class... Adeela Huma March 19, 2009 12:20 AM
You are using some keywords in your service.xml... petar banicevic July 14, 2009 6:00 PM
I am getting this error..when i am doing... Yogesh Prabhu March 18, 2010 9:56 PM
The error is as follows:... Yogesh Prabhu March 18, 2010 10:02 PM
Are there any changes in the service builder... Gaurang G September 17, 2010 12:32 AM
There are two aditions in the dtd for LR600.DTD... Antonio Ivars October 14, 2010 12:25 AM
Is there any "reverse engineering" way? I mean,... Puj Z October 22, 2010 4:39 AM
Wow, great entry, thanks a lot!!! I have a... Luis Rodríguez Fernández November 24, 2010 12:17 AM
Hi liferay, You guys are applying some logic on... amit mahajan September 21, 2011 12:55 AM
#Amit: There is a lot you can do with... Apurv Chandra November 24, 2011 9:01 AM
How about defining the column lengths? 75... Mikko Torri December 13, 2011 6:36 AM
You have to do this in... Dirk Ulrich January 5, 2012 3:03 AM
Hello, i am getting this error following the... alex marroquin March 8, 2012 11:28 PM

i am getting this error. it do create class files but they are empty..

07:17:52,513 ERROR [java:355] PARSER_ERROR
E:\liferay\ext\ext-impl\ServiceBuilder.temp:38:16: unexpected token: com
at de.hunsicker.jalopy.language.antlr.InternalJavaParser.typeDefinitionInternal(Int­ernalJavaParser.java:660)
at de.hunsicker.jalopy.language.antlr.InternalJavaParser.typeDefinition(InternalJav­aParser.java:465)
at de.hunsicker.jalopy.language.antlr.InternalJavaParser.parse(InternalJavaParser.j­ava:308)
at de.hunsicker.jalopy.language.JavaRecognizer.parse(JavaRecognizer.java:588)
at de.hunsicker.jalopy.Jalopy.parse(Jalopy.java:1212)
at de.hunsicker.jalopy.Jalopy.format(Jalopy.java:1044)
at de.hunsicker.jalopy.Jalopy.format(Jalopy.java:1017)
at de.hunsicker.jalopy.language.antlr.InternalJavaParser.parse(InternalJavaParser.j­ava:296)
at de.hunsicker.jalopy.language.JavaRecognizer.parse(JavaRecognizer.java:588)
at de.hunsicker.jalopy.Jalopy.parse(Jalopy.java:1212)
at de.hunsicker.jalopy.Jalopy.format(Jalopy.java:1044)
at de.hunsicker.jalopy.Jalopy.format(Jalopy.java:1017)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.writeFile(ServiceBuilder.­java:317)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder._createModel(ServiceBuild­er.java:1882)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.jav­a:932)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.jav­a:393)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.main(ServiceBuilder.java:­159)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.writeFile(ServiceBuilder.­java:317)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder._createModel(ServiceBuild­er.java:1882)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.jav­a:932)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.<init>(ServiceBuilder.jav­a:393)
at com.liferay.portal.tools.servicebuilder.ServiceBuilder.main(ServiceBuilder.java:­159)
07:17:52,513 ERROR [io:1071] UNKNOWN_ERROR
expecting EOF, found '}'
Posted on 3/19/09 12:20 AM.
You are using some keywords in your service.xml that are reserved. Please try to avoid java keywords as column names such as "new" etc,
Posted on 7/14/09 6:00 PM in reply to Adeela Huma.
I am getting this error..when i am doing build-service..
Can u please provide a solution..
I am not able to understand what the error is?
Is it a problem with the Portal Source Code..
Posted on 3/18/10 9:56 PM.
The error is as follows:
http://www.liferay.com/community/forums/-/message_boards/message/4737773­..

On this page there is a error-db.doc file..
That contains a screenshot of the error..
help me with a solution please..
Posted on 3/18/10 10:02 PM in reply to Yogesh Prabhu.
Are there any changes in the service builder for Liferay 6?
Posted on 9/17/10 12:32 AM.
There are two aditions in the dtd for LR600.DTD

It has been added a "filter-primary CDATA #IMPLIED" for the create sequence SQL statement (Line 275)

Copied from the DTD:
"The filter-primary value specifies the column to use as the primary key column when using filter finders. Only one column should ever have this value set to true. If no column has this set to true, then the default primary column be used."

It has been added as well a "arrayable-operator CDATA #IMPLIED" for the finder query. (Line 408)

Copied from the DTD:
"The attribute arrayable-operator takes in the values AND or OR and will generate an additional finder where this column's parameter takes an array instead of a single value. Every value in this array will be compared with the column using the comparator, and the conditions will be combined with either an AND or OR operator. For example, a finder column with the = comparator and an arrayable-operator of OR will act like an IN clause."


Related with the Service Builder's usage, I guess it's still the same, but I cannot swear it... yet.
Posted on 10/14/10 12:25 AM in reply to Gaurang G.
Is there any "reverse engineering" way? I mean, when you already have some tables and you want to generate the service.xml file.
Helps would be appreciated! emoticon
Posted on 10/22/10 4:39 AM.
Wow, great entry, thanks a lot!!!

I have a doubt. I have tried to build the ReportsEntry service builder that it comes with the liferay-portal-ext-5.2.3. It seems to work fine, I can see the services, the impls, and I can also deploy the reports portlet, the ext-impl.jar and the ext-service.jar. As I can see the service builder has also created the hibernate mappings for me, so is it not suppose that it also should create the database entity ReportsEntry?

I think I'm missing something...

Thanks a lot,

Luis
Posted on 11/24/10 12:17 AM.
Hi liferay,
You guys are applying some logic on a xml file and generating code, why not to make that logic available in xml file itself and allow it to be configurable.

How about giving control for changing package strutcture, generating more code, all this will be very useful, kindly follow spring like style and add this feature. (One more control xml to control/configure the generated code.)
Posted on 9/21/11 12:55 AM in reply to Luis Rodríguez Fernández.
#Amit: There is a lot you can do with service.xml read the documented DTD you will be able to understand.
Posted on 11/24/11 9:01 AM in reply to amit mahajan.
How about defining the column lengths?

75 chars for a string isn't a lot.
Posted on 12/13/11 6:36 AM in reply to Apurv Chandra.
You have to do this in src/META-INF/portlet-model-hints.xml:
<model name="your.EntityClass">
<field name="language" type="String">
<hint name="max-length">3</hint>
</field>
</model>
Posted on 1/5/12 3:03 AM in reply to Mikko Torri.
Hello, i am getting this error following the liferay in action book bye Richard Sezov, in chapter 3.

C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-registration-portlet>ant bu
ild-service
Buildfile: C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-registration-por
tlet\build.­xml

build-service:
Copying 1 file to C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\produ
ct-registration-portlet\docroo­t\WEB-INF\classes
Loading jar:file:/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.23/webap
ps/ROOT/WEB-INF/lib/­portal-impl.jar!/system.properties
mar 08, 2012 10:25:08 PM com.liferay.portal.kernel.log.Jdk14LogImpl
info
Informaci¾n: Global lib directory /C:/liferay-portal-6.1.0-ce-ga1/to
mcat-7.0.23/lib/ext/
mar 08, 2012 10:25:08 PM com.liferay.portal.kernel.log.Jdk14LogImpl
info
Informaci¾n: Portal lib directory /C:/liferay-portal-6.1.0-ce-ga1/to
mcat-7.0.23/webapps/ROOT/WEB-INF/lib/
22:25:08,436 INFO [EasyConf:122] Refreshed the configuration of all
components
22:25:08,990 INFO [ConfigurationLoader:56] Properties for jar:file:
/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.23/webapps/ROOT/WEB-INF/lib/­portal-im
pl.jar!/portal loaded from [jar:file:/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.
23/webapps/ROOT/WEB-INF/lib­/portal-impl.jar!/com/liferay/portal/tools/dependenci
es/portal-tools.properties,­ jar:file:/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.
23/webapps/ROOT/WEB-INF/lib/­portal-impl.jar!/portal.properties]
Loading jar:file:/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.23/webap
ps/ROOT/WEB-INF/lib/­portal-impl.jar!/portal.properties
Loading jar:file:/C:/liferay-portal-6.1.0-ce-ga1/tomcat-7.0.23/webap
ps/ROOT/WEB-INF/lib/­portal-impl.jar!/com/liferay/portal/tools/dependencies/porta
l-tools.properties
Building PRProduct
Deleting: C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-regis
tration-portlet\Servic­eBuilder.temp

compile-java:
Compiling 4 source files to C:\liferay-plugins-sdk-6.1.0-ce-ga1\port
lets\product-registration-portlet\docroo­t\WEB-INF\service-classes
----------
1. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lService.java (at line 239)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
2. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lService.java (at line 239)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
----------
3. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceClp.java (at line 24)
public class PRProductLocalServiceClp implements PRProductLocalS
ervice {
^^^^^^^^^^^^^^^^^^^^^^^^
The type PRProductLocalServiceClp must implement the inherited abstr
act method PRProductLocalService.addProduct(PRProduct, long)
----------
4. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceClp.java (at line 92)
"addProduct", PRProduct.class, long.class);
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
5. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceClp.java (at line 560)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
6. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceClp.java (at line 560)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
7. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceClp.java (at line 589)
return (PRProduct)ClpSerializer.translateOutput(returnObj);
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
----------
8. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceUtil.java (at line 265)
public static PRProduct addProduct(PRProduct newProduct, long us
erId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
9. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-reg
istration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrati
on\service\PRProductLoca­lServiceUtil.java (at line 265)
public static PRProduct addProduct(PRProduct newProduct, long us
erId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
----------
10. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-re
gistration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrat
ion\service\PRProductLoca­lServiceWrapper.java (at line 28)
public class PRProductLocalServiceWrapper implements PRProductLo
calService,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The type PRProductLocalServiceWrapper must implement the inherited a
bstract method PRProductLocalService.addProduct(PRProduct, long)
----------
11. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-re
gistration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrat
ion\service\PRProductLoca­lServiceWrapper.java (at line 258)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
12. ERROR in C:\liferay-plugins-sdk-6.1.0-ce-ga1\portlets\product-re
gistration-portlet\docroo­t\WEB-INF\service\com\inkwell\internet\productregistrat
ion\service\PRProductLoca­lServiceWrapper.java (at line 258)
public PRProduct addProduct(PRProduct newProduct, long userId)
^^^^^^^^^
PRProduct cannot be resolved to a type
----------
12 problems (12 errors)

BUILD FAILED
C:\liferay-plugins-sdk-6.1.0-ce-ga1\build-common-plugin.xml:212: The following e
rror occurred while executing this line:
C:\liferay-plugins-sdk-6.1.0-ce-ga1\build-common.xml:94: Compile failed; see the
compiler error output for details.

Total time: 13 seconds

HELP PLEASE
Posted on 3/8/12 11:28 PM.