在 Generic Class 中注入 InjectionPoint 以获得实际的 class 类型?
Inject InjectionPoint in Generic Class to get the actual class type?
在我的 JSF 2.3 项目(wildfly 19 app.server)中,我有一个通用的 EntityService class,它采用两个类型参数。 EntityService class 还注入另一个 class GenericEntityService。 GenericEntityService 是一个 @Stateless bean,它使用 EntityManager 来完成真正的工作(查找实体、更新实体、删除实体、插入实体...)
@Dependent
public class EntityService<T, ID> {
@Inject
private GenericEntityService<T, ID> entityService;
private Class<T> entityClass;
@Inject
private void entityClass(InjectionPoint injectionPoint) {
ParameterizedType type = (ParameterizedType) injectionPoint.getType();
Class<T> entityClass = (Class<T>) type.getActualTypeArguments()[0];
this.entityClass = entityClass;
}
public T find(ID id) {
return entityService.find(entityClass, id);
}
public List<T> findAll() {
return entityService.findAll(entityClass);
}
[...]
}
因为 EntityManager 的 find 方法需要一个 class 类型作为参数,我在 entityClass 方法中注入了一个 InjectionPoint 来获取实际的“实体 class 类型”并将其作为一个GenericEntityService 方法的参数。
这种从类型参数中获取 class 类型的方法有什么问题吗?
由于您的 entityClass 函数没有被调用,它不会填充您的 entityClass 字段,因此在调用时它将始终为 null。
您可以使用类似的方法,避免注入点的需要,使用使用参数化类型的 getter 方法。您的代码将更改为:
@Dependent
public abstract class EntityService<T, ID> {
@Inject
private GenericEntityService<T, ID> entityService;
private Class<T> entityClass;
public synchronized Class<T> getEntityClass() {
if (entityClass == null) {
entityClass = inferEntityClass(getClass());
}
return entityClass;
}
private Class<?> inferEntityClass(Class<?> clazz) {
// This code should be safer
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
public T find(ID id) {
return entityService.find(getEntityClass(), id);
}
// ...
}
旁注,不相关:我不明白为什么您应该创建另一层 bean 而不是直接从您的 EntityService 调用 EntityManager。请注意,CDI 上已经存在一些证明此体系结构合理的功能,例如事务控制。
在我的 JSF 2.3 项目(wildfly 19 app.server)中,我有一个通用的 EntityService class,它采用两个类型参数。 EntityService class 还注入另一个 class GenericEntityService。 GenericEntityService 是一个 @Stateless bean,它使用 EntityManager 来完成真正的工作(查找实体、更新实体、删除实体、插入实体...)
@Dependent
public class EntityService<T, ID> {
@Inject
private GenericEntityService<T, ID> entityService;
private Class<T> entityClass;
@Inject
private void entityClass(InjectionPoint injectionPoint) {
ParameterizedType type = (ParameterizedType) injectionPoint.getType();
Class<T> entityClass = (Class<T>) type.getActualTypeArguments()[0];
this.entityClass = entityClass;
}
public T find(ID id) {
return entityService.find(entityClass, id);
}
public List<T> findAll() {
return entityService.findAll(entityClass);
}
[...]
}
因为 EntityManager 的 find 方法需要一个 class 类型作为参数,我在 entityClass 方法中注入了一个 InjectionPoint 来获取实际的“实体 class 类型”并将其作为一个GenericEntityService 方法的参数。
这种从类型参数中获取 class 类型的方法有什么问题吗?
由于您的 entityClass 函数没有被调用,它不会填充您的 entityClass 字段,因此在调用时它将始终为 null。
您可以使用类似的方法,避免注入点的需要,使用使用参数化类型的 getter 方法。您的代码将更改为:
@Dependent
public abstract class EntityService<T, ID> {
@Inject
private GenericEntityService<T, ID> entityService;
private Class<T> entityClass;
public synchronized Class<T> getEntityClass() {
if (entityClass == null) {
entityClass = inferEntityClass(getClass());
}
return entityClass;
}
private Class<?> inferEntityClass(Class<?> clazz) {
// This code should be safer
ParameterizedType parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
public T find(ID id) {
return entityService.find(getEntityClass(), id);
}
// ...
}
旁注,不相关:我不明白为什么您应该创建另一层 bean 而不是直接从您的 EntityService 调用 EntityManager。请注意,CDI 上已经存在一些证明此体系结构合理的功能,例如事务控制。