服务器部署的持久性单元的类加载问题
Classloading Issue with server deployed persistence unit
我在 EAR 包中遇到问题,该包在 EJB 模块中包含服务器部署的持久性单元,在 WAR 模块中包含 Web 应用程序
EAR
|--- persistence unit (EJB module)
|--- web app (WAR)
...
一切都编译并成功执行部署(在 WildFly 10 CR5 下)。正确部署了持久性单元并创建了模式(在开发过程中使用 Hibernate 模式生成)。
尽管如此,当我尝试坚持其中一个实体时
MyEntitiy e = new MyEntitiy();
e.setId(UUID.randomUUID().toString());
e.setName("name");
entityService.save(e);
我收到一个运行时错误,其根本原因是:
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)
深入调试器,我找到了方法 sun.reflect.UnsafeFieldAccessorImpl.ensureObj
,它通过方法 Class.isAssignableFrom
在 classes
之间执行检查
Field
对象的 class (Field.getDeclaredClass()
)
- 要持久化的实体class
此检查 returns 错误,因为到 classes 已经加载了不同的 ClassLoader
s(它们在逻辑上是相同的 class) .
如何在不更改项目的总体布局的情况下解决这个问题(即,将持久性单元保留为 EJB 模块以在各个模块之间共享)?
我相信,您可能在 ejb jar 和 war 文件中包含了 MyEntity class(或实体),因此它们会被两个 class 加载器加载。您可能需要从 war 文件中删除域实体并对其进行测试。
根据 jboss 文档,默认情况下,在 ejb jar 中定义的 classes 可用于 war 文件中的 classes。因此,它们将仅由 ejb classloader 加载一次,并且对于 war 文件中的 classes 也是 used/available。
我在 EAR 包中遇到问题,该包在 EJB 模块中包含服务器部署的持久性单元,在 WAR 模块中包含 Web 应用程序
EAR
|--- persistence unit (EJB module)
|--- web app (WAR)
...
一切都编译并成功执行部署(在 WildFly 10 CR5 下)。正确部署了持久性单元并创建了模式(在开发过程中使用 Hibernate 模式生成)。
尽管如此,当我尝试坚持其中一个实体时
MyEntitiy e = new MyEntitiy();
e.setId(UUID.randomUUID().toString());
e.setName("name");
entityService.save(e);
我收到一个运行时错误,其根本原因是:
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)
深入调试器,我找到了方法 sun.reflect.UnsafeFieldAccessorImpl.ensureObj
,它通过方法 Class.isAssignableFrom
在 classes
Field
对象的 class (Field.getDeclaredClass()
)- 要持久化的实体class
此检查 returns 错误,因为到 classes 已经加载了不同的 ClassLoader
s(它们在逻辑上是相同的 class) .
如何在不更改项目的总体布局的情况下解决这个问题(即,将持久性单元保留为 EJB 模块以在各个模块之间共享)?
我相信,您可能在 ejb jar 和 war 文件中包含了 MyEntity class(或实体),因此它们会被两个 class 加载器加载。您可能需要从 war 文件中删除域实体并对其进行测试。
根据 jboss 文档,默认情况下,在 ejb jar 中定义的 classes 可用于 war 文件中的 classes。因此,它们将仅由 ejb classloader 加载一次,并且对于 war 文件中的 classes 也是 used/available。