来自其他项目的实体的类加载错误
Classloading error on entity from other project
我想创建一个可以在我项目的 JSF 页面中使用的实体转换器。
我的项目结构如下:
-- 项目-ear.ear
|--- 项目1-ejb.jar
|--- 项目2-web.war
|--- 库
|---|--- warframework.jar
|---|--- ekbframework.jar
在 lib.jar 中我有一个抽象 class EntityConverter
在 lib/warframework.jar
.
中实现了 JSF 转换器逻辑
public abstract class EntityConverter implements Converter {
protected abstract EntityLoader getEntityLoader();
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (StringUtils.isBlank(value)) return null;
try {
String[] split = value.split(":");
return getEntityLoader().loadEntity(split[0], Long.valueOf(split[1]));
} catch (NumberFormatException e) {
return null;
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof AbstractEntity) {
return value.getClass() + ":" + ((AbstractEntity) value).getSid();
} else {
return value.toString();
}
}
}
还有一个接口EntityLoader
在lib/ejbframework.jar
.
public interface EntityLoader {
AbstractEntity loadEntity(String className, Long sid);
}
我正在使用 Mavens WAR-Overlay 功能将不同的 war-文件合并为一个。我有一个 project1-web.war
,它包含在 project2-web.war
中。
在那project1-web.war
我定义了Converter的具体实现:
@Named
@FacesConverter("concreteEntityConverter")
public class ConcreteEntityConverter extends EntityConverter {
@Inject
private ConcreteEntityLoader entityLoader;
@Override
protected EntityLoader getEntityLoader() {
return entityLoader;
}
}
并且在项目 1-ejb.jar 中我定义了 EntityLoader
实现:
public class ShsEntityLoader implements EntityLoader {
@Inject
Logger log;
@Inject
protected EntityManager entityManager;
@Override
public AbstractEntity loadEntity(String className, Long sid) {
AbstractEntity entity = null;
try {
entity = (AbstractEntity) entityManager.find(Class.forName(className), sid);
} catch (ClassNotFoundException ex) {
log.warn("Could not load entity for class: " + className, ex);
}
return entity;
}
}
部署 ear
并触发转换器后,出现以下错误:
Could not load entity for class: class de.example.com.user.model.MyEntity: java.lang.ClassNotFoundException: class de.example.com.user.model.MyEntity from [Module "deployment.project-ear.ear.project1-ejb.jar:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:363)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:351)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:93)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at de.example.com.common.service.ConcreteEntityLoader.loadEntity(ConcreteEntityLoader.java:30)
class de.example.com.user.model.MyEntity
与 EntityLoader
存在于同一个 jar 中。我认为,出现此异常是因为实体转换器是从 project2-web.war
文件调用的,class 加载程序无法访问 project1-ejb.jar
中的 classes。这个对吗?我必须更改什么才能正确加载 class?
发现问题:
我在 EntityConverter.getAsString()
中的代码创建了错误的对象字符串表示形式:
return value.getClass() + ":" + ((AbstractEntity) value).getSid();
结果是:class de.example.com.user.model.MyEntity:1
而不是预期的 de.example.com.user.model.MyEntity:1
。
将上面的代码更改为以下代码,使一切都按预期工作:
return value.getClass().getCanonicalName() + ":" + ((AbstractEntity) value).getSid();
我想创建一个可以在我项目的 JSF 页面中使用的实体转换器。
我的项目结构如下:
-- 项目-ear.ear
|--- 项目1-ejb.jar
|--- 项目2-web.war
|--- 库
|---|--- warframework.jar
|---|--- ekbframework.jar
在 lib.jar 中我有一个抽象 class EntityConverter
在 lib/warframework.jar
.
public abstract class EntityConverter implements Converter {
protected abstract EntityLoader getEntityLoader();
@Override
public Object getAsObject(FacesContext context, UIComponent component, String value) {
if (StringUtils.isBlank(value)) return null;
try {
String[] split = value.split(":");
return getEntityLoader().loadEntity(split[0], Long.valueOf(split[1]));
} catch (NumberFormatException e) {
return null;
}
}
@Override
public String getAsString(FacesContext context, UIComponent component, Object value) {
if (value == null) return null;
if (value instanceof AbstractEntity) {
return value.getClass() + ":" + ((AbstractEntity) value).getSid();
} else {
return value.toString();
}
}
}
还有一个接口EntityLoader
在lib/ejbframework.jar
.
public interface EntityLoader {
AbstractEntity loadEntity(String className, Long sid);
}
我正在使用 Mavens WAR-Overlay 功能将不同的 war-文件合并为一个。我有一个 project1-web.war
,它包含在 project2-web.war
中。
在那project1-web.war
我定义了Converter的具体实现:
@Named
@FacesConverter("concreteEntityConverter")
public class ConcreteEntityConverter extends EntityConverter {
@Inject
private ConcreteEntityLoader entityLoader;
@Override
protected EntityLoader getEntityLoader() {
return entityLoader;
}
}
并且在项目 1-ejb.jar 中我定义了 EntityLoader
实现:
public class ShsEntityLoader implements EntityLoader {
@Inject
Logger log;
@Inject
protected EntityManager entityManager;
@Override
public AbstractEntity loadEntity(String className, Long sid) {
AbstractEntity entity = null;
try {
entity = (AbstractEntity) entityManager.find(Class.forName(className), sid);
} catch (ClassNotFoundException ex) {
log.warn("Could not load entity for class: " + className, ex);
}
return entity;
}
}
部署 ear
并触发转换器后,出现以下错误:
Could not load entity for class: class de.example.com.user.model.MyEntity: java.lang.ClassNotFoundException: class de.example.com.user.model.MyEntity from [Module "deployment.project-ear.ear.project1-ejb.jar:main" from Service Module Loader]
at org.jboss.modules.ModuleClassLoader.findClass(ModuleClassLoader.java:198)
at org.jboss.modules.ConcurrentClassLoader.performLoadClassUnchecked(ConcurrentClassLoader.java:363)
at org.jboss.modules.ConcurrentClassLoader.performLoadClass(ConcurrentClassLoader.java:351)
at org.jboss.modules.ConcurrentClassLoader.loadClass(ConcurrentClassLoader.java:93)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at de.example.com.common.service.ConcreteEntityLoader.loadEntity(ConcreteEntityLoader.java:30)
class de.example.com.user.model.MyEntity
与 EntityLoader
存在于同一个 jar 中。我认为,出现此异常是因为实体转换器是从 project2-web.war
文件调用的,class 加载程序无法访问 project1-ejb.jar
中的 classes。这个对吗?我必须更改什么才能正确加载 class?
发现问题:
我在 EntityConverter.getAsString()
中的代码创建了错误的对象字符串表示形式:
return value.getClass() + ":" + ((AbstractEntity) value).getSid();
结果是:class de.example.com.user.model.MyEntity:1
而不是预期的 de.example.com.user.model.MyEntity:1
。
将上面的代码更改为以下代码,使一切都按预期工作:
return value.getClass().getCanonicalName() + ":" + ((AbstractEntity) value).getSid();