概要
Genタスクは、データベースに接続してメタデータを読み取り、その情報を基にエンティティクラス、エンティティリスナークラス、Daoインタフェース、SQLのコードを生成します。
Genタスクを利用するには、次のようにtaskdefタグとtypedefタグを使ってタスクとデータ型を定義する必要があります。
<taskdef name="gen" classname="org.seasar.doma.extension.gen.task.Gen" classpathref="classpath" loaderref="loader"/> <typedef name="entityConfig" classname="org.seasar.doma.extension.gen.task.EntityConfig" loaderref="loader"/> <typedef name="daoConfig" classname="org.seasar.doma.extension.gen.task.DaoConfig" loaderref="loader"/> <typedef name="sqlConfig" classname="org.seasar.doma.extension.gen.task.SqlConfig" loaderref="loader"/>
taskdefのclasspathref属性には、Doma-Gen、FreeMarker、JDBCドライバのjarファイルが参照されるように設定してください(Doma本体のjarファイルは不要です)。
定義したタスクとデータ型は次のように使用します。
<target name="gen">
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}">
<entityConfig
destdir="${javaDestDir}"
packageName="${entityPackageName}"
/>
<daoConfig
destdir="${javaDestDir}"
packageName="${daoPackageName}"
configClassName="${configClassName}"
/>
<sqlConfig
destdir="${sqlDestDir}"
/>
</gen>
</target>
生成されるコードは次のようになります。
エンティティクラスです。
@Entity(listener = AddressListener.class)
@Table(name = "ADDRESS")
public class Address {
@Id
@Column(name = "ADDRESS_ID")
Integer addressId;
@Column(name = "STREET")
String street;
@Version
@Column(name = "VERSION")
Integer version;
...
}
エンティティリスナークラスです。
public class AddressListener implements EntityListener<Address> {
@Override
public void preInsert(Address entity, PreInsertContext<Address> context) {
}
@Override
public void preUpdate(Address entity, PreUpdateContext<Address> context) {
}
@Override
public void preDelete(Address entity, PreDeleteContext<Address> context) {
}
@Override
public void postInsert(Address entity, PostInsertContext<Address> context) {
}
@Override
public void postUpdate(Address entity, PostUpdateContext<Address> context) {
}
@Override
public void postDelete(Address entity, PostDeleteContext<Address> context) {
}
}
Daoインタフェースです。
@Dao(config = AppConfig.class)
public interface AddressDao {
@Select
Address selectById(Integer addressId);
@Select(ensureResult = true)
Address selectByIdAndVersion(Integer addressId, Integer version);
@Insert
int insert(Address entity);
@Update
int update(Address entity);
@Delete
int delete(Address entity);
}
Daoデリゲートクラスです。
public class AddressDaoDelegate {
private final Config config;
private final AddressDao dao;
public AddressDaoDelegate(Config config, AddressDao dao) {
if (config == null) {
throw new NullPointerException("config");
}
if (dao == null) {
throw new NullPointerException("dao");
}
this.config = config;
this.dao = dao;
}
public int insert(Address entity) {
return -1;
}
public int update(Address entity) {
return -1;
}
public int delete(Address entity) {
return -1;
}
}
識別子を条件として検索するSQLです。
select
ADDRESS_ID,
STREET,
VERSION
from
ADDRESS
where
ADDRESS_ID = /* addressId */1
識別子とバージョンを条件として検索するSQLです。
select
ADDRESS_ID,
STREET,
VERSION
from
ADDRESS
where
ADDRESS_ID = /* addressId */1
and
VERSION = /* version */1
パラメータ
トップレベルパラメータ
トップレベルパラメータの定義は次の通りです。
| 属性 | 説明 | デフォルト値 | 必須 |
|---|---|---|---|
| dialectName | 接続するRDBMSの方言名です。次のうちのどれかを指定できます。"h2"、"hsqldb"、"mysql"、"postgres"、"oracle"、"db2"、"mssql2008"、"mssql"。この名前に対応するクラスは、Genタスクを実行するクラスパスに通されている必要があります。 | - | genDialectClassNameが指定されていない場合YES |
| genDialectClassName | 接続するRDBMSの方言クラス名です。org.seasar.doma.extension.gen.dialect.GenDialectの実装クラスでなければいけません。dialectNameの指定により利用できる組み込みの方言クラス以外を利用する場合に指定します。指定するクラスは、Genタスクを実行するクラスパスに通されている必要があります。 |
- | dialectNameが指定されていない場合YES |
| driverClassName | JDBCドライバクラス名です。java.sql.Driverの実装クラスでなければいけません。 |
- | YES |
| url | JDBC接続URLです。 | - | YES |
| user | JDBC接続ユーザーです。 | - | YES |
| password | JDBC接続パスワードです。 | - | YES |
| schemaName | 対象とするテーブルが所属するスキーマ名です。指定しない場合、JDBC接続ユーザーでアクセス可能な全スキーマが対象になります。 | - | NO |
| tableNamePattern | 対象とするテーブル名の正規表現です。大文字小文字の違いは考慮されません。 | ".*" | NO |
| ignoredTableNamePattern | 対象としないテーブル名の正規表現です。大文字小文字の違いは考慮されません。 | ".*\$.*" | NO |
| tableTypes | 対象とするテーブルの型です。複数の値を空白またはカンマで区切って指定できます。たとえば、テーブルに加えビューを対象にしたい場合、"TABLE, VIEW"と指定します。この値は、java.sql.DatabaseMetaDataクラスのgetTablesメソッドの最後のパラメータに渡されます。 | "TABLE" | NO |
| versionColumnNamePattern | エンティティのプロパティに@Versionを付与するカラム名の正規表現です。大文字小文字の違いは考慮されません。 | "VERSION([_]?NO)?" | NO |
| templateEncoding | テンプレートファイルのエンコーディングです。 | "UTF-8" | NO |
| templatePrimaryDir | テンプレートファイルを検索する際の優先ディレクトリです。独自テンプレートファイルを使用する場合に指定します。 | - | NO |
| globalFactoryClassName | このタスクで使用されるインスタンスを生成するファクトリの完全修飾名です。org.seasar.doma.extension.gen.GlobalFactoryの実装クラスでなければいけません。このタスクの振る舞いをカスタマイズする場合に指定します。 |
"org.seasar.doma.extension.gen.GlobalFactory" | NO |
ネストした要素として指定されるパラメータ
EntityConfig
エンティティクラスの生成に関する設定を表すデータ型です。
このデータ型を使用するとエンティティクラスとエンティティリスナークラスを生成できます。エンティティクラスとエンティティリスナーは同じパッケージに生成されます。
EntityConfigのパラメータ定義は次のとおりです。
| 属性 | 説明 | デフォルト値 | 必須 |
|---|---|---|---|
| generate | "true"の場合、エンティティクラスとエンティティリスナーのJavaコードを生成します。 | "true" | NO |
| destDir | Javaファイルの出力先ディレクトリです。 | "src" | NO |
| encoding | Javaファイルのエンコーディングです。 | "UTF-8" | NO |
| overwrite | "true"の場合、エンティティクラスのJavaコードを上書きします。 | "true" | NO |
| overwriteListener | "true"の場合、エンティティリスナークラスのJavaコードを上書きします。 | "false" | NO |
| packageName | エンティティクラスのパッケージ名です。 | "example.entity" | NO |
| superclassName | エンティティクラスのスーパークラスの完全修飾名です。生成されるエンティティクラスはここに指定したスーパークラスを継承します。指定するクラスは、Genタスクを実行するクラスパスに通されている必要があります。 | - | NO |
| listenerSuperclassName | エンティティリスナーのスーパークラスの完全修飾名です。生成されるエンティティリスナークラスはここに指定したスーパークラスを継承します。ここに指定するクラスは1つの型パラメータを受け取ります。 | - | NO |
| namingType | ネーミング規約です。"none"、 "snake_upper_case"、 "snake_lower_case"、"upper_case"、"lower_case"のいずれかの値を指定できます。@Entityのnaming要素に使用されます。 | - | NO |
| entityPropertyClassNamesFile | エンティティプロパティのクラス名を解決するためのファイルです。形式は、キーをエンティティプロパティ名の正規表現、値をクラスの完全修飾名とするプロパティファイル形式です。 | - | NO |
| generationType | 識別子を生成する方法です。"identity"、 "sequence"、 "table"のいずれかの値を指定できます。使用するRDBMSがサポートしていない場合、"identity"や"sequence"を指定するとエラーが発生します。この指定は、エンティティに対応するテーブルが単一の主キーを持つ場合にのみ有効です。複数の主キーがある場合、この指定は無視されます。@GeneratedValueのstrategy要素に使用されます。 | - | NO |
| initialValue | 識別子の初期値です。generationTypeに"sequence"もしくは"table"を指定した場合にのみ有効です。@SequenceGeneratorや@TableGeneratorのinitialValue要素に指定されます。 | - | NO |
| allocationSize | 識別子の割り当てサイズです。generationTypeに"sequence"もしくは"table"を指定した場合にのみ有効です。@SequenceGeneratorや@TableGeneratorのallocationSize要素に指定されます。 | - | NO |
| useAccessor | "true"の場合、エンティティクラスにアクセサメソッドを付与します。"false"の場合、エンティティのプロパティはpublicフィールドになります。 | "true" | NO |
| useListener | "true"の場合、エンティティリスナークラスのJavaコードを生成し、@Entityのlistener要素にエンティティリスナークラスを指定します。"false"の場合、エンティティリスナークラスのJavaコードは生成されません。 | "true" | NO |
| useUtilDate | "true"の場合、エンティティクラスのプロパティの日付、時刻、タイムスタンプ型にjava.util.Dateを使用します。"false"の場合、日付、時刻、タイムスタンプ型にjava.sql.Date、java.sql.Time、java.sql.Timestampを使用します。 | "false" | NO |
| showDbComment | "true"の場合、データベースに対するコメントをエンティティのJavadocコメントに適用します。テーブルへのコメントはクラスのJavadocコメントに反映され、カラムへのコメントはプロパティのJavadocコメントに反映されます。 | "true" | NO |
| showCatalogName | "true"の場合、@Tableのcatalog属性にカタログ名を明記します。 | "false" | NO |
| showSchemaName | "true"の場合、@Tableのschema属性にスキーマ名を明記します。 | "false" | NO |
| showTableName | "true"の場合、@Tableのname属性にテーブル名を明記します。 | "true" | NO |
| showColumnName | "true"の場合、@Columnのname属性にカラム名を明記します。 | "true" | NO |
| originalStatesPropertyName | ここに指定した名前のプロパティに、@OriginalStatesを注釈します。テーブルのカラムから作られる永続的なプロパティと名前が重複しないように注意してください。指定しない場合、@OriginalStatesは使用されません。 | - | NO |
DaoConfig
Daoインタフェースの生成に関する設定を表すデータ型です。
このデータ型を使用するとエンティティごとに1つのDaoインタフェースとDaoデリゲートクラスを生成できます。
DaoConfigのパラメータ定義は次のとおりです。
| 属性 | 説明 | デフォルト値 | 必須 |
|---|---|---|---|
| overwrite | "true"の場合、DaoインタフェースのJavaコードを上書きします。 | "false" | NO |
| overwriteDelegate | "true"の場合、DaoデリゲートクラスのJavaコードを上書きします。 | "false" | NO |
| destDir | Javaファイルの出力先ディレクトリです。 | "src" | NO |
| encoding | Javaファイルのエンコーディングです。 | "UTF-8" | NO |
| generate | "true"の場合、DaoインタフェースのJavaコードを生成します。 | "true" | NO |
| packageName | Daoインタフェースのパッケージ名です。 | "example.dao" | NO |
| suffix | Daoインタフェース名のサフィックスです。Daoインタフェースの名前はエンティティクラス名に、この値をサフィックスしたものになります。 | "Dao" | NO |
| configClassName | 設定クラスの完全修飾名です。@Daoのconfig要素に使用されます。 | - | NO |
| useDelegate | "true"の場合、DaoデリゲートクラスのJavaコードを生成します。"false"の場合、生成しません。 | "false" | NO |
SqlConfig
SQLファイルの生成に関する設定を表すデータ型です。
このデータ型を使用するとエンティティごとにデフォルトで2つのSQLファイルを生成できます。 生成されるSQLは次のものです。
- 条件に識別子を指定して検索するSQL
- 条件に識別子とバージョンを指定して検索するSQL
ただし、エンティティが識別子を持たない場合、SQLファイルは生成されません。 また、エンティティがバージョンを持たない場合は、条件にバージョンを指定するSQLは生成されません。
テンプレートを用意することで、独自のSQLファイルを生成できます。詳細は、独自のSQLファイルを生成するを参照してください。
SqlConfigのパラメータ定義は次のとおりです。
| 属性 | 説明 | デフォルト値 | 必須 |
|---|---|---|---|
| generate | "true"の場合、SQLファイルを生成します。 | "true" | NO |
| destDir | SQLファイルの出力先ディレクトリです。ファイルは、ファイル名の形式に則って出力されます。ここに指定したディレクトリを基点にMETA-INF以下のディレクトリが作成されます。 | src | NO |
| overwrite | "true"の場合、SQLファイルを上書きします。 | "true" | NO |
使用例
エンティティクラスに共通のスーパークラスを指定する
EntityConfigのsuperclassName属性に、エンティティクラスに共通のスーパークラスの名前を指定できます。 たとえば、エンティティに対応するすべてのテーブルにCREATE_TIMESTAMPとUPDATE_TIMESTAMPというカラムが定義されている場合、 次のようなクラスを作成し、すべてのエンティティのスーパークラスに指定できます。
@Entity
public abstract class Common {
Date createTimestamp;
Date updateTimestamp;
...
}
スーパークラス名をsuperclassName属性に指定します。
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}">
<entityConfig
superclassName="example.Common"
...
/>
<gen/>
タスクを実行するとexample.Commonを継承した次のようなクラスが生成されます。
@Entity
public class Employee extends Common {
@Id
Integer id;
String name;
...
}
エンティティリスナーに共通のスーパークラスを指定する
EntityConfigのlistenerSuperclassName属性に、エンティティリスナーに共通のスーパークラスの名前を指定できます。 通常、EntityConfigのsuperclassName属性と合わせて使用します。 たとえば、次のようにエンティティクラスに共通のスーパークラスとそのクラスを型パラメータとして受け取るエンティティリスナーの2つを用意します。
@Entity
public abstract class Common {
Date createTimestamp;
Date updateTimestamp;
...
}
public class CommonListener<T extends Common> implements EntityListener<T> {
public void preInsert(T entity, PreInsertContext<T> context) {...}
public void preUpdate(T entity, PreUpdateContext<T> context) {...}
public void preDelete(T entity, PreDeleteContext<T> context) {...}
public void postInsert(T entity, PostInsertContext<T> context) {...}
public void postUpdate(T entity, PostUpdateContext<T> context) {...}
public void postDelete(T entity, PostDeleteContext<T> context) {...}
}
これらのクラス名をsuperclassName属性とlistenerSuperclassName属性に指定します。
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}">
<entityConfig
superclassName="example.Common"
listenerSuperclassName="example.CommonListener"
...
/>
<gen/>
タスクを実行するとexample.CommonListenerを継承した次のようなクラスが生成されます。
public class EmployeeListener extends CommonListener<Employee> {
}
エンティティプロパティのクラス名を指定する
ドメインクラスを使用する場合など、特定のエンティティプロパティに対しクラス名を指定したいことがあります。
クラス名の指定は、プロパティファイルで行います。 キーは、エンティティプロパティの完全修飾名を正規表現で表したもの、値はマッピングしたいクラスの完全修飾名です。 エンティティプロパティの完全修飾名とは、「エンティティクラスの完全修飾名」と「エンティティプロパティ名」を「@」で連結したものです。 たとえば、EmployeeエンティティクラスのエンティティプロパティemployeeNameの完全修飾名は、「example.entity.Employee@employeeName」です。 Employeeエンティティクラスの中でエンティティプロパティ名が「Name」で終わるものを「example.domain.Name」クラスにマッピングさせるには、次のように記述します。
example.entity.Employee@.*Name$=example.domain.Name
プロパティ名の部分を正規表現で示しています。正規表現はプロパティ名に対してのみ使用できます(@より左のクラス名は必ず完全修飾名でなければいけません)。
生成されるエンティティクラスでは、次のようにemployeeNameプロパティの型が「example.domain.Name」になります。
import example.domain.Name;
@Entity
public class Employee extends Common {
@Id
Integer id;
Name employeeName;
...
}
Employeeエンティティクラスに限らず、すべてのエンティティクラスを対象にエンティティプロパティ名が「Name」で終わるものを「example.domain.Name」クラスにマッピングさせたい場合は次のように記述します。
.*Name$=example.domain.Name
プロパティファイルは、エンティティプロパティごとに上から順番に評価され、正規表現がマッチした時点で評価を終えます。 どの行にもマッチしない場合、クラス名はデフォルトのクラス名になります。
プロパティファイルはentityPropertyClassNamesFile属性に指定できます。(ここではプロパティファイルの名前をentityPropertyClassNames.propertiesとします。)
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}">
<entityConfig
entityPropertyClassNamesFile="entityPropertyClassNames.properties"
...
/>
<gen/>
独自のテンプレートファイルを使用する
Doma-Genのテンプレートは、配布ファイルのresources/templateディレクトリ以下にあります。 エンティティクラスのテンプレートはentity.ftl、エンティティリスナークラスのテンプレートはentityListener.ftl、Daoインタフェースのテンプレートはdao.ftl、DaoデリゲートクラスのテンプレートはdaoDelegate.ftlになります。 また、識別子を条件に検索するSQLのテンプレートはselectById.sql.ftl、識別子とバージョンを条件に検索するSQLのテンプレートはselectByIdAndVersion.sql.ftlです。 これをコピーして、修正を加えるのが良いでしょう。 テンプレートの記述方法についてはFreeMarkerのドキュメントを参照してください。
修正したテンプレートファイルは、ファイル名を変更せずにtemplateFilePrimaryDir属性に指定するディレクトリに配置します。 mytemplateディレクトリに配置する場合、templatePrimaryDir属性にmytemplateを指定します。
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}"
templatePrimaryDir="mytemplate">
<entityConfig
...
/>
<gen/>
それぞれのテンプレートは、特定のデータモデルを参照します。 テンプレートとデータモデルクラスの対応付けを以下に示します。
| テンプレート | データモデルクラス | 生成物 |
|---|---|---|
| entity.ftl | org.seasar.doma.extension.gen.EntityDesc | エンティティクラスのJavaファイル |
| entityListener.ftl | org.seasar.doma.extension.gen.EntityListenerDesc | エンティティリスナークラスのJavaファイル |
| dao.ftl | org.seasar.doma.extension.gen.DaoDesc | DaoインタフェースのJavaファイル |
| daoDelegate.ftl | org.seasar.doma.extension.gen.DaoDelegateDesc | DaoデリゲートクラスのJavaファイル |
| xxx.sql.ftl (xxxは任意の名称) | org.seasar.doma.extension.gen.SqlDesc | SQLファイル |
独自のSQLファイルを生成する
テンプレートを用意することで、独自のSQLファイルを生成できます。 テンプレートファイルの名前は、「生成したいsqlファイル名」 + 「.ftl」としてください。
たとえば、全件検索を行うSQLファイルselectAll.sqlを生成するには、selectAll.sql.ftlという名前のテンプレートファイルを作成します。 テンプレートファイルには、以下のように記述します。 (テンプレートはデータモデルとしてorg.seasar.doma.extension.gen.SqlDescのインスタンスを参照します。)
select
<#list entityDesc.entityPropertyDescs as property>
${property.columnName}<#if property_has_next>,</#if>
</#list>
from
${entityDesc.tableName}
selectAll.sql.ftlは、templateFilePrimaryDir属性に指定するディレクトリに配置します。 mytemplateディレクトリに配置する場合、templatePrimaryDir属性にmytemplateを指定します。
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}"
templatePrimaryDir="mytemplate">
<sqlConfig
...
/>
<gen/>
このように、独自のSQLファイルを生成する場合、SQLファイルに対応するDaoメソッドについても生成するとよいでしょう。 Daoメソッドを生成するには、Daoインタフェースのテンプレートであるdao.ftlを修正し、templateFilePrimaryDir属性に指定するディレクトリに配置します。
生成するJavaファイルに共通のヘッダーとしてコピーライトを含める
lib.ftlというファイルを作成し、これをtemplatePrimaryDir属性に指定するディレクトリに配置します。 lib.ftlには次のようにcopyrightの定義をします。
<#assign copyright> /* * Copyright 2008-2009 ... * All rights reserved. */ </#assign>
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}"
templatePrimaryDir="mytemplate">
<entityConfig
...
/>
<gen/>
生成するJavaファイルにauthorを指定する
lib.ftlというファイルを作成し、これをtemplatePrimaryDir属性に指定するディレクトリに配置します。 lib.ftlには次のようにauthorの定義をします。
<#assign author="Nakamura">
<gen
dialectName="${dialectName}"
driverClassName="${driverClassName}"
url="${url}"
user="${user}"
password="${password}"
templatePrimaryDir="mytemplate">
<entityConfig
...
/>
<gen/>
