如何在Hibernate HQL结果中避免类型安全警告?


105

例如我有这样的查询:

Query q = sess.createQuery("from Cat cat");
List cats = q.list();

如果我尝试做这样的事情,它将显示以下警告

Type safety: The expression of type List needs unchecked conversion to conform to List<Cat>


List<Cat> cats = q.list();

有办法避免吗?


11
值得一提的是,通过JPA,您可以通过将类型添加到createQuery中来进行类型安全的查询。
Elazar Leibovich

5
有点晚了,但sess.createQuery("from Cat cat", Cat.class);正如Elazar所说。
多米尼克·莫尔

Answers:


99

@SuppressWarnings如建议的那样,在任何地方使用都是一种不错的方法,尽管每次调用都会涉及一些手指输入q.list()

我建议使用其他两种技术:

写一个演员助手

只需将所有内容重构@SuppressWarnings到一个位置即可:

List<Cat> cats = MyHibernateUtils.listAndCast(q);

...

public static <T> List<T> listAndCast(Query q) {
    @SuppressWarnings("unchecked")
    List list = q.list();
    return list;
}

防止Eclipse针对不可避免的问题生成警告

在Eclipse中,转到“窗口”>“首选项”>“ Java”>“编译器”>“错误/警告”,然后在“通用类型”下,选中复选框 Ignore unavoidable generic type problems due to raw APIs

对于类似的问题,这将关闭不必要的警告,这些警告是不可避免的。

一些评论:

  • 我选择传递Query而不是结果,q.list()因为那样,这种“欺骗”方法只能用于用Hibernate进行欺骗,而不能用于List一般的欺骗。
  • 您可以为.iterate()etc 添加类似的方法。

20
乍一看,Collections.checkedList(Collection <E>,Class <E>)方法看起来是完美的解决方案。但是,javadoc说它仅防止通过该方法生成的类型安全视图添加类型错误的元素。在给定列表上不进行任何检查。
phatblat

11
“ List <Cat> list = Collections.checkedList(q.list(),Cat.class);” 在Eclipse中仍然需要“ @SuppressWarnings”。关于另一个技巧:键入“ listAndCast”实际上并不比通过Eclipse自动添加的“ @SuppressWarnings”短。
特里斯坦,

2
顺便说一句,Collections.checkedList()方法不会抑制未选中的分配警告。
暗黑破坏神

39

提出问题已经有很长时间了,但是我希望我的回答可能对像我这样的人有所帮助。

如果您看一下javax.persistence api docs,您会发现此后已经添加了一些新方法Java Persistence 2.0。其中之一就是createQuery(String, Class<T>)回报TypedQuery<T>。您可以像使用TypedQuery它一样使用,只是Query所有操作现在都是类型安全的,差别很小。

因此,只需将代码更改为如下所示:

Query q = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q.list();

你们都准备好了。


1
问题不是JPA
Mathijs塞赫尔斯

2
Hibernate的最新版本实现了JPA 2.x,因此此答案很重要。
caspinos

TypedQuery <T>是最佳方案。
穆尼卜·米尔扎

21

我们也使用@SuppressWarnings("unchecked")它,但是我们经常尝试仅在变量的声明上使用它,而不是在整个方法上使用它:

public List<Cat> findAll() {
    Query q = sess.createQuery("from Cat cat");
    @SuppressWarnings("unchecked")
    List<Cat> cats = q.list();
    return cats;
}

15

尝试使用TypedQuery而不是Query。例如,代替此:

Query q = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q.list();

用这个:-

TypedQuery<Cat> q1 = sess.createQuery("from Cat cat", Cat.class);
List<Cat> cats = q1.list();

1
有办法做到这一点Criteria吗?
Stealth Rabbi

5

在我们的代码中,我们使用以下注释注释调用方法:

@SuppressWarnings(“未选中”)

我知道这看起来像是骇客,但一位共同开发人员最近检查了一下,发现这是我们所能做的。


5

显然,Hibernate API中的Query.list()方法不是“按设计”类型安全的,并且没有计划对其进行更改

我相信避免编译器警告的最简单解决方案的确是添加@SuppressWarnings(“ unchecked”)。该注释可以放在方法级别,或者如果在方法内部,则放在变量声明之前。

如果您有一个封装Query.list()并返回List(或Collection)的方法,则还会收到警告。但是可以使用@SuppressWarnings(“ rawtypes”)来抑制这一行为。

Matt Quail提出的listAndCast(Query)方法不如Query.list()灵活。虽然我可以做:

Query q = sess.createQuery("from Cat cat");
ArrayList cats = q.list();

如果我尝试下面的代码:

Query q = sess.createQuery("from Cat cat");
ArrayList<Cat> cats = MyHibernateUtils.listAndCast(q);

我会收到一个编译错误:类型不匹配:无法从List转换为ArrayList


1
“没有改变它的计划。” -这是2005年的帖子。如果从那以后一切都没有改变,我会感到惊讶。
Rup

4

这不是疏忽或错误。该警告反映了一个真正的潜在问题-java编译器无法真正确定hibernate类将正确执行其工作,并且返回的列表仅包含Cats。这里的任何建议都可以。


2

不可以,但是您可以将其隔离为特定的查询方法,并通过@SuppressWarnings("unchecked")注释禁止显示警告。


错误... Joe Dean是正确的,可以使用?作为避免警告的通用类型...
Mike Stone

1
这不是真的。如果使用List <?>,那么如果没有不必要的步骤来创建重复列表并投射每个项目,则不能将列表的元素用作Cat的元素。
Dave L.

好吧,如果您直接通过强制转换使用结果,则无需创建列表,而无论问题是“是否有避免该问题的方法”,答案肯定是肯定的(即使没有胁迫警告)
迈克Stone

2

较新版本的Hibernate现在支持类型安全的Query<T>对象,因此您不再需要使用@SuppressWarnings或实施一些技巧来使编译器警告消失。在Session API中Session.createQuery现在将返回类型安全的Query<T>对象。您可以通过以下方式使用它:

Query<Cat> query = session.createQuery("FROM Cat", Cat.class);
List<Cat> cats = query.list();

当查询结果不会返回Cat时,您也可以使用它:

public Integer count() {
    Query<Integer> query = sessionFactory.getCurrentSession().createQuery("SELECT COUNT(id) FROM Cat", Integer.class);
    return query.getSingleResult();
}

或进行部分选择时:

public List<Object[]> String getName() {
    Query<Object[]> query = sessionFactory.getCurrentSession().createQuery("SELECT id, name FROM Cat", Object[].class);
    return query.list();
}

1

我们有同样的问题。但这对我们来说并不重要,因为我们不得不使用Hibernate Query和Session解决其他更主要的问题。

特别:

  1. 控制何时可以提交事务。(我们想计算tx被“启动”的次数,并且仅在tx被“终止”与启动相同的次数时才提交。对于不知道是否需要启动事务的代码很有用。现在任何需要发送代码的代码都只是“开始”一个,并在完成后结束它。)
  2. 绩效指标收集。
  3. 延迟启动事务,直到知道将实际完成某件事为止。
  4. query.uniqueResult()的行为更加温和

因此,对于我们来说,我们有:

  1. 创建扩展查询的接口(AmplafiQuery)
  2. 创建一个扩展AmplafiQuery并包装org.hibernate.Query的类(AmplafiQueryImpl)
  3. 创建一个返回Tx的Txmanager。
  4. Tx具有各种createQuery方法并返回AmplafiQueryImpl

最后,

AmplafiQuery具有一个“ asList()”,它是Query.list()的通用版本。AmplafiQuery具有一个“ unique()”,它是Query.uniqueResult()的一个通用版本(并且仅记录问题而不是抛出一个问题。例外)

避免@SuppressWarnings要做很多工作。但是,就像我说的(和列出的)一样,还有很多其他更好的选择!做包装工作的原因。


0

我知道这个年龄较大,但截至今天在Matt Quails Answer中要注意2点。

点1

这个

List<Cat> cats = Collections.checkedList(Cat.class, q.list());

应该是这个

List<Cat> cats = Collections.checkedList(q.list(), Cat.class);

点2

由此

List list = q.list();

对此

List<T> list = q.list();

显然会减少其他警告,因为浏览器剥离了原始回复标签标记。


尝试使答案是对问题的回答,而不是对其他答案的回答。可以在Matt Quail的答案中加入评论以表示他已经过时,但只写正确而正确的答案即可。
科里·肯德尔

-1

试试这个:

Query q = sess.createQuery("from Cat cat");
List<?> results = q.list();
for (Object obj : results) {
    Cat cat = (Cat) obj;
}

4
这是Joe Dean的答案的不好的副本,因为您仍然必须对cat实例进行处理。
Artjom B.

-1

避免使用休眠查询进行类型安全警告的一个好的解决方案是使用TorpedoQuery之类的工具来帮助您构建类型安全的hql。

Cat cat = from(Cat.class);
org.torpedoquery.jpa.Query<Entity> select = select(cat);
List<Cat> cats = select.list(entityManager);


-6

如果您不想使用@SuppressWarnings(“ unchecked”),则可以执行以下操作。

   Query q = sess.createQuery("from Cat cat");
   List<?> results =(List<?>) q.list();
   List<Cat> cats = new ArrayList<Cat>();
   for(Object result:results) {
       Cat cat = (Cat) result;
       cats.add(cat);
    }

仅供参考-我创建了一个为我执行此操作的util方法,因此它不会乱扔我的代码,也不必使用@SupressWarning。


2
那真是愚蠢。您要添加运行时开销来克服与编译器完全相关的问题。请记住,类型参数没有被修饰,因此没有运行时检查类型。
John Nilsson

同意,如果您仍想执行以下操作,则可以使用以下类型添加类型的运行时检查:List <Cat> cats = Collections.checkedList(new ArrayList <Cat>(),Cat.class); cats.addAll(q.list()); 这应该工作。
ddcruver
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.