セットアップ
チュートリアルのプロジェクトをダウンロードし、環境を整えます。 JavaやEclipseのインストールがまだ完了していない場合は、先にそれらのセットアップを済ませてください。
JDKのインストール
バージョン6以上のJDKをインストールします。 JREではなくJDKが必要であることに注意してください。 JDK 6 は以下のURLのサイトからダウンロードできます。
http://www.oracle.com/technetwork/java/javase/downloads/index.html
Eclipseのインストール
バージョン3.5以上のEclipseをインストールします。 Pluggable Annotation Processing API をサポートしていれば、Eclipse以外のIDEであってもかまいませんが、 このドキュメントではEclipseを使うことを前提に説明を進めます。 Eclipseは以下のURLのサイトからダウンロードできます。
http://www.eclipse.org/downloads/
Eclipseは、バージョン6以上のJDKに含まれるJREで起動されるようにしてください。 明示的にJREを指定するには、-vm オプションを使用します。
-vm %JAVA_HOME%\bin\javaw.exe
プロジェクトのインポート
ダウンロードのページからdoma-tutorial-x.x.x.zipをダウンロードし、 Eclipseへインポートしてください。インポートの具体的な手順は次のとおりです。2つの方法を説明します。
通常の方法
- Eclipseのメニューから「File」 - 「Import」を選択します。
- 「Existing Projects to Workspace」を選択し、「Next」ボタンを押します。
- 「Select archive file」のラジオボタンをチェックし、ダウンロードしたdoma-tutorial-x.x.x.zipを選択します。
- 「Projects」の項目に表示される「doma-tutorial」のチェックボックスをチェックし、「Finish」ボタンを押します。
インポートが完了したら、doma-tutorialプロジェクトを右クリックし、コンテキストメニューから「Run As」 - 「JUnit Test」 を実行してください。 すべてのテストが成功したらセットアップが正しく完了しています。
m2eclipseを使ってMaven Projectとしてインポートする方法
- doma-tutorial-x.x.x.zipを解凍します。
- Eclipseのメニューから「File」 - 「Import」を選択します。
- 「Existing Maven Projects」を選択し、「Next」ボタンを押します。
- Root Directoryの入力欄にdoma-tutorial-x.x.x.zipを解凍したディレクトリを指定します。
- 「Projects」の項目に表示されるpom.xmlのチェックボックスをチェックし、「Finish」ボタンを押します。
- インポートが完了した時点ではビルドエラーが発生します。
- エラーを解消するために、プロジェクトのプロパティからJavaのビルドパスのダイアログを開きます。
- Javaのビルドパスのダイアログでは、src/main/resourcesとsrc/test/resourcesのソースフォルダの「Exclude:**/*」となっている項目を選択して「Remove」を押します(「Exclude:(None)」に変わります)。
- また、同じJavaのビルドパスのダイアログで「Add Folder...」を押し、プロジェクト直下の.apt_generatedをソースフォルダとして登録します。
以上の手順を実行し終えるとビルドエラーは解消されます。 最後に、doma-tutorialプロジェクトを右クリックし、コンテキストメニューから「Run As」 - 「JUnit Test」 を実行してください。 すべてのテストが成功したらセットアップが正しく完了しています。
チュートリアルの構成
チュートリアルの構成を説明します。
フォルダ構成
プロジェクトのフォルダ構成は以下の通りです。主要なものを中心に説明します。
フォルダ | 説明 |
---|---|
src/main/java | 設定クラス、Daoインタフェース、エンティティクラス等のソースフォルダです。 |
src/main/resources | SQLファイル等のソースフォルダです。 SQLファイルは、Domaの規約に則ってMETA-INFフォルダ以下に配置されます。 また、JDBCドライバのプロバイダ構成ファイルがMETA-INF/servicesフォルダ以下にjava.sql.Driverという名前で配置されます。 |
src/test/java | Daoを利用するコードのためのソースフォルダです。 Daoを利用するコードはすべてJUnitのテストクラスとして記述されています。 |
src/test/resources | 使用していません。 |
.apt_generated | apt(Annotation Processing Tool)によって生成されたコードを格納するソースフォルダです。 Package Explorerビューでは、フィルタリングされるため表示されません(フィルタリングは解除可能です)。 Nivigatorビューで確認できます。 |
lib | このチュートリアルで利用するjarファイルを格納するフォルダです。 JUnit、H2、Domaのjarが格納されます。 これらのjarはすべてビルドパスに通っていなければいけません。 |
libsrc | このチュートリアルで利用するjarファイルのソースコードを格納するフォルダです。 |
プロジェクト直下には次のファイルがあります。主要なものを説明します。
ファイル | 説明 |
---|---|
build.xml | チュートリアルプロジェクトをAntでビルドするためのビルドファイルです。 詳しくは、Antによるビルドを参照してください。 |
pom.xml | チュートリアルプロジェクトをMavenでビルドするためのプロジェクト記述ファイルです。 詳しくは、Mavenによるビルドを参照してください。 |
データベース
このチュートリアルでは、データベースにH2 Database Engineを利用します。
使用するスキーマの定義は次のとおりです。 1つのシーケンスと2つのテーブルを使用します。
create sequence employee_seq start with 100 increment by 1;
create table employee ( id integer not null primary key, name varchar(255) not null, age integer not null, salary integer, job_type varchar(20), hiredate timestamp, department_id integer, version integer not null, insertTimestamp timestamp, updateTimestamp timestamp );
create table department ( id integer not null primary key, name varchar(255) not null, version integer not null );
H2はin-memoryモードで起動し、テスト用のスキーマとデータは各テストの実行前に作成し、テスト終了後に破棄します。 スキーマとデータの作成と破棄は、共通のテストクラスで行っています。 Javaのコードは、src/test/java/tutorial/TutorialTestCase.javaになります。
JDBCドライバのプロバイダ構成ファイル
H2のJDBCドライバを登録するためのプロバイダ構成ファイルがsrc/main/resources/META-INF/servicesに必要です。 ファイルの名称はjava.sql.Driverで、中身は次のように記述されます。
org.h2.Driver
プロバイダ構成ファイルの詳細については、JAR ファイルの仕様 を参照してください。
主要なクラス
チュートリアル中の主要なクラスについて説明します。
設定クラス
設定クラスとは、Domaに関する各種設定を持つクラスです。 このチュートリアルで使用する設定クラスのソースコードは、src/main/java/tutorial/AppConfig.javaになります。
このクラスでは、H2のデータソースの作成とH2の方言の設定を行っています。 それ以外の設定については親クラスのDomaAbstractConfigのものを利用しています。 設定クラスはDaoインタフェースから利用されます。
public class AppConfig extends DomaAbstractConfig { protected static final LocalTransactionalDataSource dataSource = createDataSource(); protected static final Dialect dialect = new H2Dialect(); @Override public DataSource getDataSource() { return dataSource; } @Override public Dialect getDialect() { return dialect; } protected static LocalTransactionalDataSource createDataSource() { SimpleDataSource dataSource = new SimpleDataSource(); dataSource.setUrl("jdbc:h2:mem:tutorial;DB_CLOSE_DELAY=-1"); dataSource.setUser("sa"); return new LocalTransactionalDataSource(dataSource); } public static LocalTransaction getLocalTransaction() { return dataSource.getLocalTransaction(defaultJdbcLogger); } }
エンティティクラス
エンティティクラスとは、テーブルやSQLの結果セットにマッピングされたクラスです。 エンティティクラスは、@Entityを注釈して示します。 このチュートリアルで使用するエンティティクラスのソースコードは、 src/main/java/tutorial/entity/Employee.java と src/main/java/tutorial/entity/EmployeeDepartment.java になります。
Employeeクラスは、EMPLOYEEテーブルに対応します。
識別子(テーブルの主キー)には@Idを注釈します。 識別子を自動生成する場合は、さらに@GeneratedValueを注釈し、自動生成の方法を示します。 ここではEMPLOYEE_SEQシーケンスを使って採番することを示しています。
プロパティ名がマッピングするカラム名と異なる場合は@Columnのname要素を使って示します。
更新や削除時の楽観的排他制御に使用するカラムとマッピングされたプロパティには@Versionを注釈します。
@Entityのlistener要素にはEmployeeListenerクラスを指定しています。
@Entity(listener = EmployeeListener.class) public class Employee { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE) @SequenceGenerator(sequence = "EMPLOYEE_SEQ") Integer id; String name; int age; Salary salary; @Column(name = "JOB_TYPE") JobType jobType; Date hiredate; @Column(name = "DEPARTMENT_ID") Integer departmentId; @Version @Column(name = "VERSION") Integer version; Timestamp insertTimestamp; Timestamp updateTimestamp; @OriginalStates Employee originalStates; ... }
EmployeeDepartmentクラスは、EMPLOYEEテーブルとDEPARTMENTテーブルを結合した結果セットに対応します。
このクラスは、Employeeクラスを継承し、DEPARTMENTテーブルのNAMEカラムに対応するプロパティを持ちます。 @Columnのname要素に指定されている「DEPARTMENT_NAME」はSQL上でDEPARTMENTテーブルのNAMEカラムの別名になります。
@Entity public class EmployeeDepartment extends Employee { @Column(name = "DEPARTMENT_NAME") String departmentName; ... }
エンティティリスナークラス
エンティティリスナークラスのインスタンスは、エンティティがデータベースに挿入、更新、削除される前後に呼び出されます。 このチュートリアルで使用するエンティティリスナークラスはEmployeeListenerです。 ソースコードは、src/main/java/tutorial/entity/EmployeeListener.javaになります。
public class EmployeeListener implements EntityListener<Employee> { @Override public void preDelete(Employee employee, PreDeleteContext context) { } @Override public void preInsert(Employee employee, PreInsertContext context) { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); employee.setInsertTimestamp(timestamp); } @Override public void preUpdate(Employee employee, PreUpdateContext context) { if (context.isEntityChanged()) { Timestamp timestamp = new Timestamp(System.currentTimeMillis()); employee.setUpdateTimestamp(timestamp); } } @Override public void postInsert(Employee entity, PostInsertContext context) { } @Override public void postUpdate(Employee entity, PostUpdateContext context) { } @Override public void postDelete(Employee entity, PostDeleteContext context) { } }
ドメインクラス
ドメインクラスは、データベースのカラムにマッピング可能なアプリケーション固有の値型です。 ドメインクラスは@Domainを注釈して示します。 このチュートリアルで使用するドメインクラスは、給料を表すSalaryクラスです。 ソースコードは、src/main/java/tutorial/domain/Salary.javaになります。
@Domain(valueType = Integer.class) public class Salary { private final Integer value; public Salary(Integer value) { this.value = value; } public Integer getValue() { return value; } public Salary add(Salary salary) { if (salary == null) { throw new NullPointerException("The salary parameter is null."); } if (this.value == null || salary.value == null) { return new Salary(null); } return new Salary(this.value + salary.value); } ... }
Daoインタフェース
Daoインタフェースとは、データベースアクセスの境界となるインタフェースです。 Daoインタフェースは@Daoを注釈して示します。 @Daoのconfig要素には設定クラスであるAppConfigクラスを指定します。 このチュートリアルで使用するDaoインタフェースのソースコードは、src/main/java/tutorial/dao/EmployeeDao.javaになります。
Daoインタフェースの実装クラスはDomaにより自動生成されます。
すべてのメソッドは、@Selectや@Updateなど問い合わせの種別を示すアノテーションが注釈されなければいけません。
@Dao(config = AppConfig.class) public interface EmployeeDao { @Select Employee selectById(Integer id); @Select List<Employee> selectByAgeRange(Integer min, Integer max); @Select List<Employee> selectByAges(List<Integer> ages); @Select List<Employee> selectByNames(List<String> names); ... @Insert int insert(Employee employee); @Insert(sqlFile = true) int insertWithSqlFile(Employee employee); @Update int update(Employee employee); @Update(sqlFile = true) int updateWithSqlFile(Employee employee); @Delete int delete(Employee employee); @Delete(sqlFile = true) int deleteWithSqlFile(Employee employee); ... }
SQLファイル
SQLファイルは、src/main/resources/META-INF/tutorial/EmployeeDaoフォルダ以下に配置されます。 フォルダの名前はDaoインタフェースと対応づけられます。
SQLファイルは、名前から拡張子を除いたものがDaoインタフェースのメソッドに一致します。 たとえば、selectById.sqlはDaoインタフェースのselectByIdメソッドに対応します。 selectById.sqlの中身は次のようなテキストです。
select * from employee where id = /* id */0