次に、JPAプロバイダを設定します。以前と同じように、以下のように入力します。
roo> persistence setup --provider HIBERNATE --database HYPERSONIC_IN_MEMORY
プロバイダはHibernate、データベースはHSQLDBのインメモリDBを使用します。
新たにファイルが生成、更新されました。「persistence setup」コマンドは最初だけではなく、途中でも実行できます。
■JPAの設定は変更できる
最初はシンプルなインメモリDBで始め、ある程度できてきたら、MySQLやPostgreSQLに切り替えることも簡単にできます。providerやdatabaseは、いろいろな値が設定できますし、それ以外にもapplicationId(Google App Engineで使用)やJNDI datasource名を指定することもできます。
以下のコマンドでコンソール上で確認するか、Spring Rooのリファレンスを参照してみてください。
roo> help persistence setu
■生成された設定ファイルを確認
生成されたファイルを確認してみましょう、
次にエンティティクラスを作成します。以下のようにRoo Shellで入力してください。
roo> entity --class ~.domain.Topping --testAutomatically
エンティティクラスの、そのテストクラスが生成されました。
■「entity」コマンド
「entity」コマンドはJPAのエンティティクラスを作成します。
「class」オプションはパッケージ名を含むクラス名を指定します。最低限これさえ指定していれば実行可能です。「testAutomatically」オプションはエンティティのテストクラスを生成するためのオプションです。
これ以外にも、スーパークラスを指定するextendsオプションやJPAのバージョンフィールドを付加するversionFieldオプションなど、多数のオプションが指定できます。すべてのオプションを確認するには、以下のようにしてヘルプを確認するか、リファレンスページを確認してください。
roo> help entity
■rooは、実行されたコマンドによって対象のクラスをデフォルトで指定してくれる
entityコマンド実行後、rooプロンプトの表示が、「 roo>」から「~.domain.Topping roo>」に変わったのに気づきましたか?
rooは、どんなコマンドが実行されたのかを判断し、対象のクラスをデフォルトで指定してくれます。この場合、rooコマンド操作の対象は「~.domain.Topping」と解釈されます。もし自分で対象クラスを指定したい場合、以下のようにすれば、対象となるクラスを選択できます。
roo>focus --class {指定したいクラス名}
■「field」コマンド
続けてToppingエンティティにフィールドを追加します。
~.domain.Topping roo> field string --fieldName name --notNull --sizeMin 2
「field」コマンドでは対象のエンティティに対してフィールドを追加します。ここでは、「name」という名前のString型フィールドをToppingエンティティに追加しています。String以外にも数値やboolean、列挙型、参照型などさまざまな型が指定できます。
「field string」コマンドでは、さらに多数のオプションが使用可能です。「name」フィールドには、「notNull」オプションと「sizeMin」オプションが付けられています。notNullオプションは値にnullを許可しないオプションです。また、sizeMinオプションは最小文字数を指定するオプションで、ここでは最小文字数を2文字に制限しています。
こちらも、すべてのオプションを確認するには、以下のようにするか、「Appendix?A.?Command Index」を確認してください。
roo> help field string
最大文字数や正規表現での制限を付加することも可能になっています。
■生成されたJavaファイルとAspectJのを確認
生成されたファイルを確認してみましょう。entityコマンドによってJavaファイルとAspectJのファイルが生成されています。AspectJについてはここでは説明しませんので、記事「アスペクト指向の基礎とさまざまな実装」などをご覧ください。
まずは「Topping.java」ファイルを見てみましょう。
package jp.cm.pizzashop.domain; import org.springframework.roo.addon.entity.RooEntity; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.tostring.RooToString; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; @RooJavaBean @RooToString @RooEntity public class Topping { @NotNull @Size(min = 2) private String name; }
先ほど、「filed」コマンドで追加したプロパティ以外にはアノテーションが付いただけの非常にシンプルなクラスに見えますが、Rooの生成するエンティティはAspectJの「inter-type declaration」(ITD)と呼ばれる技術を使用しています。
ここでは、JavaのToppingクラスに対して、AspectJのファイルによってメンバやメソッドをクラスの外部から追加しています。
どのような機能が追加されているのか、AspectJファイル(.aj)を順番に見ていきましょう。[パッケージエクスプローラ]の[▽>Filters...]を選択し、[Hide generated Spring Roo ITDs]のチェックを外せば、.ajファイルが見られるようになります。
■Topping_Roo_Entity.aj
Toppingエンティティに対してJPAの操作(persist/remove/findなど)を定義しています。また、EntityManagerを取得するメソッドも定義しているので、自分でエンティティに対する操作もできます。
■Topping_Roo_JavaBean.aj
Toppingクラスに定義されたprivateフィールドに対してsetter/getterを定義しています。setter/getterの中で「this.name」としていますが、これはToppingクラスのnameフィールドのことです。
■Topping_Roo_Configurable.aj
ここでは「declare @type: Topping: @Configurable;」とだけ定義されています。これは、Toppingクラスに@Configurableアノテーションを付加するための記述です。@Configurableアノテーションを付加したクラスは、newでインスタンス化した際にもSpringのDI機能が適用されます。
Topping_Roo_Entity.ajに以下のようなメソッドが定義されていますが、@Configurableアノテーションによって、newでインスタンス化されたときにEntityManagerがDIされます。
public static final EntityManager Topping.entityManager() { EntityManager em = new Topping().entityManager; if (em == null) throw new IllegalStateException( "Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)"); return em; }
■Topping_Roo_ToString.aj
ToppingクラスのtoStringメソッドをオーバーライドしています。後でControllerとWebページを生成しますが、Webページでエンティティを表示している個所では、この「toString」が呼ばれます。
これらのajファイルがToppingクラスにコンパイル時に織り込まれ、必要な機能を持ったエンティティとして実行されます。一通り生成されたファイルの説明をしたので、ドメインモデルの通りに他のエンティティも作成していきましょう。下記コマンドを順番にRoo Shellで実行していってください。
roo> entity --class ~.domain.Base --testAutomatically ~.domain.Base roo > field string --fieldName name --notNull --sizeMin 2 ~.domain.Base roo > entity --class ~.domain.Pizza --testAutomatically ~.domain.Pizza roo > field string --fieldName name --notNull --sizeMin 2 ~.domain.Pizza roo > field number --fieldName price --type java.lang.Float
次に、エンティティ同士の関連を定義します。
■「field set」コマンド
まずは、PizzaエンティティとToppingエンティティの関連を定義します。これは1対多の関連になっているので、「field set」コマンドを使用します。対象クラスがPizzaになっているのを確認してから実行してください。
~.domain.Pizza roo> field set --fieldName toppings --type ~.domain.Topping
「field set」コマンドはSetフィールドを追加するコマンドです。「fieldName」オプションで対象エンティティのプロパティを指定し、「type」オブションでその型を指定します。
■「field reference」コマンド
Baseエンティティに対しても関連を定義します。Baseに対しては「filed reference」コマンドを使用しています。
~.domain.Pizza roo> field reference --fieldName base --type ~.domain.Base
これも「fieldName」オプションで対象エンティティのプロパティを指定し、「type」オブションでその型を指定します。Pizza(多対1関連で多側)から見たフィールドを追加します。
■Javaファイルを確認
「Pizza.java」ファイルを開いてみてください。
package jp.cm.pizzashop.domain; import org.springframework.roo.addon.entity.RooEntity; import org.springframework.roo.addon.javabean.RooJavaBean; import org.springframework.roo.addon.tostring.RooToString; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import java.util.Set; import jp.cm.pizzashop.domain.Topping; import java.util.HashSet; import javax.persistence.ManyToMany; import javax.persistence.CascadeType; import jp.cm.pizzashop.domain.Base; import javax.persistence.ManyToOne; @RooJavaBean @RooToString @RooEntity public class Pizza { @NotNull @Size(min = 2) private String name; private Float price; @ManyToMany(cascade = CascadeType.ALL) private Set toppings = new HashSet(); @ManyToOne private Base base; }
追加したフィールドがJPAの関連アノテーション付きでちゃんと定義されています。
Copyright © ITmedia, Inc. All Rights Reserved.