Search code examples
javaclassloaderwildfly

Classloading Issue with server deployed persistence unit


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

  1. the class of the Field object (Field.getDeclaredClass())
  2. 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)?


Solution

  • 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.