Liferay Service Builder Custom Service Methods

Introduction:
 
Liferay Service Builder is a tool to generate service layer to liferay portlets. It will create all necessary CRUD operation related classes and respective methods.
 
We will use  Util classes’ methods to perform CRUD operations in portlet development.
The following is the tutorial about Service Builder.
 
 
Liferay Service Builder have provided some Util classes so that we can use those classes and its methods
 
The following are the important Service Util classes we will use
 
 
XXXLocalServiceUtil
XXXServiceUtil
XXXUtil
 
XXX is your entity name in service.xml file example say Student is your entity name.
 
StudentLocalServiceUtil
StudentServiceUtil
StidentUtil
 
 
XXXLocalServiceUtil (StudentLocalServiceUtil)
 
All important CRUD operation related methods will be available. We can use this class anywhere in our code implementation i.e. when we want to interacts with database. The operations are like add, update, delete, and read.
 
When we call methods from this classes there is no security check applied or there no permission checking applicable.
 
XXXServiceUtil(StudentServiceUtil)
 
This class is similar to Local Service Util and available all CRUD operation methods but here it will use some security checks and permission checking are applied when we call the methods. If the user does not have required permissions then it will throw  Principle Exception
 
Scenario:
 
Use some XXXServiceUtil method in JSP page and access the page as Guest User then you can get  Principle Exception

Same page you can access after login as Admin then no exception will be thrown.
 
Generally this class will use to perform admin related task if we call this method in Guest user mode then it will throw the exception
 
 
Principle Exception
 
XXXUtil (StudenUtil)
 
This class especially for finder methods and all finder methods will be available.
 
Generally in liferay we can create finder methods with help of  service.xmlfile
 
We will use following tag in  service.xml file so that respective finder method will be create in  XXXUtil class.
 
 
<entity name= "Student" local-service= "true" remote-service= "true">
              <!-- PK fields -->
              <column name= "studentId" type= "long" primary= "true" />
              <column name= "firstName" type= "String" />
              <column name= "lastName" type= "String" />
              <column name= "studentAge" type= "int" />
               <column name="studentGender" type="int" />
              <column name= "studentAddress" type= "String" />
              <!-- Finder methods -->
               < finder  name="Gender" return-type="Collection">
                      < finder-column  name="studentGender"/>
               </ finder >
</entity>
 
 
Note:
 
When we declared Collection return type is a java.uti.List<ObjectType>
 
Method Syntax in Java Class
 
 
public returnType  findByXXX (finderColumns){
 
}
 
XXX is the name we specified in finder tag as  name attribute.
 
 
  Example:
 
 
public List  findBy Gender(int stdentGender){
 
}
 
 
When we use finder tag we need to specify the finder columns inside the finder tag.
We need specify the finder method return type i.e. Collection or Object type
 
If the methods want return more than one value or records then need to specify as Collection
If the method returns only one object or one record then we can specify as Object i.e. respective object we specified as entity.
 
Example:
 
By Gender we can get more records or values so its return type should be Collection
 
 
<finder name= "byGender" return-type= "Collection">
<finder-column name= "studentGender"/>
</finder>
 
 
For above Configuration respective SQL query as follows
 
 
Select * from  LS_Student Where  studentgender=?
 
 
For Above Finder Configuration respective Java Method in XXXUtil(StudentUtil) as follows
 
 
public  class StudentUtil {
 
public  static java.util.List<com.meera.dbservice.model.Student> 
findBybyGender(
int  studentGender)
throws  com.liferay.portal.kernel.exception.SystemException {
return  getPersistence().findBybyGender(studentGender);
}
}
 
If the finder returns only one value or single object, Assume by first name we have only one record is expected.
 
 
<finder name= "fistName" return-type= "Student">
<finder-column name= "firstName"/>
</finder>
 
 
For above Configuration respective SQL query as follows
 
 
Select * from  LS_Student Where  firstName=?
 
 
Note:
 
In the above configuration we can expect only one value that is respective entity model object that is why return type we specified as Object i.e. Student
 
Finder on Multiple Columns
 
If we want find the records based on multiple columns
 
 
<finder name= "Gender_Age" return-type= "Collection">
<finder-column name= "studentGender"/>
<finder-column name= "studentAge"/>
</finder>
 
 
For above Configuration respective SQL query as follows
 
 
Select * from  LS_Student Where  studentGender=? AND StudentAge=?
 
 
For Above Finder Configuration respective Java Method in XXXUtil(StudentUtil) as follows
 
 
public  class StudentUtil{
 
public  static java.util.List<com.meera.dbservice.model.Student>
findByGender_Age( int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return  getPersistence().findByGender_Age(studentGender,
studentAge);
}
}
 
Note:
 
When we use finder on multiple columns it will apply the AND operator in SQL query.
 
When we call  XXXUtil methods in JSP or Portlet action class then we will get Exception
 
Example:
 
 
java.util.List<com.meera.dbservice.model.Student>  studentsList=
StudentUtil.  findByGender_Age(1,20)
 
 
When we use above code in anywhere then we will get Hibernate Exception
 
 
org.hibernate.HibernateException: No Hibernate Session bound to thread
 
 
Solution:
 
We need to use these methods in XXXLocalServiceImpl then we will call these methods using XXXLocalServiceUtil
 
Note:
 
We can call any method which is in XXXLocalServiceUtil class in JSP, Portlet Action class or other places.
 
Custom Method Implementation:
 
When we thing about above scenarios we are not able to call finder methods and some the methods in XXXServiceUtil methods. This is where we need to implement custom methods.
 
Steps:
 
  1. Implement Custom method in XXXLocalServiceImpl class
  2. Run service Builder
  3. Call Implemented method using XXXLocalServiceUtil

 

Implement Custom method in XXXLocalServiceImpl class
 
Whenever we get the requirement to write our custom methods then we need to implement in respective entity local service implementation class
 
 
XXXLocalServiceImpl
 
StudentLocalServiceImpl
 
 
Assume scenario we are not able to call finder methods form  StudentUtil so we will implement custom method in  StudentLocalServiceImpl.java
 
 
public   java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge( int studentGender,  int studentAge)
 
throws com.liferay.portal.kernel.exception.SystemException {
 
return  StudentUtil.findByGender_Age(studentGender, studentAge);
 
}
 
 
Here we have implemented our custom method in XXXLocalServiceImpl 
(StudentLocalServiceImpl.java) and inside the custom method we have used XXXUtil methods.
Like this we can use XXXServiceUtil and XXXUtil methods in XXXLolcalServiceImpl custom method implementation.
 
Note:
 
XXXLocalServiceImpl class available in  basepackage.service.impl path
 
Run service Builder
 
Once we implement the custom method in XXXServiceImpl then we need to run service builder using ant build-service target from ant view in eclipse.
 
After run service builder respective method signature will be created in XXXLocalServiceUtil class.
 
Note:
 
For every change in XXXLocalServiceImpl class we need to re run the service builder.
 
Call Implemented method using XXXLocalServiceUtil
 
Now the method is available in XXXLocalSeriviceUtil class so that we can call method anywhere.
 
Example:
 
Method in StudentUtil.java
 
 
public  class StudentUtil{
 
public  static java.util.List<com.meera.dbservice.model.Student>
 findByGender_Age(
int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return  getPersistence().findByGender_Age(studentGender,
 studentAge);
}
}
 
 
Note:
 
We can’t call above method directly
 
Implement the Custom method in StudentLocalServiceImpl.java
 
 
public  class StudentLocalServiceImpl  extends
StudentLocalServiceBaseImpl {
public  java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge(
int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return StudentUtil. findByGender_Age(studentGender, studentAge);
}
}
 
 
Respective method Signature in StudentLocalServieUtil.java
 
 
public  static java.util.List<com.meera.dbservice.model.Student>
findByGenderAndAge(
int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return getService().findByGenderAndAge(studentGender, studentAge);
}
 
 
Note:
 
Method signature available after run the service builder
 
Using custom method in JSP page or Portlet Action Class
 
 
java.util.List<Student>  studentsList=
StudentLocalServiceUtil.  findByGenderAndAge(1,20)
 
 
 
Important Points
 
  • Whenever we need to implement custom method then we will use XXXLocalServiceimpl class
  • We can’t call XXXUtil and XXXServiceUtil methods directly so we need to use XXXLocalServiceImpl class to implement custom methods.
  • All finder methods will be created in XXXUtil
  • When we call XXXServiceUtil methods as Guest then we will get Principle Exception.
  • When we call XXXUtil methods directly then we will get Hibernate Exception says No Hibernate Session bound to thread
  • For every custom method implementation in XXXLocalServiceImpl then the respective method signature will be created in XXXLocalServiceUtil and this is happened after run the service builder.
  • We always use XXXLocalServiceUtil to interact with database and some time we will use XXXServiceUtil too.

 

Note:
 
We can use Dynamic Query API to meet all finder requirements. We can do same as finder methods in Liferay Dynamic Query API.
 
Complete code for Example
 
Cutome Method Implemetation(StudentLocalServiceImpl.java)
 
 
public  class StudentLocalServiceImpl  extends
StudentLocalServiceBaseImpl {
public  java.util.List<com.meera.dbservice.model.Student>
findByGenderAndAge(
int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return StudentUtil. findByGender_Age(studentGender, studentAge);
}
}
 
 
Cstome method Signature in
 
 
public  class StudentLocalServiceUtil {
public  static java.util.List<com.meera.dbservice.model.Student>
 findByGenderAndAge(
int studentGender,  int studentAge)
throws com.liferay.portal.kernel.exception.SystemException {
return  getService().findByGenderAndAge(studentGender,
 studentAge);
}
}
 
 
Calling method in JSP page(/html/jsps/get_students_by_gender_age.jsp)
 
 
<%@page import= "com.liferay.portal.kernel.util.ListUtil"%>
<%@page import= "com.meera.dbservice.model.Student"%>
<%@page import= "java.util.List"%>
<%@page import= "com.meera.dbservice.service.StudentLocalServiceUtil"%>
 
<%@ include file= "init.jsp"%>
<a href= "<portlet:renderURL /> ">&laquo;Home</a>
<div class= "separator"></div>
<liferay-portlet:renderURL varImpl= "getStudentsByAgeAndGender">
<portlet:param name= "mvcPath"
value= "/html/jsps/get_students_by_gender_age.jsp" />
</liferay-portlet:renderURL>
<liferay-portlet:renderURL varImpl= "iteratorURL">
<portlet:param name= "studentAge"
value= "<%= String.valueOf(studentAge) %> " />
<portlet:param name= "studentGender"
value= "<%= String.valueOf(studentGender) %> " />
<portlet:param name= "mvcPath"
value= "/html/jsps/get_students_by_gender_age.jsp" />
</liferay-portlet:renderURL>
<h2>Search Students</h2><br/>
<form action= "<%=getStudentsByAgeAndGender%> "
name= "studentForm"  method= "POST">
<b>Age</b><br/>
<input type= "text" name= "<portlet:namespace/> studentAge" id= "<portlet:namespace/> studentAge"
value= "<%=String.valueOf(studentAge)%> "/><br/>
<b>Gender</b><br/>
<input type= "radio" name= "<portlet:namespace/> studentGender" value= "1"<%=studentGender==1?"checked":""%>>Male<br>
<input type= "radio" name= "<portlet:namespace/> studentGender" value= "0"<%=studentGender==0?"checked":""%>>Female<br/>
<input type= "submit" name= "addStudent" id= "addStudent" value= "Search"/>
</form>
<liferay-ui:search-container
displayTerms= "<%=  new DisplayTerms(renderRequest) %> "
emptyResultsMessage= "there-are-no-students"
headerNames= "firstName,studentAge,studentGender"
iteratorURL= "<%= iteratorURL %> "
delta= "5"
<liferay-ui:search-container-results>
<%
 
List<Student> studentList=
StudentLocalServiceUtil.findByGenderAndAge(studentGender, studentAge);
 
searchContainer.setTotal(studentList.size());
studentList = ListUtil.subList(studentList,searchContainer.getStart(),
searchContainer.getEnd());
searchContainer.setResults(studentList);
%>
</liferay-ui:search-container-results>
<liferay-ui:search-container-row
className= "Student"
keyProperty= "studentId"
modelVar= "currentStudent">
<liferay-portlet:renderURL varImpl= "rowURL">
<portlet:param name= "backURL" value= "<%= currentURL %> " />
<portlet:param name= "mvcPath" value= "/html/jsps/display_student.jsp" />
<portlet:param name= "studentId" value= "<%=String.valueOf(currentStudent.getStudentId()) %> " />
</liferay-portlet:renderURL>
<liferay-ui:search-container-column-text
href= "<%= rowURL %> "
name= "firstName"
property= "firstName"
/>
<liferay-ui:search-container-column-text
href= "<%= rowURL %> "
name= "studentAge"
property= "studentAge"
/>
<liferay-ui:search-container-column-text
href= "<%= rowURL %> "
name= "studentGender"
value= '<%=currentStudent.getStudentGender()==1?"Male":"Female"%> '
/>
</liferay-ui:search-container-row>
<liferay-ui:search-iterator searchContainer= "<%=searchContainer %> " />
</liferay-ui:search-container>
 
 
Download Liferay Custom Service Methods Portlet
 
 
Environment:
 
Liferay IDE 2.x+Eclipse (Kepler) +Liferay Plugins SDK 6.2+Tomcat 7.x Liferay Portal Bundle
 
Deployment and its Working.
 
Download portlet you can source or war file to deploy into liferay portal as your convenient.
 
Once portlet successfully deployed drag the portlet in any desired page. Portlet is available in sample category.
 
In the portlet page you can click on  Get Student By Gender And Age link then you can see the search container with search inputs.
 
Portlet Screens:
 
Default Page
 
 
Search the students by Age and Gender
 
 
 
Reference Links
 
 
 
Author
Blogs
Good example to know the Liferay service builder.
IMHO the only revision i have for your code is the gender field data type.
Boolean will be enough.