Cwらぼっちゃ - IT技術研究ノート -

IT技術に関する記事を掲載します。

Spring boot の言語に Kotlin を選択して Gradle に MyBatis Generator の起動タスクを登録してみたお話

はじめに

背景

この記事は流行りの技術に疎いオールドエンジニアの私がちょっと頑張ってみたお話を綴っています。
Gradle も知らなければ Kotlin も Groovy 知らない。。という状態から REST API を用いた WEBシステムをつくろうとしたのが始まりです。
フレームワークは Spring boot を使おう。言語は Kotlin。フロントは Vue.js を使おう。などと、どうせやるならやったことのない技術でやりたいと思い、手を出しました。
システムはまだまだできてませんが、O/R Mapper に MyBatis を選び、MyBatis Generator のタスク登録にとてつもなく苦労し、やっとこさジェネレートできたので備忘録も兼ねて記事を書きました。

だって記事がないんだもん。。

言語に Kotlin を選んだのがそもそもの苦労した原因でした。
Spring Initializr で Gradle やら Koltin やら MyBatis やらと選んで落としたテンプレに入っていた build.gradle が build.gradle.kts でした。
「Gradle で MyBatis Generator を実行しよう」なる記事はいくつもありました。
でもね、、でもですよ?、、これがことごとく build.gradle なんですよ。Groovy なんですよ。私の ググり力が足りていないのかもしれませんが build.gradle しかなかったんですよ。
中国サイトには載っていたような気がしますが「ちょっと何言っているかわからないです」なんです。
GitHub にも載っていたような気がしますがやっぱり「ちょっと何言っているかわからないです」なんです。
今どきのおしゃれエンジニアだったらコード見ただけで「ふふん、楽勝でしょ」ってなるのでしょうがおじさんにはどえらい高い壁に見えました。
「なんでわかんねぇーんだよ!」とツッコミが聞こえてくるようです。

What's " build.gradle.kts " ??

Kotlin DSL(Domain Specific Language) と言うようですが、要は build.gradle が Groovy で書かれるのに対して、build.gradle.kts が Kotlin で書かれるという違いです。
最初に調べていた時は技術に多少覚えのあるおじさんだったのでそりゃあ「ふふん、楽勝でしょ」って思っていましたが、いざやってみるとこれが大変。
いかに自分が " 井の中の蛞 " かを思い知らされました。

いきなりできあがり

config ファイル

ファイル名は何でも良いのですが、DB(ここでは PostgreSQL 11.5) との接続設定やら出力するクラス、そのパスなどの情報を書きます。
パスは "(ルートプロジェクト)/src/main/resources/mybatis/generatorConfig.xml" として、 generatorConfig.xml というファイル名で作成しました。

<!DOCTYPE generatorConfiguration PUBLIC
        "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="kotlin" targetRuntime="MyBatis3Kotlin">
        <jdbcConnection driverClass="org.postgresql.Driver"
                        connectionURL="jdbc:postgresql://localhost:5432/hoge_db"
                        userId="hogeman"
                        password="hogehoge" />
        <javaTypeResolver />
        <javaModelGenerator
                targetPackage="com.hoge.hogeapi.model.origin"
                targetProject="src/main/kotlin">
            <property name="enableSubPackages" value="true" />
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <javaClientGenerator
                type="ANNOTATEDMAPPER"
                targetPackage="com.hoge.hogeapi.mapper.origin"
                targetProject="src/main/kotlin">
            <property name="enableSubPackages" value="true" />
        </javaClientGenerator>
        <table schema="sc_hoge" tableName="%" modelType="flat" />
    </context>
</generatorConfiguration>

xml ファイルに加えて properties ファイルを使うやり方もありますがここでは割愛します。

build.gradle.kts

はい、噂の build.gradle.kts です。

import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
    id("org.springframework.boot") version "2.2.1.RELEASE"
    id("io.spring.dependency-management") version "1.0.8.RELEASE"
    war
    kotlin("jvm") version "1.3.50"
    kotlin("plugin.spring") version "1.3.50"
}

group = "com.hoge"
version = "0.0.1-SNAPSHOT"
java.sourceCompatibility = JavaVersion.VERSION_1_8

repositories {
    mavenCentral()
}

dependencies {
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("com.fasterxml.jackson.module:jackson-module-kotlin")
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8")
    implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1")
    implementation("org.mybatis.dynamic-sql:mybatis-dynamic-sql:1.1.4")
    runtimeOnly("org.postgresql:postgresql:42.1.4")
    providedRuntime("org.springframework.boot:spring-boot-starter-tomcat")
    testImplementation("org.springframework.boot:spring-boot-starter-test") {
        exclude(group = "org.junit.vintage", module = "junit-vintage-engine")
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

tasks.withType<KotlinCompile> {
    kotlinOptions {
        freeCompilerArgs = listOf("-Xjsr305=strict")
        jvmTarget = "1.8"
    }
}

/** -----------------------------------------------------
 * Mybatis Generator 実行タスク
 * -----------------------------------------------------*/
val mybatisMapperVersion = "4.1.5"
val mybatisGeneratorVersion = "1.4.0"
val postgresqlConnectorJavaVersion = "42.1.4"

val mybatisGenerator by configurations.creating

dependencies {
    mybatisGenerator(group="org.mybatis.generator", name="mybatis-generator-core", version=mybatisGeneratorVersion)
    mybatisGenerator(group="org.postgresql", name="postgresql", version=postgresqlConnectorJavaVersion)
    mybatisGenerator(group="tk.mybatis", name="mapper", version=mybatisMapperVersion)
}
task("mybatisGenerator") {
    doLast {
        ant.withGroovyBuilder {
            "taskdef"("name" to "mbgenerator", "classname" to "org.mybatis.generator.ant.GeneratorAntTask", "classpath" to mybatisGenerator.asPath)
        }
        ant.withGroovyBuilder {
            "mbgenerator"("overwrite" to true, "configfile" to "src/main/resources/mybatis/generatorConfig.xml", "verbose" to true)
        }
    }
}

ちなみに、お手本にした build.gradle はこちら。

plugins {
    id 'org.springframework.boot' version '2.2.1.RELEASE'
    id 'io.spring.dependency-management' version '1.0.8.RELEASE'
    id 'java'
    id 'war'
}

group = 'com.hoge'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.1.1'
    implementation 'org.mybatis.dynamic-sql:mybatis-dynamic-sql:1.1.4"'
    runtimeOnly 'org.postgresql:postgresql:42.1.4'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}

test {
    useJUnitPlatform()
}

/** -----------------------------------------------------
 * Mybatis Generator 実行タスク
 * -----------------------------------------------------*/
ext {
    mybatisMapperVersion = '4.1.5'
    mybatisGeneratorVersion = '1.4.0'
    postgresqlConnectorJavaVersion = '42.1.4'
}

configurations {
    mybatisGenerator
}

dependencies {      
    mybatisGenerator group: 'org.mybatis.generator', name: 'mybatis-generator-core', version: mybatisGeneratorVersion
    mybatisGenerator group: 'org.postgresql', name: 'postgresql', version: postgresqlConnectorJavaVersion 
    mybatisGenerator group: 'tk.mybatis', name: 'mapper', version: mybatisMapperVersion
}

task mybatisGenerator {
    doLast {
        ant.taskdef(name: 'mbgenerator', classname: 'org.mybatis.generator.ant.GeneratorAntTask', classpath: configurations.mybatisGenerator.asPath)
        ant.mbgenerator(overwrite: true, configfile: 'src/main/resources/mybatis/generatorConfig.xml', verbose: true)
    }
}

実際に参考にさせて頂いた記事とは少し違っていますが、Groovy で書くとこうでした。
違いの説明はしませんので、" Don't think, just feel! " でお願いします。
書いてみれば何のことはないただの言語の違いだけです。
ただし、「KotlinCompile」やら「withGroovyBuilder」やら、Kotlin DSL ならでは(というか Kotlin で build.gradle を書くための)記述があります。

さいごに

大事な説明をすっ飛ばして起・承・転・結な記事になってしまって申し訳なかったですが、まだまだ人に説明できるほど理解していないのでご容赦ください。
苦労して苦労して、「動いた!書こう!」というノリで記事を書きました。
当初目的としていたシステムの開発が終わるころには偉そうに説明できるくらいのレベルにはなっていたいものです。
まだまだ蛞ですが。

「それでも技術はおもしろい」