読者です 読者をやめる 読者になる 読者になる

ひだまりソケットは壊れない

ソフトウェア開発に関する話を書きます。 最近は主に Android アプリ、Windows アプリ (UWP アプリ)、Java 関係です。

まじめなことを書くつもりでやっています。 適当なことは 「一角獣は夜に啼く」 に書いています。

JPA 2 の Entity クラスをかたどるための Metamodel API (Java EE 7)

Java Java EE

最近 Java Persistence API (JPA) を使ってみてます。 まだ使いこなせてはないですがなかなかいいですね。 今まで触ったことのある O/R マッパー *1 の設計が嫌いだったので O/R マッパーにはあんまりいい印象持ってなかったんですが、JPA の設計はよく考えられてて良いと思いました。 Java Persistence criteria query が SQL を意識したものになっているのも良い感じです。

JPA のエンティティクラスに対するメタモデル

Metamodel API というのがあることをさっき知ったのでメモ書きしておきます。 JSR-338 (JPA 2.1) には、メタモデルについて次のように書かれていました。

6.2 Metamodel

Java Persistence criteria queries are based on a metamodel of the managed classes of the persistence unit. Static metamodel classes corresponding to the managed classes of the persistence unit can be generated by means of an annotation processor or can be created by the application developer, or the metamodel can be accessed dynamically by use of the javax.persistence.metamodel.Metamodel interface. The getMetamodel method of the EntityManagerFactory or EntityManager interface can be used to obtain a Metamodel instance.

6.2.1 Static Metamodel Classes

In the typical case, an annotation processor is expected to be used to produce static metamodel classes corresponding to the entities, mapped superclasses, and embeddable classes in the persistence unit. A static metamodel class models the persistent state and relationships of the corresponding managed class. For portability, an annotation processor should generate a canonical metamodel as defined below.

JSR-000338 Java Persistence 2.1 - Final Release

Java Persistence criteria query は persistence unit 中の managed class のメタモデルを使うようになっているわけですね。 で、アノテーションプロセッサによって静的なメタモデルクラスを生成することもできるし、プログラムの実行中に動的にメタモデルを取得することもできるとのこと。 そして、静的なメタモデルクラスを使用することで、強く型付けされたクエリを記述することができます

静的なメタモデルクラス

上のページに書かれているサンプルコードそのままですが、次のようなエンティティクラスを考えます。

package com.example;
...
@Entity
public class Pet {
  @Id
  protected Long id;
  protected String name;
  protected String color;
  @ManyToOne
  protected Set<Person> owners;
  ...
}

このエンティティクラスに対応するメタモデルクラスは次のようになります。

package com.example;
...
@Static Metamodel(Pet.class)
public class Pet_ {
  public static volatile SingularAttribute<Pet, Long> id;
  public static volatile SingularAttribute<Pet, String> name;
  public static volatile SingularAttribute<Pet, String> color;
  public static volatile SetAttribute<Pet, Person> owners;
}

メタモデルクラスを移植可能なものにするため、JPA では canonical metamodel が定義されています。 (Canonical metamodel の条件にあうクラスは、別の JPA 実装でもサポートされることが保証されるという感じ、だと思う。)

Eclipse における静的なメタモデルの生成

Eclipse IDE for Java EE Developers を使っている場合、プロジェクトのプロパティを変更することで canonical metamodel を自動生成させることができます。 プロジェクトの Facets に JPA を追加している状態だと、プロジェクトのプロパティに 「JPA」 が表示されているはずです。

f:id:nobuoka:20131120030237p:plain

下の方に 「Canonical metamodel」 ってのがあるので、そこで出力先 (?) ソースフォルダを選択すれば静的なメタモデルクラスが生成されるようになります。

Gradle 使用

Gradle を使ってビルドする場合は、次の記事を参考に Annotation Processing させれば良さそうです。

*1:RoR の ActiveRecord など、主に Active Record パターンのもの。 JPA は Data Mapper パターン。