尽管我的问题是关于Java泛型的,但我还是提供了一些与JPA相关的代码来向您展示真实上下文。

我正在使用基于JPA 2.0和Criteria API的查询。我所有的查询都遵循相同的模式(比较简单的属性;无需路径导航),因此我试图编写一个通用类来处理JPA,同时将业务逻辑保持在单独的类中。我的目标是要有一种方法,给定一个Entity类型,并使用一个Map存储定义条件的对(字段名称->期望值),并返回一个带有某些实体字段值的bean(或bean集合)。 。

我所有的实体都实现Persistible接口(interface),而我所有的传输对象都从QueryBean继承。我认为这些类与问题无关,因此我跳过了它们的代码。

以下代码是我的第一种方法的摘要(请假设cb是有效的CriteriaBuilder实例):

protected <T extends QueryBean, TT extends Persistible> Collection<T> executeQueryEntity
        (Class<T> type, Class<TT> rootType, QueryConfig queryConfig, Map<String, Object> parameters) {
    // (...) Initialization goes here

    CriteriaQuery<T> c = cb.createQuery(type);

    // FROM CLAUSE
    Root<TT> root = c.from(rootType);

    // SELECT CLAUSE
    List<String> constructorParams = queryConfig.getTargetAttributes();
    Selection<?>[] selectArray = new Selection<?>[constructorParams.size()];
    for (int i = 0; i < constructorParams.size(); i++) {
        selectArray[i] = root.get(constructorParams.get(i));
    }
    c.select(cb.construct(type, selectArray));

    // WHERE CLAUSE
    for (String filter : parameters.keySet()) {
        if (queryConfig.getFieldConfiguration().get(filter).compareUsingEquals()) {
            // SOME PREDICATE
        }
        else {
            // SOME OTHER PREDICATE
        }
    }

    // (...) Rest of the code goes here
}

我的QueryConfig界面如下:
public interface QueryConfig {

List<String> getTargetAttributes();
Map<String, FieldConfiguration> getFieldConfiguration();

}

因为我已经在使用QueryConfig类,该类提供有关查询的信息(例如QueryBean构造函数所需的参数或有关实体字段的信息),所以我认为从该类获取实体类型而不是传递实体类型会很好作为Class参数。我从this问题推断出它不能直接完成,因此我尝试了以下解决方法:

像这样向QueryConfig添加方法:
Class< ? extends Persistible> getTargetEntity();

添加这样的中间方法:
public <T extends QueryBean> Collection<T> queryMany(Class<T> type, QueryConfig config, Map<String, Object> parameters) {
    executeQueryEntity(type, config.getTargetEntity(), parameters);
}

但是它不会编译。我相信在这里解释了原因:Type mismatch for Class Generics,但实际上我不明白答案。
我的问题是:有没有办法避免将Class< TT >参数传递给execute方法?这是解决问题的好方法还是应该重构整个事情?
也欢迎对代码进行任何改进!

最佳答案

我不太了解您认为您的方法行得通的原因:
带有QueryConfigClass< ? extends Persistible> getTargetEntity();没有提供编译器可以引用的类型信息,为什么您认为编译器可以“猜测”您要返回的类型,并为您进行类型检查?

一种方法是在QueryConfig中提供类型信息

public interface QueryConfig <T extends Persistable> {
  Class<T> getTargetEntity();
  List<String> getTargetAttributes();
  Map<String, FieldConfiguration> getFieldConfiguration();
}

和您的queryMany方法可以像:
public <T extends QueryBean, TT extends Persistible>
Collection<T> queryMany(Class<T> type,
                        QueryConfig<TT> config,
                        Map<String, Object> parameters) {
    executeQueryEntity(type, config.getTargetEntity(), parameters);
}

09-28 10:20