連載
» 2011年10月05日 00時00分 公開

EclipseベースIDEでSpring MVC開発ができRoo!Rooでアプリ開発をRapidしようぜ!(2)(2/3 ページ)

[中村修太,クラスメソッド株式会社]

HibernateとHSQLDBのJPAプロバイダ設定

 次に、JPAプロバイダを設定します。以前と同じように、以下のように入力します。

bash
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のリファレンスを参照してみてください。

bash
  roo> help persistence setu

生成された設定ファイルを確認

 生成されたファイルを確認してみましょう、

  • database.properties

     設定したデータベースのユーザー名やパスワードなどの情報が記述してあります。「persisitence setup」コマンド実行時にそれらを指定していれば、特に編集する必要はありません。

  • persistence.xml

     JPA(今回はHibernate)の設定情報が記述してあります。このファイルも今は編集する必要はありません。

     また、「applicationContext.xml」ファイルもDataSourceやTransactionManagerの設定が追加されています。

2つのコマンドでJPAのエンティティクラスを作成

 次にエンティティクラスを作成します。以下のようにRoo Shellで入力してください。

bash
 roo> entity --class ~.domain.Topping --testAutomatically

 エンティティクラスの、そのテストクラスが生成されました。

テストクラスが生成された画面

「entity」コマンド

 「entity」コマンドはJPAのエンティティクラスを作成します。

 「class」オプションはパッケージ名を含むクラス名を指定します。最低限これさえ指定していれば実行可能です。「testAutomatically」オプションはエンティティのテストクラスを生成するためのオプションです。

 これ以外にも、スーパークラスを指定するextendsオプションやJPAのバージョンフィールドを付加するversionFieldオプションなど、多数のオプションが指定できます。すべてのオプションを確認するには、以下のようにしてヘルプを確認するか、リファレンスページを確認してください。

bash
 roo> help entity

rooは、実行されたコマンドによって対象のクラスをデフォルトで指定してくれる

 entityコマンド実行後、rooプロンプトの表示が、「 roo>」から「~.domain.Topping roo>」に変わったのに気づきましたか?

 rooは、どんなコマンドが実行されたのかを判断し、対象のクラスをデフォルトで指定してくれます。この場合、rooコマンド操作の対象は「~.domain.Topping」と解釈されます。もし自分で対象クラスを指定したい場合、以下のようにすれば、対象となるクラスを選択できます。

bash
roo>focus --class {指定したいクラス名}

「field」コマンド

 続けてToppingエンティティにフィールドを追加します。

bash
~.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」を確認してください。

bash
 roo> help field string

 最大文字数や正規表現での制限を付加することも可能になっています。

生成されたJavaファイルとAspectJのを確認

 生成されたファイルを確認してみましょう。entityコマンドによってJavaファイルとAspectJのファイルが生成されています。AspectJについてはここでは説明しませんので、記事「アスペクト指向の基礎とさまざまな実装」などをご覧ください。

 まずは「Topping.java」ファイルを見てみましょう。

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ファイルを見て「inter-type declaration」を知る

 どのような機能が追加されているのか、AspectJファイル(.aj)を順番に見ていきましょう。[パッケージエクスプローラ]の[▽>Filters...]を選択し、[Hide generated Spring Roo ITDs]のチェックを外せば、.ajファイルが見られるようになります。

[Hide generated Spring Roo ITDs]のチェックを外す

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されます。

Topping_Roo_Entity.aj
    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で実行していってください。

bash
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になっているのを確認してから実行してください。

bash
~.domain.Pizza roo> field set --fieldName toppings --type ~.domain.Topping

 「field set」コマンドはSetフィールドを追加するコマンドです。「fieldName」オプションで対象エンティティのプロパティを指定し、「type」オブションでその型を指定します。

「field reference」コマンド

 Baseエンティティに対しても関連を定義します。Baseに対しては「filed reference」コマンドを使用しています。

bash
~.domain.Pizza roo> field reference --fieldName base --type ~.domain.Base

 これも「fieldName」オプションで対象エンティティのプロパティを指定し、「type」オブションでその型を指定します。Pizza(多対1関連で多側)から見たフィールドを追加します。

Javaファイルを確認

 「Pizza.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.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。