最近別のプロジェクトに0.5で参加することになりました。人生初の0.5です。おかげで?ガッツリ開発するケースが少なくなりそうで、それはそれで・・・と思う日々です。

それはともあれ、それぞれのプロジェクトでSpring Bootを触ることになりました。これまた人生初です。そんなときになかなか解決しなかったことについて書きます。

今回やりたいことは以下のような感じです。他にもいろいろありますが、今回は絞っています。

こんなことをやりたかったんです。

最初のbuild.gradle

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

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

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

ext {
    assertjGeneratorVersion = '2.0.0'
}

repositories {
    mavenCentral()
}

configurations {
    assertj
}

dependencies {
    implementation('org.springframework.boot:spring-boot-starter-web')
    testImplementation('org.springframework.boot:spring-boot-starter-test')

    assertj "org.assertj:assertj-assertions-generator:${assertjGeneratorVersion}"
    assertj project

}

// configuration and tasks for assertj
sourceSets {
    test {
        java {
            srcDir 'src/test/java'
            srcDir 'src-gen/test/java'
        }
    }
}

def assertjOutput = file('src-gen/test/java')

task assertjClean(type: Delete) {
    delete assertjOutput
}

task assertjGen(dependsOn: assertjClean, type: JavaExec) {
    doFirst {
        if (!assertjOutput.exists()) {
            logger.info("Creating `$assertjOutput` directory")

            if (!assertjOutput.mkdirs()) {
                throw new InvalidUserDataException("Unable to create `$assertjOutput` directory")
            }
        }
    }

    main 'org.assertj.assertions.generator.cli.AssertionGeneratorLauncher'
    classpath = files(configurations.assertj)
    workingDir = assertjOutput
    args = ['foo.bar']
}

compileTestJava.dependsOn(assertjGen)

args にある foo.bar はパッケージ名と思ってもらえれば。

さて、こんなbuild.gradleで、assertjOutputタスクを実行してみても、なんでか動きません。動かないというか、動くけどもファイルが出ません。何をやっても出ないのでいろいろ調査しました。

Generatorのソースを見る

実行している org.assertj.assertions.generator.cli.AssertionGeneratorLauncher を見てみます。

パッケージ名からクラスファイルを取得している部分は ここ です。ClassLoaderから持ってきているので、classpathに入っているはずのpackageが見えないわけはないはず・・・。Generatorに渡している configurations.assertj に、project自身を追加しているので、見えるはずなんです。

ということで、 configurations.assertj を可視化してみると、確かにプロジェクトのjarが入っています。・・・jar?

bootJarとjarタスク

GradleにはJarタスクという、jarを作成するためのタスクがあります。ところで今回はSpring Bootを使っていますが、Spring Bootには、 実行可能なJarを作る という機能があります。

試しに上記のbuild.gradleでbuildを実行してみると、やたらでかいjarが build/libs/ にできます。さて、このjarはJarタスクではなく、 bootJar タスクで作成されています。

Spring BootのBootable Jarは、いろいろと実現するために、repackageを行っています。AppEngineみたいな感じですね。このため、上で指定したpackageが存在しない、ということになっていたようです。

そこで、こんなスニペットを入れてbuildしてみると、もともと生成されるであろう、小さいjarが作成されます。

#+build_src groovy jar { enabled = true } #+end_src

この状態でassertjGenを実行すると、無事に作成できます。ただ、assertjGenを実行する前には、上の設定が有効になっている必要があります。

もしかしたら、bootJarのrepackageオプションを利用すれば、うまく実行できるのかもしれませんが、今回はそこまで深堀しませんでした

結局どうしたか

結局カスタムassertionでやりたいことは、ある程度は Soft assertion で代替できそうだったので、assertjGenはバッサリ削除しました。これがAnnotationベースとかだったらうまく動いたんでしょうが・・・。

しかし、いろいろと調べる過程で、AssertJの使い方とかGradleの使い方とかを知ることができたので、それはそれでよかったと思います。

オチはありませんがこのへんで。