最初に注意として JDK は今のところ必ず 1.8 (Java 8) を使用すること。 JDK 9.0 を使用してしまうと以下の手順の中で原因不明のエラーが表示されてしまう。 Kotlin 側のプラグインもまだ 1.8 までしか用意されていない。

まず PostgreSQL の例

Spring Boot やその他 Java EE プロジェクトでデータベースを扱う際は JPA を使用することが多いと思うが、まずここでは IntelliJ IDEA を使用し Spring Boot で PostgreSQL を使用できる環境を作る手順を示す。 新規プロジェクトの Spring Initializr の依存関係で以下を選択する:

  • Web (Spring MVC)
  • Thymeleaf
  • JPA
  • PostgreSQL

この状態でアプリケーションクラスを実行すると以下のエラーとなる:

Failed to auto-configure a DataSource: 'spring.datasource.url' is not specified and no embedded datasource could be auto-configured.

エラーメッセージの通り application.yaml に以下を定義する:

spring:
  datasource:
    url: jdbc:postgresql://localhost/postgres
    driverClassName: org.postgresql.Driver
    username: postgres
    password: postgres

これで実行するとまたエラーとなる:

java.lang.reflect.InvocationTargetException: null
...(中略)...
Caused by: java.sql.SQLFeatureNotSupportedException: org.postgresql.jdbc.PgConnection.createClob() メソッドはまだ実装されていません。

これでは何だか分からないので Stack Overflow に聞いてみると application.yaml に以下の設定を追加すれば良いようだ:

spring:
  jpa:
    properties:
      hibernate:
        temp:
          use_jdbc_metadata_defaults: false
        dialect: org.hibernate.dialect.PostgreSQLDialect

この状態で再度アプリケーションクラスを実行し、先ほどのエラーが表示されずに正しく Tomcat が起動する事を確認する。

SQLite の場合

SQLite の場合 PostgreSQLDialect に値する SQLiteDialect といった実装が最初から用意されていない。 ただ、これに関しては既に作成して Maven リポジトリに上げている方がいらっしゃるのでありがたく使用させていただくことにする。 それと SQLite の JDBC ドライバも必要なので build.gradle に以下を追加する:

dependencies {
    compile('com.enigmabridge:hibernate4-sqlite-dialect:0.1.2')
    runtime('org.xerial:sqlite-jdbc')
}

これに従い application.yaml を以下に書き換える:

spring:
  datasource:
    # SQLite のファイル位置を指定
    url: jdbc:sqlite:./db.sqlite3
    driverClassName: org.sqlite.JDBC
  jpa:
    properties:
      hibernate:
        temp:
          use_jdbc_metadata_defaults: false
        dialect: com.enigmabridge.hibernate.dialect.SQLiteDialect

アプリケーションクラスを実行し、正しく Tomcat が立ち上がることを確認する。

簡単にテストしてみる

JPA の詳細に関しては検索すればいくらでも出てくるのでここには記載しない。 まず該当するテーブルが SQLite 内にあるものとして以下のような感じで Entity クラスを用意する:

@Entity
@Table(name = "post")
data class Post(
        @Id @GeneratedValue(strategy = GenerationType.AUTO) var id: Int = 0,
        var date: String = "",
        var name: String = "",
        var text: String = "",
        var enabled: Boolean = false,
        var created: Date = Date(),
        var modified: Date = Date()
)

Kotlin だと data classEntity が用意できるのでとても便利だ。 toString() を実装しなくてもいい感じにクラス内のデータを出力してくれる。 var にして意味のない初期値を与えなければならないところがちょっと格好悪いが仕方がないところだろうか。

対応する PostRepository クラスを以下のように定義する:

interface PostRepository : JpaRepository<Post, String> {
    fun findById(id: Int): Post
}

定義したリポジトリを使用してコントローラから実行してみる (本来は Service から実行するのが筋だがここでは例のため簡単にする):

@Controller
class SampleController {

    @Autowired
    lateinit var postRepository: PostRepository

    @GetMapping("/")
    fun sample(model: Model): String {
        val post = postRepository.findById(1)  // ID をキーにして 1 件取得
        System.out.println(post)  // Post の中身が出力される
        return "sample"
    }
}

特に意味はないがテンプレートが必要なので /resources/templates/sample.html として以下を用意:

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Sample</title>
</head>
<body>
<p>Hello World!!</p>
</body>
</html>

実行して http://localhost:8080 にアクセスし、標準出力に正しく DB 取得結果が表示されることを確認する。