Intellij 2017.2 + Gradle + doma-spring-boot-starter でハマったメモ

## 免責
いまいち原因が理解できていませんが、困っている人のために公開します。

## やりたいこと
Maven で書かれた doma-spring-boot-starter のチュートリアルを Gradle で実装したい。
https://github.com/domaframework/doma-spring-boot

## 環境

* IntelliJ IDEA 2017.2.4
* JDK 1.8
* Gradle 3.5.1

## やったこと

* IntelliJ から Spring Initializr を使ってプロジェクト初期化
    * Web, JDBC, H2 にチェック
* build.gradle に doma-spring-boot-starter を追加
    * `compile('org.seasar.doma.boot:doma-spring-boot-starter:1.1.1')`
* build.gradle に [Doma ドキュメント](http://doma.readthedocs.io/ja/stable/build/#gradle) にある記述を追加
    * 最終的なbuild.gradleは↓の方にあります
* IntelliJ の Doma Plugin をインストール
* あとはチュートリアル通りにクラスなどを作成

## ハマり1: エディタに赤線が出る

`ReservationDao` をフィールド定義するところでエラーが表示されます。これは Maven でも同様です。

```DomaExampleApplication.java
@SpringBootApplication
@RestController
public class DomaGradleApplication {
    
    @Autowired
    public ReservationDao reservationDao;
    //=> Could not autowire. No beans of 'ReservationDao' type found.

...
}
```

**解決策(?)**
IntelliJのバグみたいです。
https://stackoverflow.com/questions/26889970/intellij-incorrectly-saying-no-beans-of-type-found-for-autowired-repository
この記事にいろいろ解決策が書いてありますが、異なるバージョンへの対策だったりワークアラウンドであったりするので注意が必要です。
実行時に問題にならないので、私はお布施をして修正を待つことにしました。

## ハマり2: Domaクラスが生成されない

IntelliJ の `Run` ボタンで実行すると、ビルドは成功するものの、下記のエラーでサーバーの起動に失敗してしまいました。

```
***************************
APPLICATION FAILED TO START
***************************

Description:

Field reservationDao in com.example.domagradle.DomaGradleApplication required a bean of type 'com.example.domagradle.ReservationDao' that could not be found.


Action:

Consider defining a bean of type 'com.example.domagradle.ReservationDao' in your configuration.

```

ちなみに Constructor Injection で書き換えた場合、Description は下記となります。

```
Description:

Parameter 0 of constructor in com.example.domagradle.DomaGradleApplication required a bean of type 'com.example.domagradle.ReservationDao' that could not be found.
```

**原因**

`out`フォルダの中身を見てみると、Doma で生成されるはずの `ReservationDao`実装クラスが存在しません。今の場合「a bean of type '...ReservationDao'」とはこの実装クラスを探して見つからなかったということになります。

**解決策**

なぜ生成されないのかをまだ理解していませんが、`gradlew` を使えば生成されることに気付きました。

```
$ ./gradlew build
```
これにより、`build`フォルダが新たに作られ、その中に必要なクラスファイルやjarが作られます。jarを実行してサーバーを起動します。

```
$ java -jar ./build/libs/***.jar
```

ただ、これではIntelliJを使ったデバッグができません。
調べてみると、build.gradle に設定を加えることで動くようになるとのこと。
https://stackoverflow.com/questions/45174989/building-with-intellij-2017-2-out-directory-duplicates-files-in-build-director

実際、`allprojects {...}`を`buildscript{...}`の直後に書くことで、無事動作するようになりました。せっかくなので`build.gradle`全体を掲載します。

```build.gradle
buildscript {
	ext {
		springBootVersion = '1.5.7.RELEASE'
	}
	repositories {
		mavenCentral()
	}
	dependencies {
		classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
	}
}

// https://stackoverflow.com/questions/45174989/building-with-intellij-2017-2-out-directory-duplicates-files-in-build-director
allprojects {
    apply plugin: 'idea'
    idea {
        module {
            outputDir file('build/classes/main')
            testOutputDir file('build/classes/test')
        }
    }
    if(project.convention.findPlugin(JavaPluginConvention)) {
        // Change the output directory for the main and test source sets back to the old path
        sourceSets.main.output.classesDir = new File(buildDir, "classes/main")
        sourceSets.test.output.classesDir = new File(buildDir, "classes/test")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = 1.8

// JavaクラスとSQLファイルの出力先ディレクトリを同じにする
processResources.destinationDir = compileJava.destinationDir
// コンパイルより前にSQLファイルを出力先ディレクトリにコピーするために依存関係を逆転する
compileJava.dependsOn processResources

repositories {
	mavenCentral()
}

dependencies {
	compile('org.springframework.boot:spring-boot-starter-jdbc')
	compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.seasar.doma.boot:doma-spring-boot-starter:1.1.1')

	runtime('com.h2database:h2')

    testCompile('org.springframework.boot:spring-boot-starter-test')
}
```

**注意**
DAOや.sqlファイルを変更したら再度 `./gradle build` する必要があります。

## 最後に

素直に Maven でやった方が楽なのではと思いました。