OpenRewrite の OrderImports レシピでインポート宣言を一括整形する


はじめに

OpenRewrite の OrderImports レシピを使ってインポート宣言を一括整形することができます。

OpenRewrite のレシピは親切なドキュメントが提供されておらず、ソースを見てね という感じなので、OrderImports レシピの使い方を記しておきます。

OpenRewrite については以下を参照してください。

blog1.mammb.com


Gradle 設定

build.gradle.kts でプラグインを導入し、rewrite ブロックに設定を定義します。

plugins {
  java
  id("org.openrewrite.rewrite") version("7.0.3")
}

rewrite {
  activeRecipe("com.example.MyFormat")
  activeStyle("com.example.MyStyle")
  isExportDatatables = true
}

activeRecipe で有効化するレシピを定義し、ます。ここでは後述の rewrite.yml で定義する名前を指定しています。

isExportDatatables は脆弱性スキャンのレシピなどで分析結果のレポートを出力するような場合に true を設定します。ここでは必要ありませんが true にしておきました。


buildSrc 配下の Convention Plugin で設定を行う場合は以下のようになります。

buildSrc\build.gradle.kts

plugins {
    `kotlin-dsl`
}
repositories {
    gradlePluginPortal()
}
dependencies {
    implementation("org.openrewrite.rewrite:org.openrewrite.rewrite.gradle.plugin:7.0.3")
}
plugins {
    java
    id("org.openrewrite.rewrite")
}
// ...
rewrite {
    activeRecipe("com.example.MyFormat")
    activeStyle("com.example.MyStyle")
    isExportDatatables = true
    configFile = project.rootProject.file("rewrite.yml")
}


rewrite.yml の準備

プロジェクトのルートディレクトリに rewrite.yml を作成します。

type: specs.openrewrite.org/v1beta/recipe
name: com.example.MyFormat
recipeList:
  - org.openrewrite.java.OrderImports:
      removeUnused: true
---  
type: specs.openrewrite.org/v1beta/style
name: com.example.MyStyle
styleConfigs:
  - org.openrewrite.java.style.ImportLayoutStyle:
      classCountToUseStarImport: 999
      nameCountToUseStarImport: 999 
      layout:
        - import java.*
        - import javax.*
        - import all other imports
        - <blank line>
        - import static all other imports

レシピとして org.openrewrite.java.OrderImports を宣言しています。removeUnused により未使用のインポート宣言を削除できます。

org.openrewrite.java.OrderImports は、内部で org.openrewrite.java.style.ImportLayoutStyle というスタイルを利用します。スタイルの定義は com.example.MyStyle として定義しています。

ImportLayoutStyle の設定が無い場合は org.openrewrite.java.style.IntelliJ がデフォルトとして使用されます(デフォルトだと同じ名前の別Enumを静的スターインポートに変換してコンパイルエラーになることがあるのでお勧めできません)。

ImportLayoutStyle では以下の設定を行うことができます。

設定 説明
classCountToUseStarImport 同じパッケージからのインポートがスターインポートに折りたたまれるまでに、いくつ存在しなければならないか(デフォルト5)
nameCountToUseStarImport 同じ型からの静的インポートがいくつ存在すれば、それらをスタティックスター・インポートに折りたたむか(デフォルト3)
layout コンパイルユニット内でインポートをどのようにまとめるかを定義するインポートグループの順序付きリスト
packagesToFold 1つ以上のタイプが使用されているときに折りたたまれるパッケージの順序付きリスト


OrderImports レシピの実行

レシピの実行は以下で行います。

$ ./gradlew rewriteRun

ソースファイルのインポート宣言が一括更新できます。

以下でドライランすることもできます。

$ ./gradlew rewriteDryRun


インポート宣言の更新は大抵の場合上手くいきますが、スターインポート利用時に問題がでることがあります。

例えば以下のようなインポート宣言は、

import static org.mockito.Mockito.any;  
import static org.mockito.Mockito.*;  
import static org.hamcrest.CoreMatchers.*;

以下のように更新されます。

import static org.hamcrest.CoreMatchers.*;  
import static org.mockito.Mockito.*;

これにより any(Foo.class) というコードはコンパイルエラーになります。CoreMatchers.any()Mockito.any() か判断できないためです。コンパイルエラーになった場合は、対象のソースコードをリストアし、スターインポートを解消してから rewriteRun を再度実行すると良いでしょう。