Java 如何避免 Hibernate HQL 结果的类型安全警告?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/115692/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 08:26:19  来源:igfitidea点击:

How to avoid type safety warnings with Hibernate HQL results?

javagenerics

提问by serg

For example I have such query:

例如我有这样的查询:

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

If I try to make something like this it shows the following warning

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

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


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

Is there a way to avoid it?

有没有办法避免它?

采纳答案by Matt Quail

Using @SuppressWarningseverywhere, as suggested, is a good way to do it, though it does involve a bit of finger typing each time you call q.list().

@SuppressWarnings正如建议的那样,在任何地方使用是一个很好的方法,尽管每次调用q.list().

There are two other techniques I'd suggest:

我建议使用另外两种技术:

Write a cast-helper

写一个演员表助手

Simply refactor all your @SuppressWarningsinto one place:

只需将所有内容重构@SuppressWarnings到一个地方:

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

...

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

Prevent Eclipse from generating warnings for unavoidable problems

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

In Eclipse, go to Window>Preferences>Java>Compiler>Errors/Warnings and under Generic type, select the checkbox Ignore unavoidable generic type problems due to raw APIs

在 Eclipse 中,转到 Window>Preferences>Java>Compiler>Errors/Warnings 并在 Generic type 下,选中复选框 Ignore unavoidable generic type problems due to raw APIs

This will turn off unnecessary warnings for similar problems like the one described above which are unavoidable.

这将关闭对类似问题的不必要警告,如上述不可避免的问题。

Some comments:

一些评论:

  • I chose to pass in the Queryinstead of the result of q.list()because that way this "cheating" method can only be used to cheat with Hibernate, and not for cheating any Listin general.
  • You could add similar methods for .iterate()etc.
  • 我选择传入 theQuery而不是 result ,q.list()因为这样这种“作弊”方法只能用于与 Hibernate 作弊,而不能用于作弊List一般。
  • 您可以为.iterate()等添加类似的方法。

回答by tyshock

In our code we annotate the calling methods with:

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

@SuppressWarnings("unchecked")

@SuppressWarnings("未选中")

I know it seems like a hack, but a co-developer checked recently and found that was all we could do.

我知道这看起来像是一种黑客行为,但最近一位合作开发人员检查并发现这就是我们所能做的。

回答by Dave L.

No, but you can isolate it into specific query methods and suppress the warnings with a @SuppressWarnings("unchecked")annotation.

不,但您可以将其隔离到特定的查询方法中,并使用@SuppressWarnings("unchecked")注释抑制警告。

回答by Joe Dean

If you don't want to use @SuppressWarnings("unchecked") you can do the following.

如果您不想使用 @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);
    }

FYI - I created a util method that does this for me so it doesn't litter my code and I don't have to use @SupressWarning.

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

回答by cretzel

We use @SuppressWarnings("unchecked")as well, but we most often try to use it only on the declaration of the variable, not on the method as a whole:

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

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

回答by Pat

We had same problem. But it wasn't a big deal for us because we had to solve other more major issues with Hibernate Query and Session.

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

Specifically:

具体来说:

  1. control when a transaction could be committed. (we wanted to count how many times a tx was "started" and only commit when the tx was "ended" the same number of times it was started. Useful for code that doesn't know if it needs to start a transaction. Now any code that needs a tx just "starts" one and ends it when done.)
  2. Performance metrics gathering.
  3. Delaying starting the transaction until it is known that something will actually be done.
  4. More gentle behavior for query.uniqueResult()
  1. 控制何时可以提交事务。(我们想计算一个 tx 被“开始”的次数,并且只在 tx 被“结束”时提交与它开始的相同次数。对于不知道它是否需要开始事务的代码很有用。现在任何需要 tx 的代码都只是“开始”并在完成后结束。)
  2. 性能指标收集。
  3. 延迟启动事务,直到知道某些事情会实际完成。
  4. query.uniqueResult() 的更温和的行为

So for us, we have:

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

  1. Create an interface (AmplafiQuery) that extends Query
  2. Create a class (AmplafiQueryImpl) that extends AmplafiQuery and wraps a org.hibernate.Query
  3. Create a Txmanager that returns a Tx.
  4. Tx has the various createQuery methods and returns AmplafiQueryImpl
  1. 创建一个扩展 Query 的接口 (AmplafiQuery)
  2. 创建一个扩展 AmplafiQuery 的类 (AmplafiQueryImpl) 并包装一个 org.hibernate.Query
  3. 创建一个返回 Tx 的 Txmanager。
  4. Tx 有各种 createQuery 方法并返回 AmplafiQueryImpl

And lastly,

最后,

AmplafiQuery has a "asList()" that is a generic enabled version of Query.list() AmplafiQuery has a "unique()" that is a generic enabled version of Query.uniqueResult() ( and just logs an issue rather than throwing an exception)

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

This is a lot of work for just avoiding @SuppressWarnings. However, like I said (and listed) there are lots of other better! reasons to do the wrapping work.

为了避免@SuppressWarnings,这需要做很多工作。然而,就像我说的(和列出的)还有很多其他更好的!做包装工作的理由。

回答by paulmurray

It's not an oversight or a mistake. The warning reflects a real underlying problem - there is no way that the java compiler can really be sure that the hibernate class is going to do it's job properly and that the list it returns will only contain Cats. Any of the suggestions here is fine.

这不是疏忽或错误。该警告反映了一个真正的潜在问题——java 编译器无法真正确定 hibernate 类将正确地完成它的工作,并且它返回的列表将只包含 Cats。这里的任何建议都很好。

回答by Tony Shih

I know this is older but 2 points to note as of today in Matt Quails Answer.

我知道这是较旧的,但截至今天,在 Matt Quails Answer 中需要注意 2 点。

Point 1

第 1 点

This

这个

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

Should be this

应该是这个

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

Point 2

第 2 点

From this

由此

List list = q.list();

to this

对此

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

would reduce other warnings obviously in original reply tag markers were stripped by the browser.

会明显减少其他警告,原始回复标签标记被浏览器剥离。

回答by Paulo Merson

Apparently, the Query.list() method in the Hibernate API is not type safe "by design", and there are no plans to change it.

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

I believe the simplest solution to avoid compiler warnings is indeed to add @SuppressWarnings("unchecked"). This annotation can be placedat the method level or, if inside a method, right before a variable declaration.

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

In case you have a method that encapsulates Query.list() and returns List (or Collection), you also get a warning. But this one is suppressed using @SuppressWarnings("rawtypes").

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

The listAndCast(Query) method proposed by Matt Quail is less flexible than Query.list(). While I can do:

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

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

If I try the code below:

如果我尝试下面的代码:

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

I'll get a compile error: Type mismatch: cannot convert from List to ArrayList

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

回答by Brian Ngure

Try this:

尝试这个:

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