9

今日、私は JVM の非常に奇妙な動作を発見しました。a (通常はタイプ セーフ)List<Date>が実際にList<MyObject>は実行時に a を保持していました!

どうしてそんなことが起こったのだろうと思いますが、ウェブで何も見つかりませんでした。

それが状況です:私は with で作業していSpring Data JPA 1.2.0ます。JBoss EAP 6.0 ServerJRE 1.6.0_18-b07

誤って、あるSpring Data JPA Repositoryクラスで、式に間違った結果タイプが書き込まれました@Query。次のようになっているはずです。

  @Query("select distinct trunc(record.orderDateTime) from MyType record [...]" )
  public List<Date> getOrderDates(...);

しかし、次のとおりでした。

  @Query("select record from MyType record [...]" )
  public List<Date> getOrderDates(...);

したがって、目的は日付のリスト ( java.util.Date) をロードすることでした。これは、最初のコード スニペットのようにクエリが適切に定義されている場合に正常に機能します。

しかし、そのコーディング ミスにより、次のような結果になりました。List<MyType>メソッドのシグネチャでList<Date>. また、私のモデルでは、List<Date>was/contained の属性がList<MyType>. 私はそれをデバッグし、私の目を信じることができませんでした! MyTypeこのリストの内容を JSP に書き込むことさえできました (私がこの奇妙な動作を認識したのは、型一致 from toの試行で発生した Spring 式言語エラーが原因で JSP を表示できなくなったためでしDateた。クラッシュする)。

Java の型安全性に対する信念を捨てようか。

誰もそのような問題を抱えたことがありますか?

これについての説明はありますか?

それを修正するために何かできることはありますか、それとも一般的な問題ですか? おそらく、JRE、JBOSS の別のバージョン...?

4

2 に答える 2

10

どうしてそんなことが起こったのだろうと思いますが、ウェブで何も見つかりませんでした。

これは、ジェネリックがほとんどコンパイル時のみの機能であるために発生します。メタデータは、クラスの型パラメーター、フィールドなどに関して維持されますが、実行時に型引数は (ほとんど) 失われます。例えば:

Object x = new ArrayList<String>();
Object y = new ArrayList<Integer>();
System.out.println(x.getClass() == y.getClass()); // True

JVM は違いを見分けることができません。そのため、キャストしようとすると警告が表示されます。

// At execution time, this cast will *really* only check for List
List<String> dodgyCast = (List<String>) y;

ほとんどの場合、コンパイラはジェネリックを使用する「通常の」コードを安全に保ちます。しかし、リフレクションや動的バイトコードを介して値を提供する ORM のようなものがある場合、その安全性はすべて窓の外に出てしまいます。

于 2013-01-16T16:44:30.643 に答える
5

悲しいことに、そのようなことは型消去のために発生する可能性があります。コレクションに設定した型は、実行時ではなくコンパイル時にのみチェックされます。

問題は、クエリがコンパイルされていないため、Java が返すオブジェクトの種類を知る方法がないことです。この種の動作を避けるために、私は常にクエリのテストを作成しています。

于 2013-01-16T16:51:05.993 に答える