web-dev-qa-db-ja.com

Hibernate HQLの結果で型安全性の警告を回避する方法は?

たとえば、私はそのようなクエリがあります:

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

それを回避する方法はありますか?

101
serg

提案されているように、_@SuppressWarnings_をあらゆる場所で使用するのは良い方法ですが、q.list()を呼び出すたびに少し指を入力する必要があります。

私が提案する他の2つのテクニックがあります:

キャストヘルパーを書く

すべての_@SuppressWarnings_を1つの場所にリファクタリングするだけです。

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

...

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

Eclipseが避けられない問題の警告を生成しないようにする

Eclipseで、Window> Preferences> Java> Compiler> Errors/Warningsに移動し、Generic typeでチェックボックス_Ignore unavoidable generic type problems due to raw APIs_を選択します

これにより、上記のような避けられない類似の問題に対する不要な警告がオフになります。

コメント:

  • q.list()の結果の代わりにQueryを渡すことを選択しました。これは、この「チート」メソッドはHibernateでチートするためにのみ使用でき、List 一般に。
  • .iterate()などにも同様のメソッドを追加できます。
96
Matt Quail

質問が出されてから長い時間が経ちましたが、私の答えが私のような人に役立つことを願っています。

Javax.persistence api docs を見ると、_Java Persistence 2.0_以降にいくつかの新しいメソッドが追加されていることがわかります。それらの1つはcreateQuery(String, Class<T>)で、_TypedQuery<T>_を返します。 TypedQueryを使用したときと同じようにQueryを使用できます。ただし、すべての操作がタイプセーフになるというわずかな違いがあります。

したがって、次のようにコードをsmthに変更するだけです。

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

そして、あなたはすべて設定されています。

33
antonpp

@SuppressWarnings("unchecked")も使用しますが、ほとんどの場合、メソッド全体ではなく、変数の宣言でのみ使用しようとします。

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

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();
13
shivam oberoi

このコードでは、呼び出しメソッドに次の注釈を付けます。

@SuppressWarnings( "unchecked")

ハックのように見えますが、共同開発者が最近チェックし、それが私たちにできるすべてであることがわかりました。

5
tyshock

どうやら、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に変換できません

5
Paulo Merson

それは見落としや間違いではありません。警告は実際の根本的な問題を反映しています-Javaコンパイラがhibernateクラスが適切に仕事をすることを確実にし、返されるリストにCatsのみが含まれることを確実にする方法はありません。ここでの提案はすべて問題ありません。

4
paulmurray

いいえ。ただし、特定のクエリメソッドに分離し、@SuppressWarnings("unchecked")アノテーションを使用して警告を抑制することができます。

2
Dave L.

Hibernateの新しいバージョンでは、タイプセーフQuery<T>オブジェクトを使用するため、@SuppressWarningsまたはハッカーを実装して、コンパイラの警告を消します。 セッションAPISession.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
David DeMar

同じ問題がありました。しかし、Hibernate QueryとSessionに関する他のより大きな問題を解決しなければならなかったため、それは大したことではありませんでした。

具体的には:

  1. トランザクションをコミットできるタイミングを制御します。 (txが「開始」された回数をカウントし、txが開始されたのと同じ回数だけ「終了」した場合にのみコミットしたかった。トランザクションを開始する必要があるかどうかわからないコードに役立ちます。 txを必要とするコードは、txを「開始」し、完了したら終了します。
  2. パフォーマンスメトリックの収集。
  3. 実際に何かが行われることがわかるまで、トランザクションの開始を遅らせる。
  4. Query.uniqueResult()のより穏やかな動作

したがって、私たちには次のものがあります。

  1. Queryを拡張するインターフェース(AmplafiQuery)を作成する
  2. AmplafiQueryを拡張し、org.hibernate.Queryをラップするクラス(AmplafiQueryImpl)を作成します
  3. Txを返すTxmanagerを作成します。
  4. TxにはさまざまなcreateQueryメソッドがあり、AmplafiQueryImplを返します

そして最後に、

AmplafiQueryには、Query.list()の汎用有効バージョンである「asList()」があります。AmplafiQueryには、Query.uniqueResult()の汎用有効バージョンである「unique()」があります。例外)

これは、@ SuppressWarningsを回避するための多くの作業です。しかし、私が言ったように(そしてリストされているように)より良いものがたくさんあります!ラッピング作業を行う理由。

1
Pat

Joe Deanのソリューションは興味深いように見えますが、それだけの価値があると思います。警告を取り除くために、新しいリストを作成し、すべての要素をループしますか?

(申し訳ありませんが、何らかの理由で彼のソリューションに直接コメントを追加することはできません)

0
serg

これは古いことは知っていますが、今日の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();

元の返信タグマーカーがブラウザによって削除された場合、他の警告が明らかに減少します。

0
Tony Shih