Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » EclipseLink-7242
EclipseLink-7242 [message #484854] Wed, 09 September 2009 09:53 Go to next message
Mauro is currently offline Mauro
Messages: 79
Registered: July 2009
Member
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 #485927 is a reply to message #484854] Tue, 15 September 2009 10:37 Go to previous messageGo to next message
Doug Clarke is currently offline Doug Clarke
Messages: 155
Registered: July 2009
Senior Member
Mauro,

I have been assisting several groups in doing similar migrations and would
be interested in any all feedback or notes on your efforts so we can
publish them on the wiki to assist the entire community.

On this specific issue I am not sure I understand the functionality you
are seeing in OpenJPA. During detachment (through serialization) if a null
reference or empty collection is returned I am unsure how the application
would differentiate this state from the scenario where the entity actually
had a null or empty collection. We have always sided with throwing an
exception versus returning an entity in a state which may be incorrect.

Can you provide more insight as to how your application differentiates a
null value or empty collection caused by serialization versus one that is
actually null or empty?

Doug
Re: EclipseLink-7242 [message #486257 is a reply to message #485927] Wed, 16 September 2009 18:14 Go to previous messageGo to next message
Mauro is currently offline Mauro
Messages: 79
Registered: July 2009
Member
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 #486259 is a reply to message #486257] Wed, 16 September 2009 18:35 Go to previous messageGo to next message
Mauro is currently offline Mauro
Messages: 79
Registered: July 2009
Member
If a call a business method, I must know previously what it returns, I
must know
if it was implemented to bring a relationship or not. That would be
enough.

But for openjpa null collection means that the It was not initialized and
empty collection means that there is no elements indeed.

Mauro.
Re: EclipseLink-7242 [message #487951 is a reply to message #486259] Thu, 24 September 2009 22:43 Go to previous messageGo to next message
Doug Clarke is currently offline Doug Clarke
Messages: 155
Registered: July 2009
Senior Member
Mauro,

Sorry for the delay getting back to this thread. Thanks for taking the time to put all this together.

One difference obvious from this is that before serialization a call to a.getListB() in EclipseLink makes no calls to the database. We simply return the container which has no knowledge yet what is on the database. With the OpenJPA example the same call now knows the number of elements and thus must have made a database call. In the second case do you have the instances of B in the list or just the size?

If a collection's contents are not needed we generally believe that we should avoid any query to the database.

I am still not convinced that a null collection is an intuitive result for a collection that was not instantiated before serialization. I can also see that an exception traversing one of these relationships may not be intuitive to some. Java has no standard mechanism to indicate that a collection's state is unknown.

The short answer is there is no solution that I believe is generally accepted today.

Now, if you need to address the same sort of behaviour you have now we may be able to help.

EclipseLink is very customizable so it is possible to specify the use of different IndirectContainer classes (i.e. a subclass of IndirectList could be specified) which may have different serialization behaviour. If you would like to proceed please file an enhancement request and we can finalize the requirements and provide an example of how to extend the framework.

Cheers,

Doug
Re: EclipseLink-7242 [message #488195 is a reply to message #484854] Fri, 25 September 2009 17:08 Go to previous messageGo to next message
Mauro Flores is currently offline Mauro Flores
Messages: 84
Registered: September 2009
Location: Brasil
Member
Doug,

"In the second case do you have the instances of B in the list or just the
size?"
After a.getListB() I have the complete list. The query had already been run.

Anyway, I accepted your suggestion and I opened an enhancement request:

https://bugs.eclipse.org/bugs/show_bug.cgi?id=290593

I didn't get if I can make this enhanced by myself while you don't get a I final solution or if I wait you working on this request.

Cheers, Mauro.

Re: EclipseLink-7242 [message #488218 is a reply to message #488195] Fri, 25 September 2009 22:53 Go to previous message
Doug Clarke is currently offline Doug Clarke
Messages: 155
Registered: July 2009
Senior Member
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
Previous Topic:not support executeThreadRuntime
Next Topic:release plans
Goto Forum:
  


Current Time: Wed Aug 20 14:47:05 EDT 2014

Powered by FUDForum. Page generated in 0.03036 seconds