しおしお

IntelliJ IDEAのことなんかを書いてます

DomaをIntelliJ&Gradleの組み合わせで使った場合にIntelliJでビルドできるようにする

DomaIntelliJ&Gradleで使ったば場合にIntelliJ側でもビルドできるようにする手順です。

バージョンなど

Gradle
task wrapper(type: Wrapper) {
  gradleVersion = '3.3'
}
IntelliJ IDEA

下のバージョンで確認をしました。

  • 2016.3.2
  • 2017.1(EAP)
プロジェク構成

下のプロジェクト構成で確認を行いました

  • シングルプロジェクト
  • マルチプロジェクト(rootプロジェクトのsubprojects内に設定を行っています)

Domaのドキュメントを参考にbuild.gradleを作る

ビルド — Doma 2.0 ドキュメントを参考にbuild.gradleを作りましょう。
これで、Gradleでビルドした場合にSQLファイルをうまく参照できるようになります。

IntelliJでビルドできるようにするための設定を追加する

build.gradleに以下の設定を追加します

// ideaプラグインを追加
apply plugin: 'idea'

// モジュールの出力先ディレクトリをcompileJava.destinationDirに変更
idea.module.outputDir = compileJava.destinationDir

IntelliJでビルドしてみると

SQLファイルの出力先がresourcesからclassesになりちゃんとビルドできるようになりました。

ちなみに、上の設定を行わずにビルドした場合はこんな感じに出力されてビルドが失敗します。

inheritOutputDirsを有効しないと動かない場合がある

inheritOutputDirsを有効(true)にしないと、うまく動かないとの指摘をいただきました。
上に書いたバージョンの組み合わせでは、この設定がなくても動いたのですがバージョンの組み合わせによってはこの設定が必要なので、以下の設定をbuild.gradleに追加してあげましょう。

  idea.module.inheritOutputDirs = true



おわり。

JenkinsでIntelliJ IDEAのinspectionを実行して結果をいい感じに表示させてみる

IntelliJさんのinsupectionはCI環境でも実行できるので、Jenkinsで実行&いい感じに結果を表示する方法を調べてみた。 *1

Jenkinsに必要なプラグイン

Warnings Plugin - Jenkins - Jenkins Wiki
IntelliJさんのinspectionの結果をいい感じに集計&表示するために必要になります。

ビルドにinspectionの実行を定義する

inspectionの実行と、inspection実行結果のファイル内のパス置き換えを行ってあげます。
実行結果ファイルのパス書き換えをしないと、指摘箇所のソースへのジャンプ時にエラーになってしまいます。

/var/jenkins_home/idea-IC-163.9166.29/bin/inspect.sh . /var/jenkins_home/my_inspection.xml ./report/inspection -d src/main/java
sed -i 's/file:\/\/\$PROJECT_DIR\$\///' ./report/inspection/*.xml

設定のイメージ的にはこんな感じです。

IntelliJプラグインをCIサーバに配置する

サードパーティ製のプラグインのInspection機能をCIサーバで実行したい場合には、プラグインをCIサーバ上にインストールする必要があります。
インストール先は、$idea.config.path/pluginsとなります。

ビルド後の手順にinspection結果の集計を追加する

下の画層のようにWarnings Pluginを使って結果の集計を行います。
集計するファイルにはinspection実行結果のファイルを指定して、パーサにはIntelliJ IDEA Inspectionsを選択します。

ジョブの実行結果

ジョブを実行するとChecstyleプラグインと同じ感じに結果が見れます。

ジョブの結果画面


指摘の一覧

指摘箇所のソースコード


ハマりポイント

CI環境にIntelliJさんのjdk設定が必要

具体的には、$idea.config.path/options/jdk.table.xmlが必要となります。
この設定がないと、下のようなメッセージがでてinspectionの実行がエラーとなってしまいます。
(他のパターンもあって、下と同じようにJDKの設定がないよ的なエラーがでます)

Please, specify sdk 'null' for module 'inspection_test_pj_main'

デスクトップ環境があれば、IntelliJを起動して、JDKの設定をしてあげるだけでOKです。
もし、デスクトップ環境がない場合には、別の環境で作ったファイルをCIの該当ディレクトリに移動する必要があります。

Warnnings pluginがエラーをはいておわってしまう

こんな感じのエラーをはいて異常終了してしまうことがあります。
これは、inspectionの結果ファイルに行数を示す要素がない場合に発生します。
例えば、パッケージ名やモジュールに対するinspection結果にはこの要素がないためエラーとなってしまいます。

エラーとなった結果ファイルは、例えばgrep -L line report/inspection/*.xmlで検索できます。
これらの結果を除外したい場合は、inspect.sh(bat)実行後に、grep -L line report/inspection/*.xml | xargs rm -rfを実行して削除してあげれば良いと思います。

ERROR: Build step failed with exception
java.lang.NumberFormatException: For input string: "-"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65)
	at java.lang.Integer.parseInt(Integer.java:572)
	at java.lang.Integer.parseInt(Integer.java:615)
	at hudson.plugins.warnings.parser.IdeaInspectionParser.parseProblems(IdeaInspectionParser.java:69)

おわり。

JBeretでスクリプト言語を使用してバッチアーチファクトを作ってみる

JBeretのユーザーズガイド見てたら、「Develop Batch Artifacts in Script Languages」なる章*1があったので試してみた。

JBeretのバージョンは1.3系にする

Gradleだとこんな感じです

  compile 'org.jberet:jberet-se:1.3.0.Beta3'

使用するスクリプト言語のライブラリをdependencyに追加する

Groovyだとこんな感じになります

  compile 'org.codehaus.groovy:groovy-jsr223:2.4.7'
  compile 'org.codehaus.groovy:groovy:2.4.7'

ジョブ定義をしてみる

簡単そうなBatchletで試してみました。
このれいでは、batchletタグ内にscriptタグでBatchletの実装を定義しています。
stepContextやjobContextの参照もできます。

<job id="script-sample" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
  <step id="myStep">
    <batchlet>
      <script type="groovy">
        <![CDATA[
          println("Groovy Script!")
          println("ステップ名:${stepContext.stepName}")
        ]]>
      </script>
    </batchlet>
  </step>
</job>

実行結果

ちゃんと動いた!!!

[main] INFO org.jboss.weld.Version - WELD-000900: 2.4.1 (Final)
[main] INFO org.jboss.weld.Bootstrap - WELD-000101: Transactional services not available. Injection of @Inject UserTransaction not available. Transactional observers will be invoked synchronously.
[main] INFO org.jboss.weld.Bootstrap - WELD-ENV-002003: Weld SE container STATIC_INSTANCE initialized
Groovy Script!
ステップ名:myStep
[Thread-1] INFO org.jboss.weld.Bootstrap - WELD-ENV-002001: Weld SE container STATIC_INSTANCE shut down
Weld SE container STATIC_INSTANCE shut down by shutdown hook

使うシーンがイメージできないけど。。。

H2データベースに複数プロセスから接続する

こんな感じに、URLに;AUTO_SERVER=TRUEをくっつけるだけでいける。

jdbc:h2:./h2/db/nablarch_example;AUTO_SERVER=TRUE

アプリ実行中にIntelliJから繋いで状態確認するレベルであればこれで問題なさそう。

Featuresによると、最初の接続を閉じた場合に実行中のトランザクションロールバックされる的なこと書いてあるので、使い方には注意が必要かな。

Spring Bootの@Valueに指定するプレースホルダのプレフィックスを変更する方法

@Valueアノテーションを使ってプロパティの値をインジェクションする場合、デフォルトではプレフィックスに${を指定する必要がある。
Javaで書いてる場合は問題ないけど、Kotlinを使うと文字列内の$は変数を展開するために使うので下のコードのようにエスケープしないとダメで残念な感じになります。

@Value("\${target.host}") private val host:String

プレフィックスはこんな感じに、PropertySourcesPlaceholderConfigurerを使うことで変更できます。

@Bean
open fun propertyConfigurer() : PropertySourcesPlaceholderConfigurer {
  val propertySourcesPlaceholderConfigurer = PropertySourcesPlaceholderConfigurer()
  propertySourcesPlaceholderConfigurer.setPlaceholderPrefix("&{")
  eturn propertySourcesPlaceholderConfigurer
}

これで、$のエスケープが不要になります。

@Value("&{target.host}") private val host:String

参考にした情報です。
stackoverflow.com

※ConfigurationPropertiesを使えばValueアノテーション使わなくていいので、単純にこの問題を回避できる。
そもそも、プロパティの値を保持するBeanはJavaで書いたほうが幸せになりそうな気もする。

IntelliJ小ネタ:Compact Empty Middle Packagesでも好きなパッケージ配下にファイルを作る!

IntelliJさんの、Project Viewでパッケージの表示状態をCompact Empty Middle packagesな状態にしていると、間のパッケージにファイルを作成することができません。

例えば、下の画像の状態でdomaパッケージを選択してファイルを作ると、domaの下に作られます。
f:id:sioiri:20160804225540p:plain

これを、siosio配下に作るかdoma配下に作るかを選択できるようにする方法です。

Registry画面を開く

Find ActionからRegistry画面を開きます。
f:id:sioiri:20160804225802p:plain

設定を変更する

「projectView.choose.directory.on.compacted.middle.packages」のチェックをオンにすることで、作成するパッケージを選択できるようになります。

f:id:sioiri:20160804230626p:plain

ファイルを作ってみると

どこに作るか聞いてくれます。いい感じです。
f:id:sioiri:20160804230110p:plain

おわり。

Spring Bootでjackson-module-kotlinを使う

Jacksonのkotlin対応モジュール をSpring Bootで使ってみる。

バージョンなど

Spring Boot:1.3.5
Jackson:2.6.6

Jacksonのkotlinモジュールを依存に追加

Gradleだとこんな感じですね

compile 'com.fasterxml.jackson.module:jackson-module-kotlin:2.6.6'

Jsonマッピングするクラス

こんな感じのクラスにマッピングする

data class Param(val str:String, val num:Int)

JacksonのKotlinモジュールを有効にする

Developing Spring Boot applications with Kotlinを参考にして追加してあげる。

  @Bean
  open fun objectMapperBuilder(): Jackson2ObjectMapperBuilder
      = Jackson2ObjectMapperBuilder().modulesToInstall(KotlinModule())

コントローラの実装

Jsonマッピングされたdata classを文字列表現で返すだけのシンプルな実装です。

@RestController
@RequestMapping("test")
open class Controller {

  @RequestMapping(consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE), method = arrayOf(RequestMethod.POST))
  @ResponseBody
  fun post(@RequestBody param: Param): String {
    return param.toString()
  }
}

動かしてみると

いい感じに動きました。

curl  -H "Content-Type: application/json" -X POST -d '{"str": "12345", "num": 100}' http://localhost:8080/test
Param(str=12345, num=100)

Spring Boot1.4系になると

Spring Boot1.4系になると、 jackson-module-kotlinを追加してあげるだけでいい感じに動いてくれます。
上の例で書いたような、KotlinModuleの設定がいらなくなる感じです。

この辺の実装が追加されてるからですかね。
spring-framework/Jackson2ObjectMapperBuilder.java at master · spring-projects/spring-framework · GitHub

おわり。