【问题标题】:Inject InjectionPoint in Generic Class to get the actual class type?在泛型类中注入 InjectionPoint 以获取实际的类类型?
【发布时间】:2020-07-13 20:48:00
【问题描述】:

在我的 JSF 2.3 项目(wildfly 19 app.server)中,我有一个通用 EntityService 类,它采用两个类型参数。 EntityService 类还注入了另一个类 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 方法需要类类型作为参数,所以我在 entityClass 方法中注入了一个 InjectionPoint 来获取实际的“实体类类型”并将其作为参数传递给 GenericEntityService 方法。

这种从类型参数中获取类类型的方法有什么问题吗?

【问题讨论】:

    标签: java generics cdi


    【解决方案1】:

    由于您的 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 上。

    【讨论】:

    • 感谢您的回答。首先:容器调用我的初始化方法 entityClass,因此注入 InjectionPoint(它使用 wildfly 19 工作)。第二:我必须在这里使用组合,因为我的无状态 bean 上不能有状态。我尝试了“全在一个类”的方法,但这不适用于无状态 bean(根据文档,无状态 bean 被池化,并且不能保证我为每个 @Inject 获得一个新实例或为我的方法调用获得相同的实例)
    • 我将删除之前调用初始化方法的需要,如答案中的代码中所述,因为该策略避免了对 CDI 提供程序的再次调用(和注入),并且仅依赖于编译类。关于组合,您的服务中会保留哪些陈旧数据?还有一件事:我回答你的问题了吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-06-07
    • 1970-01-01
    • 2013-09-13
    • 1970-01-01
    • 2019-01-20
    相关资源
    最近更新 更多