Classloading Issue with server deployed persistence unit - java

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.

Related

How to find all classes with my annotation | Wildfly JavaEE

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);

NoClassDefFoundException in N-tier application

I am building a project for a class that I am taking, and it consists of 4 modules
-impl (business logic/dao access)
-ejb (encapsulates business logic and provides access to it via a remote interface)
-war (web tier)
-ear (contains the war and ejb modules)
One utility class that I have inside the impl is able to populate an H2 database. It does this by running an ingestor that reads in an processes an xml file that resides in a maven repository, using various dao classes/methods to ingest the data:
String fileName = "xml/proj-data.xml";
InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream(fileName);
When I run the ingestor through a unit test, it runs fine, but when I have everything layered, I get the NoClassDefFoundException on xml/proj-data.xml
So the basic outline that I have is:
-the war has dependencies on the impl and ejb modules
-the ejb has dependency on the impl module
-the ear has dependency on the impl, ejb, and war
This is a maven project. When I deploy the EAR to the server, the start page for the war is displayed (as I expect).
-The html page has a button that when pressed, does a post to a servlet
-The servlet has an ejb injected into it that it calls (via its remote interface).
-The ejb method makes a call back to the populate method in the impl, and thats when the exception happens, and I get a webpage back showing the exception.
Do I need to declare that repository in the WAR pom file as well?
In typing the question, I think I know what the problem may be. The repository that the xml file resides in is declared in the root pom for the project(the impl parent), NOT the pom for the impl module. Since the impl is the module that gets packaged with the EAR, I may need to declare the repository in the impl pom file as well.

Hibernate ENVERS Classloading issue

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/

How do I correct a Java LinkageError exception?

I am developing an application for WebSphere 6.1 which uses a Java servlet. Within my servlet, I have defined a serial vesion ID of 1L. Upon deploying and running my application, I am receiving a LinkageError of the following type (from the server log):
[5/9/11 15:14:26:868 EDT] 0000001c WebApp
E [Servlet Error]-[ManageRecordsConsumerServlet]: java.lang.Exception:
java.lang.LinkageError: LinkageError while defining class:
<redacted>.docindexupdate.batch.servlet.ManageRecordsConsumerServlet
Could not be defined due to: (<redacted>/docindexupdate/batch/servlet
/ManageRecordsConsumerServlet) class name must be a string at offset=2074
This is often caused by having a class defined at multiple
locations within the classloader hierarchy. Other potential causes
include compiling against an older or newer version of the class
that has an incompatible method signature.
I'm not sure what the issue is. I was seeing this previously before defining a serial version uid and figured that by defining that and being consistent, future updates to the class file would run successfully. There are no errors during compilation or deployment to the server. Is it possible that an older version of the servlet is cached somewhere on the WebSphere instance (I am only deploying on my dev machine at the moment)?
The
class name must be a string at offset=2074
line is also confusing.
I am suspecting you have a jar that is being loaded in two different classloaders. By that I mean, your websphere server on startup loads that jar or has an endorsed directory with that jar. Also your EAR you are deploying has that jar in its lib. The two can conflict at runtime
What I would suggest is to find out which jar ManageRecordsConsumerServlet belongs to and either remove it from your EAR lib or your Websphere endorsed lib (best would be your EAR lib).
It may be versioning, but I don't thing so.
When two classes loaded by different classloader, a ClassNotFoundException is normally thrown.
When a class is passed over a wire/loaded from disk cache, VersionMismatchException is normally thrown.
When a class with different method signatures is used, NoSuchMethodError or alike is thrown.
I think this case is a corrupted class file. Could be corrupted in cache or in the JAR.

Classloader problem with EJB

I'm working on a project which includes persistence library (JPA 1.2), EJB 3 and Web presentation layer (JSF). I develop application using Eclipse and application is published on Websphere Application Server Community Edition (Geronimo 2.1.4) through eclipse plugin (but the same thing happens if I publish manually). When publishing to server I get the following error:
java.lang.NoClassDefFoundError: Could not fully load class: manager.administration.vehicles.VehicleTypeAdminBean
due to:manager/vehicles/VehicleType
in classLoader:
org.apache.geronimo.kernel.classloader.TemporaryClassLoader#18878c7
at org.apache.xbean.finder.ClassFinder.(ClassFinder.java:177)
at org.apache.xbean.finder.ClassFinder.(ClassFinder.java:146)...
In web.xml I have reference to EJB:
<ejb-local-ref>
<ejb-ref-name>ejb/VehicleTypeAdmin</ejb-ref-name>
<ejb-ref-type>Session</ejb-ref-type>
<local>manager.administration.vehicles.VehicleTypeAdmin</local>
<ejb-link>VehicleTypeAdminBean</ejb-link>
</ejb-local-ref>
EJB project has a reference to persistence project, and Web project has references to both projects. I don't get any compilation errors, so I suppose classes and references are correct.
I don't know if it is app server problem, but I ran previously application on the same server using same configuration parameters.
Does anybody have a clue what might be the problem?
Looks almost like it couldn't find the class manager.vehicles.VehicleType when it was attempting to create/load the class manager.administration.vehicles.VehicleTypeAdminBean.
I've encountered similar problems before. When the class loader attempts to load the class it looks at the import statements (and other class usage declarations) and then attempts to load those classes and so on until it reaches the bottom of the chain (ie java.lang.Object). If it cannot find one class along the chain (in your case it looks like it cannot load VehicleType) then it will state that it cannot load the class at the top of the chain (in your case VehicleTypeAdminBean).
Is the VehicleType class in a different jar? If you have a web module and and EJB module do you have the jar containing the VehicleType class in the appropriate place(s). Sometimes with web projects you have to put the jars in the WebContent/WEB-INF/lib folder or it won't find them.
Are both of these projects deployed separately (ie. two ears? or one ear and one war?) or are they together (ie, one ear with jars and a war inside?). I'm assuming the second given you declared your EJB local?
The jars that you are dependent on also have to be declared in your MANIFEST.MF files in the projects that use it.
I'm kind of running on guesses since I do not know your project structure. Showing that would help quite a bit. But I'd still check on where VehicleType is located with regards to your EJB class. You might find it isn't where you think it is come packaging or runtime.
Thanks #Chris for WebContent/WEB-INF/lib idea ! it works for me by following these steps :
1- Export my EJBs to a JAR (MyEJBs.jar)
2- I created another jar with your_installation_path/IBM/SDP/runtimes/your_version/binCreateEJBStrub.bat via CMD.exe, by executing this command :
createEJBStubs.bat <my_path>/MyEJBs.jar -newfile –quiet
3- A new jar will be automatically created in the same directory as MyEJBs.jar named MyEJBs_withStubs.jar
4- Put your new jar in WebContent/WEB-INF/lib
5- Call your EJBs by :
MyEJBRemote eJBRemote;
InitialContext ic = new InitialContext();
obj = ic.lookup("your_ejb_name_jndi");
eJBRemote = (MyEJBRemote ) PortableRemoteObject.narrow(obj,
MyEJBRemote.class);
eJBRemote = (MyEJBRemote ) obj;
Now you can call your EJBs from another EAR

Categories

Resources