掲示板

Service Builder Many to Many Problem in 6.2

thumbnail
10年前 に meera prince によって更新されました。

Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 1111 参加年月日: 11/02/08 最新の投稿
Hi ALL
I am getting class cast exception when I implement many to many service builder.
I insertion is ok but when access data then I am getting class cast exception.

The following is scenario

Student can obtain many course and same way one course can be taken by many students.
The following are my entities and I am using mapping-table attribute for column

<entity name="Student" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="studentId" type="long" primary="true" />
<!-- Audit fields -->
<column name="studentName" type="String" />
<column name="studentPlace" type="String" />
<column name="studentCollege" type="String" />
<column name="courses" type="Collection" entity="Course" mapping-table="Students_Courses"/>
<!-- Order -->
<order by="asc">
<order-column name="studentId" />
</order>
<!-- Finder methods -->
<finder name="studentPlace" return-type="Collection">
<finder-column name="studentPlace" />
</finder>
</entity>
<entity name="Course" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="courseId" type="long" primary="true" />
<!-- Audit fields -->
<column name="courseName" type="String" />
<column name="courseGroup" type="String" />
<column name="students" type="Collection" entity="Student" mapping-table="Students_Courses" />
<!-- Order -->
<order by="asc">
<order-column name="courseId" />
</order>
<!-- Finder methods -->
<finder name="courseGroup" return-type="Collection">
<finder-column name="courseGroup" />
</finder>
</entity>

Problem When I access data as follows

<%
List<Student> studentslist=StudentLocalServiceUtil.getCourseStudents(1);
for(Student student:studentslist){
out.println(student.getStudentName());
}
%>



getCourseStudents() return type is List<Student > but I am getting exception says that

java.lang.ClassCastException: com.meera.db.model.impl.StudentImpl cannot be cast to com.meera.db.model.Student

I don’t know why it giving class cast exception
The following classes’ available and return type is List<Student >
com.meera.db.model.impl.StudentImpl
com.meera.db.model.Student



Full Stack trace
java.lang.ClassCastException: com.meera.db.model.impl.StudentImpl cannot be cast to com.meera.db.model.Student
at com.meera.db.service.persistence.StudentPersistenceImpl.fetchByPrimaryKey(StudentPersistenceImpl.java:949)
at com.meera.db.service.persistence.StudentPersistenceImpl.findByPrimaryKey(StudentPersistenceImpl.java:911)
at com.meera.db.service.persistence.StudentPersistenceImpl.findByPrimaryKey(StudentPersistenceImpl.java:1)
at com.liferay.portal.service.persistence.impl.TableMapperImpl.getBaseModels(TableMapperImpl.java:400)
at com.liferay.portal.service.persistence.impl.TableMapperImpl.getLeftBaseModels(TableMapperImpl.java:241)
at com.liferay.portal.service.persistence.impl.ReverseTableMapper.getRightBaseModels(ReverseTableMapper.java:96)
at com.meera.db.service.persistence.CoursePersistenceImpl.getStudents(CoursePersistenceImpl.java:1211)
at com.meera.db.service.persistence.CoursePersistenceImpl.getStudents(CoursePersistenceImpl.java:1191)
at com.meera.db.service.persistence.CoursePersistenceImpl.getStudents(CoursePersistenceImpl.java:1172)
at com.liferay.portal.dao.shard.advice.ShardPersistenceAdvice.invoke(ShardPersistenceAdvice.java:54)
at com.meera.db.service.base.StudentLocalServiceBaseImpl.getCourseStudents(StudentLocalServiceBaseImpl.java:363)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:115)
at com.liferay.portal.spring.transaction.DefaultTransactionExecutor.execute(DefaultTransactionExecutor.java:62)
at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:51)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:111)
at com.liferay.portal.spring.aop.ChainableMethodAdvice.invoke(ChainableMethodAdvice.java:56)
thumbnail
10年前 に David H Nebinger によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 14917 参加年月日: 06/09/02 最新の投稿
meera prince:
getCourseStudents() return type is List<Student > but I am getting exception says that

java.lang.ClassCastException: com.meera.db.model.impl.StudentImpl cannot be cast to com.meera.db.model.Student

I don’t know why it giving class cast exception


Class cast exceptions (especially in SB ) are usually not casting issues as much as they are class loader issues. For example, if you have a service jar in the global lib directory (lib/ext in tomcat) and a service jar in the WEB-INF/lib directory, you'll get these errors a lot.
thumbnail
10年前 に meera prince によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 1111 参加年月日: 11/02/08 最新の投稿
David H Nebinger:
meera prince:
getCourseStudents() return type is List<Student > but I am getting exception says that

java.lang.ClassCastException: com.meera.db.model.impl.StudentImpl cannot be cast to com.meera.db.model.Student

I don’t know why it giving class cast exception


Class cast exceptions (especially in SB ) are usually not casting issues as much as they are class loader issues. For example, if you have a service jar in the global lib directory (lib/ext in tomcat) and a service jar in the WEB-INF/lib directory, you'll get these errors a lot.


Hi David
Thank you for your reply. I will check according to you.
In my case I did not share any service jar between two portlet contexts and I am sure service jar not in global lib (ext/lib) and service jar and implementation classes in same class path ..

This exception I observed especially when I am using many to many relation in SB. And I will take new portlet in another attempt and same many to many I have used, again I have seen same exception.

Here I have observed two cases

Case: 1

com.meera.db.model.Student student=new com.meera.db.model.impl.StudentImpl(); // this is working fine
com.meera.db.model.Student student=new com.meera.db.service.SrudenLocalServiceUtil.getStudent(1); // this is also working fine


No class cast exception for above scenario

Case: 2

List<com.meera.db.model.Student> studentList=com.meera.db.service.SrudenLocalServiceUtil.getCourseStudents(courseId)
for(int i=0;i<studentsList.size();i++){
com.meera.db.model.Student student= studentsList.get(i)
}



In the second case I am getting class cast exception. This is place we are using Many to Many relation to pass courseId and we are getting students.

The following is method implementation in StudentLocalServiceUtil

public static java.util.List<com.meera.db.model.Student> getCourseStudents(
long courseId)
throws com.liferay.portal.kernel.exception.SystemException {
return getService().getCourseStudents(courseId);
}



However I will check once again

And one more according to Liferay Service Builder I have seen following

If the entity and mapping-table attributes are specified, then the Service
Builder will assume you are specifying a many to many relationship.

For example:

<column
name="roles"
type="Collection"
entity="Role"
mapping-table="Groups_Roles"
/>

The above column specifies that there will be a getter called
pojo.getRoles() that will return a collection. It will use a mapping table
called Groups_Roles to give a many to many relationship between groups and
roles


But when I observed I did not see any methods as they said in POJO/Model classes
i.e.
student.getCourses() // not available in model class

The only thing is that, required many to may relation methods is generated in XXXLocalServiceUtil,XXXServiceUtil,XXXUtil.

According to service builder 6.2 DTD mapping-key is no longer available

The mapping-key attribute is no longer supported. See LPS-32250 for more
information. The value of the mapping-key is now always assumed to be the column
entity's primary key.


How can I achieve One to Many in SB,

I guess if we use many to many in One Way we can achieve is this correct?

I did following way but SB throwing exception and it’s not generating any classes

<entity name="Student" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="studentId" type="long" primary="true" />
<!-- Audit fields -->
<column name="studentName" type="String" />
<column name="studentPlace" type="String" />
<column name="studentCollege" type="String" />
</entity>
<entity name="Course" local-service="true" remote-service="true">
<!-- PK fields -->
<column name="courseId" type="long" primary="true" />
<!-- Audit fields -->
<column name="courseName" type="String" />
<column name="courseGroup" type="String" />
<column name="students" type="Collection" entity="Student" mapping-table="Students_Courses" />
</entity>

It’s not allowing to define mapping-table attribute for one entity.

It is forcing to declare mapping-table attribute in two tables i.e. the entities participate in relation.

Regards,
Meera Prince
thumbnail
10年前 に meera prince によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 1111 参加年月日: 11/02/08 最新の投稿
Hi All
As i said in First thered of this post i got class cast exception when i am implementing many to many relation in SB.

Insertion is fine but when we do read operation i am getting class cast exception,

In the following example i already done work around to complete example
http://www.liferaysavvy.com/2014/01/liferay-service-builder-many-to-many_3547.html

Here we have two alternatives when we perform read operation

Manual JSON serialization

Custom SQL

Manual JSON serialization

Get Student Courses


List studentCoursesList=CourseLocalServiceUtil.getStudentCourses(studentId);

for(int i=0;i<studentCoursesList.size();i++){

Object curCourse=studentCoursesList.get(i);

JSONObject jobj=JSONFactoryUtil.createJSONObject(curCourse.toString());

System.out.println(jobj.getString("courseName"));

}



Get Course Students


List courseStudentList =StudentLocalServiceUtil.getCourseStudents(courseId);

for(int i=0;i<studentCoursesList.size();i++){

Object curStudent= courseStudentList.get(i);

JSONObject jobj=JSONFactoryUtil.createJSONObject(curStudent.toString());

System.out.println(jobj.getString("studentName"));

}


Custom SQL

Create StudentFinderImpl.java and CourseFinderImpl.java

Create method and decide its return type
Implement required method in XXXFinderImpl
run service builder
Implement Method In XXXLocalServiceImpl
run service builder
Use XXXLocalServiceUtil to access custom method



Get Student Courses

Implement required method in XXXFinderImpl

package com.meera.db.service.persistence;
public class StudentFinderImpl extends BasePersistenceImpl<Student>
implements StudentFinder {
public static String getStudentCourses = "select * from meera_course "+
"INNER JOIN meera_students_courses ON meera_course.courseId=meera_students_courses.courseId"+
"WHERE meera_students_courses.studentId=?";
public List<Course> getStudentCourses(long studentId) throws SystemException {
Session session = null;
try {
session = openSession();
SQLQuery query = session.createSQLQuery(getStudentCourses);
query.addEntity("Course", CourseImpl.class);
QueryPos qPos = QueryPos.getInstance(query);
qPos.add(studentId);
return (List<Course>)query.list();
}catch (Exception e) {
e.printStackTrace();
return null;
}
}

}


run service builder

Implement method in StudentLocalServiceImpl.java

public class StudentLocalServiceImpl extends StudentLocalServiceBaseImpl {
public List<Course> getStudentCourses(long studentId) throws SystemException {
return StudentFinderUtil.getStudentCourses(studentId);
}
}


run service builder

use StudentLocalServiceUtil in jsp page

Display student courses
<%
try{
List<Course> courseList= StudentLocalServiceUtil.getStudentCourses(studentId);
for(Course course:courseList){
out.println(course.getCourseName());
}
}catch(Exception e){
e.printStackTrace();
}
%>


The same thing you can use when we want display students for course .. query will be changes

Regards,
Meera Prince
thumbnail
8年前 に Olaf Kock によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 6403 参加年月日: 08/09/23 最新の投稿
I've just given another explanation attempt on stackoverflow
8年前 に Mohd Shamsul Amerudin によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

New Member 投稿: 1 参加年月日: 15/11/25 最新の投稿
Thanks Olaf Kock, from your explanation on stackoverflow

Let say, I do not want to touch or change code from service builder, So what I do,
To make sure no error in java.lang.ClassCastException when trigger retrieval many to many relationship ,

I clean everything my related portlet in my tomcat. delete my portlet inside webapps folder and also temp folder.
From portlet project, I run ant build services , Then find service jar put into tomcat path ../tomcat/lib/ext/<myservice>.jar
After that, I do not run ant build all, it will automatically put war file into deploy folder.
So I run ant build war, Then I find /liferay-plugins-sdk-6.2/dist/myportlet.war , open the war file, I remove lib /<myservice>.jar inside /WEB-INF/lib.
Next step, I copy myportlet.war paste into deploy folder.
So It should not duplicate <myservice>.jar in tomcat.

But, now every time I change code, when and build war, i have to remove jar. This is not best practice to me.

Is there any command from ant-build that I can exclude service.jar into my portlet project?

my other reference : http://www.opensource-techblog.com/2013/03/call-service-from-one-portlet-to.html
thumbnail
8年前 に David H Nebinger によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

Liferay Legend 投稿: 14917 参加年月日: 06/09/02 最新の投稿
I typically just deploy the war as is and let Liferay handle it.

After deployment I usually do a app container restart (because I like a clean environ) so while the server is stopped I just move from the portlet's WEB-INF/lib dir to tomcat's lib/ext dir.

Much less work, much less copying and no tampering with the war file contents.

No there is no command to exclude the service jar. Honestly Liferay frowns on the global service jar, it's not the best use in all situations.

The only times the service jar should be global are:

1. The portal is going to consume the service through some hook that you've created.
2. There are more than say 4 service consumers.

When there are less than 4, I still think you are best served by shipping the service jar in each of the consumer's WEB-INF/lib folder than going through the pain of making them global. And 4 is an arbitrary number, you could always use a higher value.

Simply put, global service jars are a total pain. You constantly have to get rid of service jars in all of the portlets' WEB-INF/lib folders, you have to update the global jar in tomcat's lib/ext directory, and (depending on your OS) you may not be able to move the jar if the app container is running so a restart is forced on you whether you can handle a restart immediately or not.
7年前 に qiang lei によって更新されました。

RE: Service Builder Many to Many Problem in 6.2

New Member 投稿: 1 参加年月日: 17/03/10 最新の投稿
I found that when there are two or more portlets under the {tmocat.dir}/temp folder ,for example 1-xxxxxxxxxx-portlet and 2-xxxxxxxxx-portlet,this porblem will happen.after i delete them and redeploy the portlet,everything is normal.