2013-04-24 282 views
7

尽管我的问题是关于Java泛型的,但我已经提供了一些与JPA相关的代码来向您展示真实的上下文。Java泛型:如何从一个方法获得泛型类型?

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

我的所有实体都实现了Persistible接口,而我的所有传输对象都继承自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(); 

} 

由于我已经使用提供关于查询的信息的类(例如QueryBean构造函数所需的参数或关于实体字段的信息)的类,我认为从该类获取实体类型而不是将其作为Cla类传递将会很不错ss参数。我从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方法?这是处理这个问题的好方法,还是我应该重构整个事情? 代码的任何改进也是受欢迎的!

+1

你的英语,顺便说一句,其实是很不错的。实际上,除非你指出,否则我甚至都没有注意到。 – Zyerah 2013-04-24 04:01:40

+2

@Telthien谢谢你,我尽我所能=) – DiegoAlfonso 2013-04-24 04:20:01

+1

你最好的传球比许多母语人士更好!努力是真正的赞赏。 – Zyerah 2013-04-24 04:23:24

回答

2

我不太明白为什么你认为你的方法将工作的原因: 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); 
} 
+0

非常感谢!我在尝试类似的东西,但是在queryMany的签名中遗漏了QueryConfig的类型参数,所以编译器抱怨从Class转换到Class DiegoAlfonso 2013-04-24 12:46:57