如何避免使用Hibernate HQL结果的types安全警告?

例如,我有这样的查询:

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

如果我试图做这样的事情,它会显示警告“types安全:types列表的expression需要未经检查的转换,以符合列表”:

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

有没有办法避免它?

正如所build议的那样,在任何地方使用@SuppressWarnings是一个很好的方法,尽pipe每次调用q.list()都会涉及一些手指input。

还有两个我会build议的技术:

Collections.checkedList()

用这个replace你的任务:

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

您可能想要检查该方法的javadoc ,尤其是关于equalshashCode

写一个施舍帮手

只需将所有@SuppressWarnings重构为一个地方:

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

一些评论:

  • 我select传递Query而不是q.list()的结果,因为这种“作弊”方法只能用来作弊,而不是用来欺骗任何List
  • 你可以为.iterate()等添加类似的方法

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

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

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

如果您查看javax.persistence API文档 ,您将看到自Java Persistence 2.0以来,已经添加了一些新的方法。 其中之一是createQuery(String, Class<T>) ,它返回TypedQuery<T> 。 您可以像使用TypedQuery一样使用TypedQuery ,但是所有操作现在都是安全的。

所以,只要改变你的代码就可以这样做:

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

而且你们都定了。

在我们的代码中,我们用下面的方法来标注调用方法:

@SuppressWarnings( “未登记”)

我知道这似乎是一个黑客,但最近检查了一个合作开发者,发现这是我们所能做的。

显然,Hibernate API中的Query.list()方法在devise上并不安全,而且也没有计划改变它 。

我相信避免编译器警告的最简单的解决scheme的确是添加@SuppressWarnings(“unchecked”)。 这个注解可以放在方法级别,或者如果放在方法中,就放在variables声明之前。

如果你有一个方法封装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); 

我会得到一个编译错误: types不匹配:不能从列表转换为ArrayList

这不是一个疏忽或错误。 这个警告反映了一个真正的潜在问题 – java编译器没有办法确定hibernate类是否能够正常工作,并且返回的列表将只包含Cat。 这里的任何build议都很好。

尝试使用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(); 

不,但可以将其隔离为特定的查询方法,并用@SuppressWarnings("unchecked")注释来禁止警告。

我们有同样的问题。 但对我们来说这不是什么大问题,因为我们必须用Hibernate Query和Session来解决其他更重要的问题。

特别:

  1. 控制何时可以提交交易。 (我们想要计算一个tx被“启动”了多less次,只有在tx被“结束”了相同的启动次数时才提交,对于不知道是否需要启动事务的代码有用。任何需要一个tx的代码只是“启动”一个,并在完成时结束。)
  2. 性能指标收集。
  3. 延迟开始交易,直到知道事实将会被完成。
  4. query.uniqueResult()更温和的行为

所以对我们来说,我们有:

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

最后,

AmplafiQuery有一个“asList()”,它是Query.list()的通用启用版本。AmplafiQuery有一个“unique()”,它是Query.uniqueResult()的一个通用启用版本(只logging问题而不是抛出例外)

这是避免@SuppressWarnings的很多工作。 但是,正如我所说(和列出)还有很多其他更好的! 理由做包装工作。

乔·迪恩的解决scheme看起来很有趣,但你认为这是值得的 – 创build一个新的列表并循环所有元素,以摆脱警告?

(对不起,由于某种原因,不能直接向他的解决scheme添加评论)

我知道这是比较老,但在今天的马特Quails答案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(); 

在原始答复中显然会减less其他警告标记标记被浏览器剥离。

尝试这个:

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

避免使用Hibernate查询的types安全警告的一个好的解决scheme是使用像TorpedoQuery这样的工具来帮助您构build安全的hqltypes。

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

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

  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); } 

仅供参考 – 我创build了一个实用的方法,为我这样做,所以它不乱扔我的代码,我不必使用@SupressWarning。