I am trying to integrate Hibernate Envers in an already developed application.
I ship the Hibernate Envers JAR inside an EAR package, and it throws an ugly exception regarding to class loader and some kind of conflict.
If I avoid shipping the Envers JAR inside the EAR and I place it in the "lib" directory of JBoss, then everything works fine, but I need to ship the library along with the application, since I have no access to this global "lib" directory.
I am deploying on JBoss 5.1.0.GA, using Hibernate 3.3.GA and Envers 1.2.2.GA.
Any clue?
The exception is this one:
15:31:21,621 WARN [arjLoggerI18N] [com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator_2] TwoPhaseCoordinator.beforeC
ompletion - failed for com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple#84697f
java.lang.LinkageError: loader constraint violation: when resolving interface method "org.hibernate.Transaction.register
Synchronization(Ljavax/transaction/Synchronization;)V" the class loader (instance of org/jboss/classloader/spi/base/Base
ClassLoader) of the current class, org/hibernate/envers/synchronization/AuditSyncManager, and the class loader (instance
of org/jboss/classloader/spi/base/BaseClassLoader) for resolved class, org/hibernate/Transaction, have different Class
objects for the type javax/transaction/Synchronization used in the signature
at org.hibernate.envers.synchronization.AuditSyncManager.get(AuditSyncManager.java:56)
at org.hibernate.envers.event.AuditEventListener.onPostUpdate(AuditEventListener.java:163)
at org.hibernate.action.EntityUpdateAction.postUpdate(EntityUpdateAction.java:200)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:179)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:32
1)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
at org.hibernate.ejb.AbstractEntityManagerImpl$1.beforeCompletion(AbstractEntityManagerImpl.java:504)
at com.arjuna.ats.internal.jta.resources.arjunacore.SynchronizationImple.beforeCompletion(SynchronizationImple.j
ava:101)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.beforeCompletion(TwoPhaseCoordinator.java:269)
at com.arjuna.ats.arjuna.coordinator.TwoPhaseCoordinator.end(TwoPhaseCoordinator.java:89)
at com.arjuna.ats.arjuna.AtomicAction.commit(AtomicAction.java:177)
at com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionImple.commitAndDisassociate(TransactionImple.ja
va:1423)
at com.arjuna.ats.internal.jta.transaction.arjunacore.BaseTransaction.commit(BaseTransaction.java:137)
at com.arjuna.ats.jbossatx.BaseTransactionManagerDelegate.commit(BaseTransactionManagerDelegate.java:75)
at org.jboss.aspects.tx.TxPolicy.endTransaction(TxPolicy.java:170)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:87)
at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:190)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:102)
This looks like the classic Java inheritance issue when dealing with multiple classloaders. Have you tried adding jboss-classloading.xml to your EAR META-INF/lib directory?
<classloading xmlns="urn:jboss:classloading:1.0"
parent-first="false"
domain="DefaultDomain"
top-level-classloader="true"
parent-domain="Ignored"
export-all="NON_EMPTY"
import-all="true">
</classloading>
You'll probably have to start packaging Hibernate as well as any other 3rd party libraries that you rely on being provided by the application server.
This also appears to be a good resource http://phytodata.wordpress.com/2010/10/21/demystifying-the-jboss5-jboss-classloading-xml-file/
Related
What is the best way to find all classes with a specific annotation in a JavaEE deployment? I work with a WildFly ApplicationServer and have created my own annotation. At the start of my deployment I would like to find all classes with my annotation and cache them for later access. What do I have to do to protect resources?
First of all Wildfly has modular class loading structure. In Wildfly doc:
Since JBoss AS 7, Class loading is considerably different to previous versions of JBoss AS. Class loading is based on the JBoss Modules project. Instead of the more familiar hierarchical class loading environment, WildFly's class loading is based on modules that have to define explicit dependencies on other modules. Deployments in WildFly are also modules, and do not have access to classes that are defined in jars in the application server unless an explicit dependency on those classes is defined.
As described above, if you have more .ear or .war package, they cannot see classes within each other unless explicit dependency defined. Each module can see its own class therefore each module should load and cache its own classes. You can not load all classes with a single class and single method.
With the following code you can see all loaded classes in the module.
Field f = ClassLoader.class.getDeclaredField("classes");
f.setAccessible(true);
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Vector<Class> classes = (Vector<Class>) f.get(classLoader);
Websphere 8.0.0.11
Hibernate 4.2.21.Final
I have found many questions about this same problem but none of them worked for me.
If I deploy the application in Websphere it works OK.
However we have defined a shared library that contains all the third party libraries (spring, hibernate, javassist, etc) so that our WARs are thinner.
This way during deployment we associate our thin WAR against that Websphere shared library.
The point is that when we deploy the application this way the ClassCastException Hibernate exception _$$_javassist_856 cannot be cast to javassist.util.proxy.Proxy is thrown.
I have checked the loaded jars in the websphere console and can only see one javassist jar (3.18.1-GA) in the classpath.
Why could this be happening?
UPDATE
I have also tried using PARENT_FIRST and PARENT_LAST class loading.
UPDATE 2
I just found out that Websphere is loading its own javassist jar:
URL location = ProxyFactory.class.getProtectionDomain().getCodeSource().getLocation();
logger.info("{}", location);
It prints: file:/opt/IBM/WebSphere/AppServer/plugins/javassist.jar
After trying pretty much everything I found on S.O. without any success I decided to downgrade Hibernate to version 4.1.12.Final. This is the maximum 4.x version compatible with Websphere 8.x.
The problem is that Javassist leaves traces in its generated code. With Javassist on the class path twice, its classes are loaded twice. Two types are however only equal if they have the same name and are loaded by the same class loader. In your case, the generated class resolves its Javassist dependeny to a type that is loaded by your application class loader while your code is casting the instance to the Javassist type that is loaded by the Websphere class loader (or the other way around).
Are you sharing any Hibernate dependencies between applications? Try to not use any shared libraries related to Hibernate in your application to avoid this.
When starting my managed server I see the following ClassCastException related to log4j in my WebLogic 12c managed server out file. I have commons-logging-1.1.1.jar and log4j-1.2.17.jar bundled in my WAR's lib directory and no other version of those libraries there. I also pasted the managed server log file error generated in in processing a request. Should I be using the log4j and commons logging that comes with WebLogic 12c? I see these in the modules directory: com.bea.core.apache.commons.logging_1.1.2.jar and com.bea.core.apache.log4j_1.2.0.0_1-2-15.jar. I haven't had a problem with log4j and WebLogic before.
out file:
jadomain.lang.ClassCastException: org.apache.log4j.RollingFileAppender cannot be cast to org.apache.log4j.Appender
at org.apache.log4j.xml.DOMConfigurator.parseAppender(DOMConfigurator.jadomain:248)
at org.apache.log4j.xml.DOMConfigurator.findAppenderByName(DOMConfigurator.jadomain:176)
at org.apache.log4j.xml.DOMConfigurator.findAppenderByReference(DOMConfigurator.jadomain:191)
at org.apache.log4j.xml.DOMConfigurator.parseChildrenOfLoggerElement(DOMConfigurator.jadomain:523)
at org.apache.log4j.xml.DOMConfigurator.parseCategory(DOMConfigurator.jadomain:436)
at org.apache.log4j.xml.DOMConfigurator.parse(DOMConfigurator.jadomain:1004)
at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.jadomain:872)
at org.apache.log4j.xml.DOMConfigurator.doConfigure(DOMConfigurator.jadomain:778)
at org.apache.log4j.xml.DOMConfigurator.configure(DOMConfigurator.jadomain:906)
at com.domain.d.app.restwrapper.ContextListener.contextInitialized(ContextListener.jadomain:37)
at weblogic.servlet.internal.EventsManager$FireContextListenerAction.run(EventsManager.jadomain:66
log file:
]] Root cause of ServletException.
jadomain.lang.LinkageError: loader constraint violation: when resolving method "org.apache.log4j.LogMF.entering(Lorg/apache/log4j/Logger;Ljadomain/lang/String;Ljadomain/lang/String;)V" the class loader (instance of weblogic/utils/classloaders/ChangeAwareClassLoader) of the current class, com/domain/d/app/restwrapper/appResource, and the class loader (instance of weblogic/utils/classloaders/GenericClassLoader) for resolved class, org/apache/log4j/LogMF, have different Class objects for the type /lang/String;)V used in the signature
at com.domain.d.app.restwrapper.appResource.addQuery(appResource.jadomain:244)
at com.domain.d.app.restwrapper.appResource.addQuery(appResource.jadomain:224)
at com.domain.d.app.restwrapper.appResource$Proxy$_$$_WeldClientProxy.addQuery(appResource$Proxy$_$$_WeldClientProxy.jadomain)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.jadomain:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.jadomain:43)
You have a conflict between tow versions of log4j. One is loaded from the server's classpath and the other one from your web application's classpath.
To resolve it you can setup your web application to use only the one from your application. Update your weblogic.xml file and add the following tag :
<prefer-web-inf-classes>true</prefer-web-inf-classes>
I'm having a problem in an EAR package which contains a server deployed persistence unit in an EJB mdule, and a web app in a WAR module
EAR
|--- persistence unit (EJB module)
|--- web app (WAR)
...
Everything compiles and the deploy (under WildFly 10 CR5) is performed successfully. The persistnce unit is correctly deployed and the schema is created (using Hibernate schema generation during development).
Though, when I try to persist one of the entities like that
MyEntitiy e = new MyEntitiy();
e.setId(UUID.randomUUID().toString());
e.setName("name");
entityService.save(e);
I get a runtime error which root cause is:
Caused by: java.lang.IllegalArgumentException: Can not set java.lang.String field x.y.z.MyEntity.id to x.y.z.MyEntity
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:167)
at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:171)
at sun.reflect.UnsafeFieldAccessorImpl.ensureObj(UnsafeFieldAccessorImpl.java:58)
at sun.reflect.UnsafeObjectFieldAccessorImpl.get(UnsafeObjectFieldAccessorImpl.java:36)
at java.lang.reflect.Field.get(Field.java:393)
at org.hibernate.property.access.spi.GetterFieldImpl.get(GetterFieldImpl.java:39)
Diving into the debugger, I tracked down to the method sun.reflect.UnsafeFieldAccessorImpl.ensureObj which perform a check via the method Class.isAssignableFrom between the classes
the class of the Field object (Field.getDeclaredClass())
the class of the entity to be persisted
This check returns false, due to the fact that the to classes have been loaded with different ClassLoaders (they are logically the same class).
How can I overcome this issue without changing the general layuot of the project (ie, keep the persistence unit as an EJB module to be shared across various modules)?
I believe, you might have included MyEntity class(or entities) in both ejb jar and war file and so they are getting loaded by both the class loaders. You may need to remove domain entities from war file and test it.
As per jboss docs, classes defined in ejb jar are available for classes in war file by default. And so they will loaded only once by ejb classloader only and will be used/available for classes in the war file as well.
I recently start a spring web project with HBase. The problem is,spring seems unable to resolve types under WEB-INF/libs. it complains about "unresolved org.apache.hadoop.conf.Configuration" which is indirectly referenced from required .class file, which is actually in a .jar under the WEB-INF/lib library. Is there anything to be set for spring container to find it?
You need to make sure that Spring itself was loaded by the same class loader: the WAR class loader. This class loader should include all JARs in WEB-INF/lib and all .class files in WEB-INF/classes.
There's a way to pass a class loader into Spring to use a different class loader than the one that loaded it (or the Thread's context class loader), but that gets more complicated.
OK I got the problem. It seems that my project depended on hadoop-core-1.0.2 whilst hbase depend on hadoop-core-1.0.0 and that confused Spring. I fixed the dependency and problem solved.