springbootでdoma-genを使う

## はじめに
springbootでSQLベース開発したいときはMyBatisと思ってたけど、domaの方が使いやすそう。
 javaとSQLの相互遷移とか。
 2waySQLとか。。
SQLコメントとか。。。
というわけで、今回はdoma-genを使ってDaoやentityを自動生成するところをゴールとして書いていきます。

## 開発環境
* java8
* STS 3.8.3.RELEASE
* springboot 1.5.2.RELEASE
* doma, doma-gen 2.12.0

## プロジェクトの設定
* STSからSpringStarterProjectでGradle(BuildShip)プロジェクト作成
 * Gradle(STS)は非推奨
 * PostgreSQL、Web、DevTools、Lombokあたりにチェック（適宜）
* 依存関係の追加。springboot用のdomaを追加する。

```groovy
compile('org.seasar.doma.boot:doma-spring-boot-starter:1.1.0')
```
* [公式](http://doma.readthedocs.io/ja/stable/build/#eclipse)にあるように[boilerplate](https://github.com/domaframework/simple-boilerplate)を参考に設定をする。
 * `eclipse.gradle`をクローンして`build.gradle`と同じ階層に配置。
 * `build.gradle`に以下を追加

```groovy:build.gradle
apply from:'eclipse.gradle'
```
 * Gradle Tasksのeclipseを実行。[annotation processing](http://doma.readthedocs.io/ja/stable/build/#id3)と[Factory Path](http://doma.readthedocs.io/ja/stable/build/#factory-path)が設定されるはず。。   
 ※`doma-spring-boot-starter`の依存関係を追加せずにやると`Factory Path`の自動設定がされないので注意。ソース的にはココかなー

```groovy:eclipse.gradle
def domaJar = configurations.compile.find {
    it.name.startsWith('doma-2')
}
```

## doma-genの設定
* [公式](http://doma-gen.readthedocs.io/ja/stable/gen/#id3)を参考に依存関係の追加。

```groovy:build.gradle
configurations {
	domaGenRuntime
}
dependencies {
    def domaGenVersion = "2.12.0"
    domaGenRuntime('org.postgresql:postgresql')
    domaGenRuntime("org.seasar.doma:doma-gen:${domaGenVersion}")
}
```

## ファイル一式を作成するスクリプト
* [使用例](http://doma-gen.readthedocs.io/ja/stable/gen/#id5)を参考にファイル一式を作るスクリプトを書いていく。
 * DB接続情報はyamlからとってきて拡張プロパティとして定義。（gradle触ったことないから自信薄。。）

```groovy:datasource.gradle
import org.yaml.snakeyaml.*

buildscript {
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.yaml:snakeyaml:1.17")
	}
}

task datasource {
	Yaml parser = new Yaml()
	ant.loadfile (
		srcfile: 'src/main/resources/application.yml',
		property: 'yaml'
	)
	def yamlObj = parser.load("${ant.properties.yaml}")
	ext.url = yamlObj.spring.datasource.url
	ext.user = yamlObj.spring.datasource.username
	ext.password = yamlObj.spring.datasource.password
}
```
 * DB接続情報をapplyしてdomagenタスク組み立て。

```groovy:build.gradle
apply from:'datasource.gradle'

task domaGen {
	def destBaseDir = 'src/main/java/com/example/domain'
	def basePackage = 'com.example.domain'
	def resourceDir = 'src/main/resources'
	
	ant.taskdef(resource: 'domagentask.properties',
		classpath: configurations.domaGenRuntime.asPath)
	ant.gen(url: "${datasource.url}", user: "${datasource.user}", password: "${datasource.password}", templatePrimaryDir: "${resourceDir}/config/doma/templates", tableNamePattern: 'sns_account') {
		entityConfig(packageName: "${basePackage}.entity", useAccessor: false, useListener: false)
		daoConfig(packageName: "${basePackage}.dao", overwrite: true)
		sqlConfig()
	}
}
```
#### トップレベルで使用した変数
1. templatePrimaryDir
 * springbootで使用する場合Daoには`@ConfigAutowireable`を付与しなくてはいけない。これを自動で行いたいのでカスタムテンプレートを用意する（詳細は後述）。それを配置するディレクトリの設定。
 * デフォルトは`src/main/resources/template`なので指定しなくてもよい。
2. tableNamePattern
 * 特定のテーブルだけ自動生成したい場合に使用。適宜。
 * 正規表現で指定可能。デフォルトは`.*`

#### entityConfigで使用した変数
1. packageName
 * 任意のパッケージ下にentityを生成したいときに使用。
2. useAccessor
 * domaはlombokなどと相性が悪く、フィールドを`public`で持つのが慣習らしいので`false`を指定。   
※ 最近では公式のドキュメントに[lombokベストプラクティス](http://doma.readthedocs.io/ja/stable/lombok-support/#id4)があるから、それに則ってコーディングすれば問題ないかも。ただし自動生成したファイルにアノテーションつけたりするにはカスタムテンプレートが必要。
 * `false`を指定するとgetter/setterが生成されないだけではなく、修飾子も自動で`public`にしてくれる。
3. useListener
 * 更新・削除系の前後に何かしらの処理をいれたいときに使うリスナーを自動生成するかどうか。あんまり使わない気がするから`false`。

#### カスタムテンプレート
自動生成されたDaoに`@ConfigAutowireable`を自動で付与させたいときは作りましょう。自動じゃなくてもいいのであれば必要ありません。
1. [doma-gen](https://github.com/domaframework/doma-gen/tree/master/src/main/resources/org/seasar/doma/extension/gen/template)から`dao.ftl`と`lib.ftl`を持ってきます。`templatePrimaryDir`で指定したディレクトリかデフォルトのディレクトリに配置します。
※`lib.ftl`は空ファイルなので、普通に新規作成してもいいです。
2. `dao.ftl`で使用するアノテーション名とパッケージのハッシュを`lib.ftl`に定義します。

 ```velocity:lib.ftl
<#assign annotationHash={ "ConfigAutowireable": "org.seasar.doma.boot.ConfigAutowireable" }>
```
　
3. `dao.ftl`にアノテーションとアノテーションの`import`を追加するスクリプトを適当な場所に追記します。

 ```velocity:dao.ftl
<#list lib.annotationHash?values as annotationImportName>
import ${annotationImportName};
</#list>
```

```velocity:dao.ftl
<#list lib.annotationHash?keys as annotation>
@${annotation}
</#list>
```
4. あとはタスクを実行すればファイル一式が生成されると思います。

## ソース
https://github.com/kunipon/domagen-sample

## 参考
* [doma公式](http://doma.readthedocs.io/ja/stable/)
* [doma-gen公式](http://doma-gen.readthedocs.io/ja/stable/)
* [カンガルーさんの日記](http://ksby.hatenablog.com/entry/2015/10/15/043336)