EclipseLink-7242 [message #484854] |
Wed, 09 September 2009 09:53  |
Eclipse User |
|
|
|
Hi,
I'd like to change the jpa implementation of all systems of my company
from Openjpa to Eclipselink.
No big deal until start to test lazy loading relationship and get this
exception:
Exception [EclipseLink-7242] (Eclipse Persistence Services -
1.1.2.v20090612-r4475):
org.eclipse.persistence.exceptions.ValidationException
Exception Description: An attempt was made to traverse a relationship
using indirection that had a null Session. This often occurs when an
entity with an uninstantiated LAZY relationship is serialized and that
lazy relationship is traversed after serialization. To avoid this issue,
instantiate the LAZY relationship prior to serialization.
This exception happens whenever I call an EJB that returns an entity with
a lazy relationship from outside the EJB container (webservice or web).
Sometimes I don't want to 'instantiate the LAZY relationship prior to
serialization.', because I don't want to work with the relationships.
Openjpa returns a empty Collection in those cases. Eclipselink returns a
Linked List that returns this exception when I try to use it.
Is there a way to configure Eclipselink to have the same behavior of
OpenJpa.
Thanks. Mauro.
|
|
|
|
Re: EclipseLink-7242 [message #486257 is a reply to message #485927] |
Wed, 16 September 2009 18:14   |
Eclipse User |
|
|
|
Doug,
I really appreciate your reply.
"I am unsure how the application would differentiate this state"
That's the backstage of openjpa. My application don't worry about it.
I made I simple example that can show the difference of behavior. It shows
the change of values in 3 scenarios traced before and after the
serialization (web context)
1)after the find and before the execution of method get of relationship
2)after the get and before the method size
3)after the size
In openjpa, if a relationship was no initialized (scenario 1) , its
serialized with null. As soon as a method getRelationship is executed its
filled with a subclass of ArrayList with 0 or more elements(scenario 2 e
3). So a null collection means that relationship was not initialized and
an empty collection means that the relationship doesn't exist.
In eclipselink, in all scenarios the relationship has an InternalList. In
scenario 1 and 2 the internal list has the property isInstantiated set to
false and throws an exception when serialized In scenario 3, the
property isInstantiated is set to true and relationship is serialized.
Eclipselink wouldn't have an configured option sinalizing to serialize
relationship as null when the property isInstatiated is set to false????
Wouldn't it be a good approach?
I'm working on a proxy (Ejb interceptor) that makes exactly this. Each
collection of a returned entity that has an InternalList not instantiated
is set to null before the serialization. I'm not sure if that's the best
approach.
Example
=======
---------------------------------------------------
EJB Class:
---------------------------------------------------
@Stateless(mappedName = "ARN")
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class ARNImpl implements ARN {
protected final Log logger = LogFactory.getLog(getClass());
@Resource
SessionContext context;
@PersistenceContext(unitName="TESTE")
EntityManager em;
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public A consultWithoutGet(int code) {
System.out.println("Code" + code);
A a = em.find(A.class, code);
return a;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public A consultWithoutSize(int code) {
System.out.println("Code" + code);
A a = em.find(A.class, code);
List<B> listaB = a.getListB();
if (listaB == null) {
System.out.println("SessionBean Before size() - null relationship");
return a;
}
System.out.println("SessionBean Before size() - Class relationship: "
+ listaB.getClass().getName());
System.out.println("SessionBean Before size() - Super Class
relationship: " + listaB.getClass().getSuperclass().getName());
if (listaB instanceof IndirectList) {
System.out.println("SessionBean Before size() - Eclipselink
Instantiated: " + ((IndirectList)listaB).isInstantiated());
}
return a;
}
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public A consultWithSize(int code) {
System.out.println("Code" + code);
A a = em.find(A.class, code);
int size = a.getListB().size();
List<B> listaB = a.getListB();
if (listaB == null) {
System.out.println("SessionBean After size() - null relationship");
return null;
}
listaB = a.getListB();
System.out.println("SessionBean size - : " + size);
System.out.println("SessionBean After size() - Class relationship: "
+ listaB.getClass().getName());
System.out.println("SessionBean After size() - Super Class
relationship: " + listaB.getClass().getSuperclass().getName());
if (listaB instanceof IndirectList) {
System.out.println("After size() - Eclipselink Instantiated: " +
((IndirectList)listaB).isInstantiated());
}
return a;
}
----------------------------------------------
Pojo Method called from JSP that calls the EJB
----------------------------------------------
public void consult() {
ARN arn = (ARN) ServiceLocator.getEJB3(ARN.class);
A a = arn.consultWithoutGet(code);
try {
if (a.getListB() != null) {
System.out.println("Web context - before get() - class " +
a.getListB().getClass().getName());
System.out.println("Web context - before get() - size " +
a.getListB().size());
} else {
System.out.println("Web context - before get() - relationship
null");
}
} catch (Exception e) {
System.out.println("Web context - before size() - exeption: " +
e.getClass());
}
try {
a = arn.consultWithoutSize(code);
if (a.getListB() != null) {
System.out.println("Web context - before size() - class " +
a.getListB().getClass().getName());
System.out.println("Web context - before size() - size " +
a.getListB().size());
} else {
System.out.println("Web context - before size() - relationship
null");
}
} catch (Exception e) {
System.out.println("Web context - before size() - exeption: " +
e.getClass());
}
try {
a = arn.consultWithSize(code);
System.out.println("Web context - after size() - class " +
a.getListB().getClass().getName());
System.out.println("Web context - after size() - size " +
a.getListB().size());
} catch (Exception e) {
System.out.println("Web context - after size() - exeption: " +
e.getClass());
}
}
------------------
Entity A
------------------
@Entity
@Table(name = "A")
public class A implements Serializable{
@OneToMany(fetch = FetchType.LAZY, mappedBy = "a")
private List<B> listB = new ArrayList<B>();
}
========================
Running with eclipselink
========================
Web context - before get() - class
org.eclipse.persistence.indirection.IndirectList
Web context - before get() - exeption: class
org.eclipse.persistence.exceptions.ValidationException
SessionBean Before size() - Class relationship:
org.eclipse.persistence.indirection.IndirectList
SessionBean Before size() - Super Class relationship: java.util.Vector
SessionBean Before size() - Eclipselink Instantiated: false
Web context - before size() - class
org.eclipse.persistence.indirection.IndirectList
Web context - before size() - exeption: class
org.eclipse.persistence.exceptions.ValidationException
SessionBean size - : 2
SessionBean After size() - Class relationship:
org.eclipse.persistence.indirection.IndirectList
SessionBean After size() - Super Class relationship: java.util.Vector
After size() - Eclipselink Instantiated: true
Web context - after size() - class
org.eclipse.persistence.indirection.IndirectList
Web context - after size() - size 2
====================
Running with openjpa
====================
Web context - before get() - relationship null
SessionBean Before size() - Class relationship:
org.apache.openjpa.util.java$util$ArrayList$proxy
SessionBean Before size() - Super Class relationship: java.util.ArrayList
Web context - before size() - class
org.apache.openjpa.util.java$util$ArrayList$proxy
Web context - before size() - size 2
SessionBean size - : 2
SessionBean After size() - Class relationship:
org.apache.openjpa.util.java$util$ArrayList$proxy
SessionBean After size() - Super Class relationship: java.util.ArrayList
Web context - after size() - class
org.apache.openjpa.util.java$util$ArrayList$proxy
Web context - after size() - size 2
|
|
|
|
|
|
Re: EclipseLink-7242 [message #488218 is a reply to message #488195] |
Fri, 25 September 2009 22:53  |
Eclipse User |
|
|
|
I made a small example subclassing IndirectList allowing different behaviour on writeReplace during serilaization. The following test case now passes.
Employee emp = new Queries().minEmployeeWithAddressAndPhones(getEntityManager() );
Assert.assertNotNull(emp.getPhoneNumbers());
// Verify its an IndirectList that is not instantiated
IndirectList phonesList = (IndirectList) emp.getPhoneNumbers();
Assert.assertFalse(phonesList.isInstantiated());
byte[] bytes = SerializationHelper.serialize(emp);
Employee serEmp = (Employee) SerializationHelper.deserialize(bytes);
Assert.assertNull(serEmp.getPhoneNumbers());
I have attached my example so far to your bug. Please note that I have not tested merging the detached instance back in yet. I am unsure what will happen there.
Doug
|
|
|
Powered by
FUDForum. Page generated in 0.05422 seconds