如何避免使用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 ,尤其是关于equals
和hashCode
。
写一个施舍帮手
只需将所有@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来解决其他更重要的问题。
特别:
- 控制何时可以提交交易。 (我们想要计算一个tx被“启动”了多less次,只有在tx被“结束”了相同的启动次数时才提交,对于不知道是否需要启动事务的代码有用。任何需要一个tx的代码只是“启动”一个,并在完成时结束。)
- 性能指标收集。
- 延迟开始交易,直到知道事实将会被完成。
- query.uniqueResult()更温和的行为
所以对我们来说,我们有:
- 创build一个扩展Query的接口(AmplafiQuery)
- 创build一个扩展AmplafiQuery并包装org.hibernate.Query的类(AmplafiQueryImpl)
- 创build一个返回Tx的Txmanager。
- 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。