ClassLoader problem using JPA with Native Eclipselink project file [message #1003363] |
Mon, 21 January 2013 03:30 |
Roger Spall Messages: 17 Registered: January 2013 |
Junior Member |
|
|
Following various helpful documentation, I am trying to use JPA with a Native Eclipse Project. I setup my persistence.xml to point to my Sessions.xml, and meanwhile my Sessions.xml file references a project java file - generated from the Mapping Workbench.
I am testing my application with WebSphere 8 and there is only one copy of eclipselink.jar file (V2.4.1) in the lib directory of my EAR file / application. The eclipselink.jar is in turn referenced from the Manifest.mf file for my EJB project. Anyway, when I start my Enterprise Application, I get a Class cast exception:
com.yamaha.progress.database.connections.ProgressProject incompatible with org.eclipse.persistence.sessions.Project
Given that my ProgressProject was generated from the Mapping Workbench, and that it directly subclasses org.eclipse.persistence.sessions.Project, the problem must be with class loaders. So... I used the WebSphere debugger and located the problem code inside org.eclipse.persistence.internal.sessions.factories.SessionsFactory:
....
if (projectConfig.isProjectClassConfig()) {
try {
if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){
project = (Project) AccessController.doPrivileged(new PrivilegedNewInstanceFromClass(m_classLoader.loadClass(projectString)));
}else{
project = (Project) PrivilegedAccessHelper.newInstanceFromClass(m_classLoader.loadClass(projectString));
}
} catch (Throwable exception) {
throw SessionLoaderException.failedToLoadProjectClass(projectString, exception);
}
....
During initialization, Eclipselink hits the second project = assignment and throws the exception. Under closer examination, m_classLoader is identified as 'com.ibm.ws.classloader.CompoundClassLoader@9ab7dd4[jpatemp:app:YMUSWebApplications]' and has a different java id to the SessionFactory instance's class loader. This SessionFactory Class Loader (derived from evaluating this.getClass().getClassLoader()) is identified as com.ibm.ws.classloader.CompoundClassLoader@95b78cf[app:YMUSWebApplications]. In both cases the actual class path is identical, but clearly they are different class loaders.
Just to be sure, when I place the eclipselink.jar file in the WebSphere Application Server classpath (not a good idea for a prroduction deployment:-)), the problem goes away, and my mappings work just fine.
I am using the default WebSphere class loading policy(s), namely One class loader per enterprise app and delegation to PARENT_FIRST.
What am I doing wrong? Is there some additional configuration property that I need to set for eclipselink, OR for WebSphere?
|
|
|
Re: ClassLoader problem using JPA with Native Eclipselink project file [message #1063975 is a reply to message #1003363] |
Mon, 17 June 2013 05:42 |
Kishore Kirdat Messages: 1 Registered: June 2013 |
Junior Member |
|
|
I had similar problem and I saw that when sessions.xml is used, the eclipselink sets up a temporary session as shown below:
Code snippet from the org.eclipse.persistence.internal.jpa.EntityManagerSetupImpl
if (isSessionLoadedFromSessionsXML) {
if (this.compositeEmSetupImpl == null && this.staticWeaveInfo == null) {
JPAClassLoaderHolder privateClassLoaderHolder = session.getServerPlatform().getNewTempClassLoader(persistenceUnitInfo);
classLoaderToUse = privateClassLoaderHolder.getClassLoader();
} else {
classLoaderToUse = persistenceUnitInfo.getNewTempClassLoader();
}
// Loading session from sessions-xml.
.
.
// Do not register the session with the SessionManager at this point, create temporary session using a local SessionManager and private class loader.
// This allows for the project to be accessed without loading any of the classes to allow weaving.
// Note that this method assigns sessionName to session.
Session tempSession = new SessionManager().getSession(xmlLoader, tempSessionName, classLoaderToUse, false, false);
// Load path of sessions-xml resource before throwing error so user knows which sessions-xml file was found (may be multiple).
session.log(SessionLog.FINEST, SessionLog.PROPERTIES, "sessions_xml_path_where_session_load_from", xmlLoader.getSessionName(), xmlLoader.getResourcePath());
if (tempSession == null) {
throw ValidationException.noSessionFound(sessionName, sessionsXMLStr);
}
// Currently the session must be either a ServerSession or a SessionBroker, cannot be just a DatabaseSessionImpl.
if (tempSession.isServerSession() || tempSession.isSessionBroker()) {
session = (DatabaseSessionImpl) tempSession;
if (tempSessionName != sessionName) {
// set back the original session name
session.setName(sessionName);
}
} else {
throw EntityManagerSetupException.sessionLoadedFromSessionsXMLMustBeServerSession(persistenceUnitInfo.getPersistenceUnitName(), (String)predeployProperties.get(PersistenceUnitProperties.SESSIONS_XML), tempSession);
}
.
.
}
Although, moving eclipselink.jar to websphere lib (adding it to the server classpath) resolved this specific error, I started getting ClassCastException further down when using listeners.
So I tried subclassing the WebSphere_7_Platform and overriding the getNewTempClassLoader method as follows:
@Override
public JPAClassLoaderHolder getNewTempClassLoader(PersistenceUnitInfo puInfo) {
// Return the main classloader and not the temporary one.
return new JPAClassLoaderHolder(puInfo.getClassLoader(), false);
}
But this also means that the temporary session and weaving process is using the main class loader. And I am not sure if it can cause some problems. I haven't seen any so far.
|
|
|
Powered by
FUDForum. Page generated in 0.03741 seconds