日々常々

ふつうのプログラマがあたりまえにしたいこと。

Javaアプリケーションを作るときにまずやってること

DevLOVE関西で実験的なイベントをさせてもらいました。

devlove-kansai.doorkeeper.jp

このイベントのおかげで、自分がアプリケーション作るときに最初にどうしてるかを確認できたので晒してみます。誰かの役に立つかどうかは知らない。あ、Macです。ある程度はWindowsでもいけると思うけど、ある程度だと思う。

なおSTSとかIDEのプロジェクト生成機能を使えば一発で済むことだったりする。宗教上の理由で使わないけど。

やってること

基本的にマウスを触る必要はないです。それぞれの詳細は次の通り。長く見えるかもしれませんが、(IDEAの起動とgradleのjarのダウンロード時間を除けば)全部で30秒くらいです。

作業ディレクトリを作る

% git init {作るもの}
% cd {作るもの}

mkdir {作るもの} して cd {作るもの} して git init することもあります。 たまにこの段階で README.md を作ってコミット、ライセンスファイルを作るときはGitHubで作ってからcloneします。

ビルドスクリプトを用意する

記憶かける程度ならそれで。

% vi build.gradle

だいたいこれくらい。たまに cat>build.gradle で書いたりもしますが、気分です。

apply plugin: 'java'
repositories.jcenter()
dependencies {
  testCompile 'junit:junit:4.12'
}

Javaのバージョンやエンコードの設定などが無いですが、一旦作ってから後で変えればいいと思っているのでこだわりません。

これよりも多く書く場合(作るものが決まってるとか)は次のいずれかになります。イベントでは「手元のテンプレートをコピる」をしました。

  • 手元のテンプレートをコピる
  • ググる
  • Spring Initializr

手元のテンプレートをコピる

% cp {テンプレートのあるとこ}/build.gradle ./

ググる

ググって出てきたの(主にGettingStarted)を切り貼りします。

MavenCentralRepositoryを検索

使いたいgroupIdとかがわかっている場合はこっちで検索。

https://mvnrepository.com/

Spring Initializr

https://start.spring.io/

便利ですね。

必要なディレクトリを作る

% mkdir src/main/java src/main/resources src/test/java src/test/resources

これをするエイリアスを作っています。前段のテンプレートをコピるのをあわせたのもあるので、そっちを使うことが多いです。

alias mkjavadirs='mkdir src/main/java src/main/resources src/test/java src/test/resources'
alias initSpringProject='mkjavadirs && cp {テンプレートのあるとこ}/springboot.gradle ./build.gradle'

と言う感じ。

IDEを起動して取り込む

% idea build.gradle

IntelliJコマンドラインランチャーを使います。 Tools / Create Command-Line Launcher から作れるもので、 idea コマンドで新しくプロジェクトが開けます。 コマンドラインラインチャーを作らないなら、IDEAを立ち上げてからOpenでbuild.gradleを選ぶのですが、若干面倒。

テストを書いて実行する

こんな感じのテストを作って実行します。

import org.junit.Test;

public class HogeTest {
    @Test
    public void test() throws Exception {
        
    }
}

即捨てるのでデフォルトパッケージです。確認したいのは環境です。テストが実行できる環境になっているかとか。

面倒に思えるかもしれませんが、テストの作成は以下でできます。

  • Projectの src/test/java ディレクトリを選択
    • [Command]+1 から上下キー、もしくはマウスクリックします
  • [Command]+n で新規のメニューを開いて [Enter]
    • 新規クラス作成のダイアログが出る
  • HogeTest [Enter]
    • クラスができる
  • [Esc]
    • エディタがアクティブになる
  • O
    • 新規行ができる。vimすばらしい。
  • test [Tab]
    • Live Templatesによりテストメソッドが生成される
  • test
    • テストメソッド名を入力
  • [Ctrl]+[Alt]+r [Enter]
    • テストが実行される

キーを押す回数は30回程度、今やってみたら12秒でした。( HgeTest ってtypoったけど。) これをサボると、たまに「なんかビルドできない」とかで悩んだりして馬鹿らしいので、ビルドスクリプトを切り貼りしたときや、環境の更新をした後などは必ずやります。

SpringBootアプリケーションの場合

テストではなく Application クラスで代用します。 起動すれば環境としては問題無いと判断できます。

コミットする

% git add .
% git commit -m"init"

いつでもここに戻ってこれるように。

この段階のリポジトリ

GitHub - irof/DevKan20180305 at a4ccd5d761ccb58cd66bdbec1516cfb2f41852c6

コミットとしてはこの2つ。

さらに前段のことや、周囲のことや、マルチプロジェクトの場合とか、とかとか

WEB+DB PRESS vol.98 「実践!イマドキのビルド環境」に書いてます!

WEB+DB PRESS Vol.98

WEB+DB PRESS Vol.98

Spring Boot Gradle Pluginの話(Spring Boot 1.5.x & Gradle 4.5)

Spring Boot 1.5.x とGradle 4.5 の話です。Spring Boot 2.0とGradle4.6が出たので、埋葬がてら書いておきます。 どんな感じで要らない話になったのかは最後に書いてます。

Spring Boot Gradle Pluginの機能

67. Spring Boot Gradle plugin

たいだい*1 だいたいリファレンスは先頭が重要です。なぜか読み飛ばされがち。コードがあったらそっち読んじゃうのはわかるけど。

The Spring Boot Gradle Plugin provides Spring Boot support in Gradle, allowing you to package executable jar or war archives, run Spring Boot applications and use the dependency management provided by spring-boot-dependencies.

  • allowing you to package executable jar or war archives
    • executable jarを作るための bootRepackage タスクが追加され、 jar タスクの後に自動的に実行されるようになる。
  • run Spring Boot applications
    • bootRun タスクが追加される。
  • use the dependency management provided by spring-boot-dependencies
    • dependencies のうち、Springが管理されるものはバージョンの記述が不要になる。

つまり、プラグインの機能は主に3つ*2ということ。

これからわかるのは、Spring Boot Gradle PluginはSpringBootアプリケーションプロジェクト(Mainクラスが入ってるやつ)には適切だけれど、SpringBootアプリケーションから使用されるモジュールにはdependency management以外は不要なので微妙ってことです。2/3を使ってないわけですからね。

単一モジュールで作っているなら問題にならないだろうけど、共通で使うモジュールとか作る際にうっかり使っちゃうと困ることになる。使わないもの( bootRun タスクがそれ)はまだいいのだけど、勝手に動作する( bootRepackage タスクがそれ)のが問題なのです。

起こりうる問題

たとえばこういう問題が起こります。

  • Main クラスがないのでビルドエラーになる。
  • (仮に最初のを回避したとして)依存ライブラリがjarの中に入る。

他にもあるかもしれないけど、知らない。

対処

  • (だめ) Mainクラスを作る
  • (だめ)bootRepackage.layout = 'MODULE'
  • bootRepackage をしない
  • Dependency management plugin だけ使う

それぞれ書いていきます。

Mainクラスを作る

Mainクラスがないからエラーとか言われるからってMainクラスを作るやつ。要らないもの作っちゃだめですね。

レイアウトをMODULEにする

Mainクラスがなくてもビルドできます。モジュールを作ってるんだからそれっぽく見えるかもしれませんが、jarの中に依存ライブラリがぶっこまれます。そんなjarいらない。無駄にでかくなるし。

bootRepackageしない

そもそもrepackageする必要がないので止めちゃいましょう。

bootRepackage {
    enabled = false
}

シンプルだし、プロジェクトによって使うGradle Pluginを変えなくていいというのはメリットかもしれません。技術スタックは少ない方がいいので。

でも使用しないタスクが入るところは微妙かも。

Dependecy management pluginを使う

Sprign Boot Gradle Pluginは中で Dependency management plugin を使っています。

GitHub - spring-gradle-plugins/dependency-management-plugin: A Gradle plugin that provides Maven-like dependency management functionality

コードではこんな感じでとりこんで、こんな感じspring-boot-starter-parent をインポートしてます。これをDependency management Plugin を使う形で build.gradle に書くとこうなります。

plugins {
    id "io.spring.dependency-management" version "1.0.4.RELEASE"
}

...

dependencyManagement {
    imports {
        mavenBom 'org.springframework.boot:spring-boot-starter-parent:1.5.10.RELEASE'
    }
}

これで余計なタスクも入らない。Spring Bootアプリケーションを作ってるわけではないのだから、たぶんこれでいいはず。

モジュールの独立性とか言ったら(bomとはいえ)SpringBootに依存するのはどうなのとかあるでしょうけど、バージョンの整合性を取るのは面倒だし、自分たちしか使わないモジュールならこれでよかろーです。

Spring Boot 2.0では

マイグレーションガイドに書かれている通り、Spring Boot Gradle Pluginからdependency managementは除外されています。

Spring Boot 2.0 Migration Guide · spring-projects/spring-boot Wiki · GitHub

あと変わったことといえば、Spring BootのリファレンスのSpring Boot Gradle Pluginの記述がスッキリしてます。(最初に出したのと見比べて見てください)

69. Spring Boot Gradle Plugin

リンクされてるSpring Boot Gradle Plugin Reference Guideがしっかりしたものになってる。あとAPIドキュメントもリンクされててて開きやすくなったのも嬉しい。

Gradle 4.6では

Gradle 4.6 Release Notes

BOMをインポートする機能がはいったのでDependency management pluginもいらない。 かも。まだ試してない。

リリースノートに書いてる通り、 settings.gradle に1行いります。

github.com

こんな感じ。

*1:

*2:Agent指定の何かとかエンコーディング変えたりとかもあるのだけど、これらは補助的なものなので書かれてないっぽい。

SpringBoot2.0がリリースされたのでバージョンアップしてみた

spring.io

待望のSpringBoot2.0がリリースされました。 ので早速バージョンアップだー。

やったことといえば、 build.gradle のビルドスクリプトプラグインのバージョンアップだけ。 Spring Boot Gradle Plugin Reference Guide に書いてる通りですね。

- id 'org.springframework.boot' version '1.5.10.RELEASE'
+ id 'org.springframework.boot' version '2.0.0.RELEASE'

そしたら javaio.spring.dependency-management が外れるので、追加。

+ apply plugin: 'java'
+ apply plugin: 'io.spring.dependency-management'

対象のプロジェクトは spring-boot-starter を使ってるだけのやつで、超シンプルなやつなのでこれだけで完了しました。 application.properties にSpringBootのことは書いてなかったんで、そっちがどう変わったかはみてないです。とりあえず軒並みキーは変えなきゃいけないはず。

SpringFrameworkも4から5に上がるわけだけど、コンパイルエラーとかにもなんない。流石にこう言うところは安定してるなー。

変わってたとこ

なんかあったらメモがてら実装してこーかと思って。

github.com

application.properties の空白文字の扱いが変わってた。

プロパティファイルの空白ってどう言う扱いなんだっけなと軽く探してみてみたけど、 Properties (Java Platform SE 8) くらいしか見つけられず。 そもそも Properties#load で読むのと SpringBoot1.5で application.properties を読むのとでも違うので、まあ、うん。

とりあえず application.properties で値に空白文字(スペースやタブ)を使用してたら、 String#trim されるんで消えちゃいます。 これは新しいプロパティを読むクラスで実装されてるので、 PropertyPlaceholderConfigurer. setTrimValues(false) とかしてみても意味ないです。

ちなみにapplication.properties ではなく、コマンドライン引数とか application.yml とか、他の手段で設定すれば特に関係ない話です。 どうしても application.properties でないとダメなんだーとかでもなければそちらで対応できるやつです。

もともとが正しいとも言いづらい(IDEが警告だすような記述なわけだし)ものなんで、仕様外の話かなーと。