Class loading problem on new() in JPQL [message #525403] |
Tue, 06 April 2010 13:54 |
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 #525494 is a reply to message #525429] |
Tue, 06 April 2010 17:14 |
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 19:20 |
|
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
|
|
|
Powered by
FUDForum. Page generated in 0.01426 seconds