Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Class loading problem on new() in JPQL
Class loading problem on new() in JPQL [message #525403] Tue, 06 April 2010 09:54 Go to next message
Luca  is currently offline Luca
Messages: 8
Registered: April 2010
Junior Member
Hi all,
I'm using EclipseLink 2.0.1 to provide persistense service for an application whose backend is implemented in OSGi. I've two bundles: org.spagic3.rv.piave.jpa.model and org.spagic3.rv.common.executor.

org.spagic3.rv.piave.jpa.model contains the persistence model obtained with reverse enginneering of database schema. Objects in it are org.spagic3.rv.piave.jpa.model.Person and org.spagic3.rv.piave.jpa.model.Address by now.

org.spagic3.rv.common.executor contains command classes that can be executed. Four basic commands are provided at the moment:

SelectCommand
InsertCommand
UpdateCommand
DeleteCommand

A command executor class configured with persistence unit name executes these commands against the objects in org.spagic3.rv.piave.jpa.model.

Commands are serialized with XStream and unmarshalled in command executor. CommandExecutor code is:

EntityManager em = null;
try {
String inXml = (String) in.getBody();

XStream xStream = new XStream(new Dom4JDriver());
xStream.registerConverter(new IndirectListConverter(xStream.getMapper()));
xStream.alias("list", IndirectList.class);
xStream.setClassLoader(Command.class.getClassLoader());

EntityManagerFactory factory = Persistence
.createEntityManagerFactory(persistenceUnitName);
em = factory.createEntityManager();
command.setEntityManager(em);

boolean rc = command.execute();

String outXml = xStream.toXML(command.getResult());
out.setBody(outXml);

return rc;
} catch (Throwable e) {
logger.error(e.getMessage(), e);
e.fillInStackTrace();
throw new Exception(e);
} finally {
if (em != null) {
em.close();
}
}

I need to set XStream class loader to have it to find my command classes. Command is the common interface for all command classes.

On first execution of a select command everything worked fine. I sent this request:

<org.spagic3.rv.common.command.SelectCommand>
<query>select p from Person p left join fetch p.addresses where p.id = '26'</query>
</org.spagic3.rv.common.command.SelectCommand>

and the answer contained the requested Person data

<?xml version="1.0" encoding="UTF-8"?>
<vector>
<org.spagic3.rv.piave.jpa.model.Person>
<id>26</id>
<birthday>2010-03-31 19:23:34.0 CEST</birthday>
<name>Agapito</name>
<surname>Malteni</surname>
<addresses>
<org.spagic3.rv.piave.jpa.model.Address>
<id>5</id>
...
</org.spagic3.rv.piave.jpa.model.Address>
<org.spagic3.rv.piave.jpa.model.Address>
<id>6</id>
...
</org.spagic3.rv.piave.jpa.model.Address>
</addresses>
</org.spagic3.rv.piave.jpa.model.Person>
</vector>

on the second execution i sent a command to have only a few data about Person

<org.spagic3.rv.common.command.SelectCommand>
<query>select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'</query>
</org.spagic3.rv.common.command.SelectCommand>

query uses a constructor to create a Person object initialize with the few attributes required. Obviously Person provides a suitable constructor. Nonetheless invocation fails with an exception

java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'], line 1, column 7: constructor class [org.spagic3.rv.piave.jpa.model.Person] not found.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.creat eQuery(EntityManagerImpl.java:1328) [na:na]
...
Caused by: org.eclipse.persistence.exceptions.JPQLException:
Exception Description: Error compiling the query [select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'], line 1, column 7: constructor class [org.spagic3.rv.piave.jpa.model.Person] not found.
at org.eclipse.persistence.exceptions.JPQLException.constructor ClassNotFound(JPQLException.java:240) [na:na]

it seems Person class cannot be loaded. I found a workaround for this problem. Setting context classloader to the classloader that loads Command inteface this way,

Thread.currentThread().setContextClassLoader(
Command.class.getClassLoader());

before using EntityManager in command executor, seems to work.

But the question is: is there any other way to do this? Or in other words: everything works with EclipseLink class loading until i don't create a class in JPQL. If there is a new in JPQL i need this suplementary setting. It sonuds strange to me, like i'm missing something in EclipseLink configuration.

Thanks in advance for any reply,
Luca





Re: Class loading problem on new() in JPQL [message #525429 is a reply to message #525403] Tue, 06 April 2010 10:41 Go to previous messageGo to next message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

The JPQL parsing code seems to be using the correct class loader from the Session. What is the class loader in the Session?

Could you include the full exception stack trace?

It is very odd that using the Command class loader fixes the issue, isn't the class in the model jar not the command jar?


James : Wiki : Book : Blog : Twitter
Re: Class loading problem on new() in JPQL [message #525494 is a reply to message #525429] Tue, 06 April 2010 13:14 Go to previous messageGo to next message
Luca  is currently offline Luca
Messages: 8
Registered: April 2010
Junior Member
Hi James,
how can i find which is the Session classloader? Or better, what am i to look at to answer your question?
Tracing execution i found the class loader used without setting it explicitely have cached some http classes used in another component that collects requests for command executer. This http connector is a Jetty based server and it sets the context class loader to it's own, AFAIK.

Here is the full stack trace:

18:50:17.750 [EventAdmin Async Event Dispatcher Thread] ERROR o.s.r.c.executor.ExecutorComponent - An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'], line 1, column 7: constructor class [org.spagic3.rv.piave.jpa.model.Person] not found.
java.lang.IllegalArgumentException: An exception occurred while creating a query in EntityManager:
Exception Description: Error compiling the query [select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'], line 1, column 7: constructor class [org.spagic3.rv.piave.jpa.model.Person] not found.
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.creat eQuery(EntityManagerImpl.java:1328) [na:na]
at org.spagic3.rv.common.command.SelectCommand.doExecute(Select Command.java:11) [na:na]
at org.spagic3.rv.common.command.AbstractReadEntityCommand.exec ute(AbstractReadEntityCommand.java:28) [na:na]
at org.spagic3.rv.common.executor.ExecutorComponent.run(Executo rComponent.java:83) [na:na]
at org.spagic3.core.BaseSpagicService.process(BaseSpagicService .java:76) [org.spagic3.core/:na]
at org.spagic3.core.AbstractSpagicService.handleEvent(AbstractS pagicService.java:138) [org.spagic3.core/:na]
at org.eclipse.equinox.internal.event.EventHandlerWrapper.handl eEvent(EventHandlerWrapper.java:177) [org.eclipse.equinox.event_1.1.100.v20090520-1800.jar:na]
at org.eclipse.equinox.internal.event.EventHandlerTracker.dispa tchEvent(EventHandlerTracker.java:198) [org.eclipse.equinox.event_1.1.100.v20090520-1800.jar:na]
at org.eclipse.osgi.framework.eventmgr.EventManager.dispatchEve nt(EventManager.java:220) [org.eclipse.osgi_3.5.0.v20090520.jar:na]
at org.eclipse.osgi.framework.eventmgr.EventManager$EventThread .run(EventManager.java:330) [org.eclipse.osgi_3.5.0.v20090520.jar:na]
Caused by: org.eclipse.persistence.exceptions.JPQLException:
Exception Description: Error compiling the query [select new org.spagic3.rv.piave.jpa.model.Person(p.id, p.name, p.surname) from Person p where p.id = '26'], line 1, column 7: constructor class [org.spagic3.rv.piave.jpa.model.Person] not found.
at org.eclipse.persistence.exceptions.JPQLException.constructor ClassNotFound(JPQLException.java:240) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.ConstructorNode .getConstructorClass(ConstructorNode.java:131) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.ConstructorNode .applyToQuery(ConstructorNode.java:52) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.SelectNode.appl yToQuery(SelectNode.java:174) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.ParseTree.apply QueryNodeToQuery(ParseTree.java:337) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.p opulateReadQueryInternal(JPQLParseTree.java:113) [na:na]
at org.eclipse.persistence.internal.jpa.parsing.JPQLParseTree.p opulateQuery(JPQLParseTree.java:84) [na:na]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQL DatabaseQuery(EJBQueryImpl.java:202) [na:na]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.buildEJBQL DatabaseQuery(EJBQueryImpl.java:173) [na:na]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:125) [na:na]
at org.eclipse.persistence.internal.jpa.EJBQueryImpl.<init>(EJBQueryImpl.java:109) [na:na]
at org.eclipse.persistence.internal.jpa.EntityManagerImpl.creat eQuery(EntityManagerImpl.java:1326) [na:na]

I think the classloader setting solves the problem becouse the command bundle imports model package containing classes Person and Address.
Re: Class loading problem on new() in JPQL [message #527036 is a reply to message #525494] Tue, 13 April 2010 15:20 Go to previous message
James Sutherland is currently offline James Sutherland
Messages: 1939
Registered: July 2009
Location: Ottawa, Canada
Senior Member

From looking at the code from the stack trace there seems to be a bug in EclipseLink here.

In,
EJBQueryImpl
>>
public static DatabaseQuery buildEJBQLDatabaseQuery(String jpql, Session session) {
return buildEJBQLDatabaseQuery(null, jpql, session, null, null, null);
}

It is not passing the class loader from the session. Please log this bug.


James : Wiki : Book : Blog : Twitter
Previous Topic:Is it possible to return a Collection inside a multiselect (CriteriaBuilder)
Next Topic:efficient cascade delete
Goto Forum:
  


Current Time: Wed Aug 20 06:56:48 EDT 2014

Powered by FUDForum. Page generated in 0.01645 seconds