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、2011

5
少し遅れましたがsess.createQuery("from Cat cat", Cat.class);、エラザーが言ったように。
ドミニクモール2013

回答:


99

@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で、[ウィンドウ]> [設定]> [Java]> [コンパイラ]> [エラー/警告]に移動し、[一般的なタイプ]でチェックボックスを選択します Ignore unavoidable generic type problems due to raw APIs

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

いくつかのコメント:

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

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()メソッドは未チェックの割り当ての警告を抑制しません。
Diablo

39

質問されて久しぶりですが、私のような回答が私のような人のお役に立てれば幸いです。

javax.persistence api docsを見ると、そこからいくつかの新しいメソッドが追加されていることがわかりますJava Persistence 2.0。それらの1つは、どれが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 Segers

2
Hibernateの最近のバージョンはJPA 2.xを実装しているため、この回答は重要です。
カスピノ

TypedQuery <T>が最適なシナリオです。
Muneeb Mirza

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ますか?
ステルスラビ

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

コンパイルエラーが発生します:型の不一致:リストからArrayListに変換できません


1
「変更する予定はありません。」-これは2005年の投稿です。それ以降、状況が変わらないとしたら驚きます。
Rupの

4

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


2

いいえ。ただし、特定のクエリメソッドに分離し、@SuppressWarnings("unchecked")注釈を付けて警告を抑制することができます。


間違っています... Joe Deanは正解です。警告を回避するためのジェネリック型として...
マイク・ストーン

1
それは真実ではない。List <?>を使用する場合、重複したリストを作成して各項目をキャストする不要な手順がないと、リストの要素をCatとして使用できません。
Dave L.

まあ、キャストを介して直接結果を使用する場合、リストを作成する必要はありません。それにもかかわらず、「それを回避する方法はあるか」という質問でしたが、答えは間違いなくYESです(警告を抑制しなくても)
Mike石

2

Hibernateの新しいバージョンでタイプセーフQuery<T>オブジェクトがサポートされるようになっ@SuppressWarningsたため、コンパイラの警告を消すためにハックを使用または実装する必要がなくなりました。ではセッションAPISession.createQuery今タイプセーフ返されQuery<T>たオブジェクトを。次のように使用できます。

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

クエリ結果が猫を返さないときにも使用できます。

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 and Sessionで他のより大きな問題を解決する必要があったので、それは私たちにとって大した問題ではありませんでした。

具体的には:

  1. トランザクションをいつコミットできるかを制御します。(txが「開始」された回数を数え、txが開始されたのと同じ回数だけtxが「終了」したときにのみコミットしたかったのです。トランザクションを開始する必要があるかどうかわからないコードに役立ちます。 txを必要とするすべてのコードは、1つを「開始」し、終了時にそれを終了します。)
  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を回避するだけの多くの作業です。しかし、私が言った(そしてリストされた)ように、他にももっとたくさんあります!ラッピング作業を行う理由。


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の回答にコメントを含めて、彼が時代遅れだと言っても問題ありませんが、回答を純粋かつ正確に書いてください。
Cory Kendall


-1

休止状態のクエリでタイプセーフの警告を回避するための適切なソリューションは、TorpedoQueryなどのツールを使用して、タイプセーフなhqlを構築するのに役立ちます。

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

-1
TypedQuery<EntityName> createQuery = entityManager.createQuery("from EntityName", EntityName.class);
List<EntityName> resultList = createQuery.getResultList();

3
ソリューションがどのように機能するかについて、わかりやすい説明を提供してください。参照: 良い回答を書くにはどうすればよいですか?。ありがとう。
Shree

1
他の人がコードから学ぶことができるように、コードに説明を追加できますか?
Nico Haase

-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、

同意します。それでもこのようなことを実行したい場合は、次のようにして型のランタイムチェックを追加できます。cats.addAll(q.list()); これはうまくいくはずです。
ddcruver 2010年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.