13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

アプリケーションの独自プロパティ編集でコード補完ができるようにする

Last updated at Posted at 2018-02-24

概要

Spring Bootの設定ファイル(application.properteis or .yml)の編集をEclipseやIntelliJ IDEAなどのIDE上で行うと、プロパティ名や値をコード補完できます。

  • Eclipse、Spring Tool Suiteなどでは未確認です。もしかしたらバージョンやプラグインの有無によりコード補完ができないかもしれません。
  • 確認した環境はIntelliJ IDEA 2017.3 Ultimate Editon (+ Spring Support Plugin)です。

IntelliJ IDEAではこの図のようにCtrl + Spaceでコード補完できます。

cc1.png

この記事はコード補完をアプリケーションの独自プロパティでも利用できるにするための手順といくつかのtipsについて説明します。

環境

  • Windows 10 Professional
  • Java 1.8.0_162
  • Spring Boot 2.0.0.RC2
  • IntelliJ IDEA 2017.3 Ultimate Edition

参考

メタデータファイル

Spring Bootのjarファイルには、設定ファイル(application.properties or .yml)のプロパティのメタデータファイルが含まれていて、IDEでのコード補完に利用されています。
アプリケーションの独自プロパティもメタデータファイルを作成することで同じようにコード補完ができるようになります。

メタデータファイルはMETA-INFディレクトリ下に配置し、ファイル名はspring-configuration-metadata.jsonです。ただしこのファイルは自動的に生成されるものを使用するので基本的に手動で編集しません。

メタデータファイルのフォーマット

メタデータファイルはjsonフォーマットで記述します。大まかなアウトラインは次のようになっています。

spring-configuration-metadata.json
{
  "property": [
    {
      "name": "The full name of the property. Names are in lower-case period-separated form.",
      "type": "The full signature of the data type of the property but also a full generic type.",
      "description": "A short description of the group that can be displayed to users.",
      "defaultValue": "The default value, which is used if the property is not specified."
    }
  ],
  "groups": [
    {
      "name": "The full name of the group. This attribute is mandatory.",
      "type": "The class name of the data type of the group. ",
      "description": "A short description of the group that can be displayed to users."
    }
  ],
  "hints": [
    {
      "name": "The full name of the property to which this hint refers.",
      "values": [
        "value": "A valid value for the element to which the hint refers.",
        "description": "A short description of the value that can be displayed to users."
      ],
      "providers": [
        "name": "The name of the provider to use to offer additional content assistance for the element to which the hint refers."
      ] 
    }
  ]
}

独自プロパティのメタデータファイルを作る

プロジェクトの依存関係にspring-boot-configuration-processorを追加します。

Maven

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-configuration-processor</artifactId>
  <optional>true</optional>
</dependency>

Gradle

compileOnly("org.springframework.boot:spring-boot-configuration-processor")

次に、プロパティをバインドするクラスにConfigurationPropertiesアノテーションを付加します。
コンパイル時に、このアノテーションが付いたクラス定義からメタデータファイルが自動的に生成されます。

@Component
@ConfigurationProperties(prefix = "my-app.my-module.foo")
@Validated
public class FooProperties {

    /**
     * foo name description.
     */
    @NotNull
    private String name;

    /**
     * foo max height description.
     */
    @NotNull
    private Integer maxHeight;

    /**
     * foo min height description.
     */
    @NotNull
    private Integer minHeight;

    // getter/setterは省略
}

このクラスをコンパイルして生成されたメタデータファイルです。

spring-configuration-metadata.json
{
  "hints": [],
  "groups": [
    {
      "sourceType": "com.example.demomavenspring2.configure.FooProperties",
      "name": "my-app.my-module.foo",
      "type": "com.example.demomavenspring2.configure.FooProperties"
    }
  ],
  "properties": [
    {
      "sourceType": "com.example.demomavenspring2.configure.FooProperties",
      "name": "my-app.my-module.foo.max-height",
      "description": "foo max height description.",
      "type": "java.lang.Integer"
    },
    {
      "sourceType": "com.example.demomavenspring2.configure.FooProperties",
      "name": "my-app.my-module.foo.min-height",
      "description": "foo min height description.",
      "type": "java.lang.Integer"
    },
    {
      "sourceType": "com.example.demomavenspring2.configure.FooProperties",
      "name": "my-app.my-module.foo.name",
      "description": "foo name description.",
      "type": "java.lang.String"
    }
  ]
}

この状態で基本的なコード補完ができるようになっています。
コード補完はこの図のようになります。表示されているプロパティの説明文はJavaDocが利用されます。

cc2.png

コード補完をカスタマイズする

コード補完をカスタマイズするにはMETA-INFディレクトリ下にadditional-spring-configuration-metadata.jsonという名前でカスタマイズ用のメタデータファイルを作成します。
このファイルはコンパイル時にspring-configuration-metadata.jsonへマージされます。

既定値の中から選択したい場合

例えばnameプロパティの値を既定値の中から選択したい場合、additional-spring-configuration-metadata.jsonに次のヒントを設定することでnameプロパティの値を"simple","combine","complex"から選択できるようになります。

additional-spring-configuration-metadata.json
{
  "hints" [
    {
      "name": "my-app.my-module.foo.name",
      "values": [
        {
          "value": "simple",
          "description": "simple module description."
        },
        {
          "value": "combine",
          "description": "combine module description."
        },
        {
          "value": "complex",
          "description": "complex module description."
        }
      ]
    }
  ]
}

既定値がコード補完されるようになりました。

cc3.png

既定値以外を入力すると警告メッセージが表示されます。

cc4.png

既定値に加え任意の値を設定したい場合

既定値に加え任意の値を指定できるようにすることもできます。次のように"providers"要素を追加します。

additional-spring-configuration-metadata.json
{
  "hints" [
    {
      "name": "my-app.my-module.foo.name",
      "values": [
        // 省略
      ],
      "providers": [
        {
          "name": "any"
        }
      ]
    }
  ]
}

既定値がコード補完されつつ、且つ既定値以外も設定できるようになりました。

cc5.png

Enumを使用する

既定値から選択させたい場合、もっと簡単な方法はフィールドの型にEnumを使用することです。
この方法ではadditional-spring-configuration-metadata.jsonの編集は不要です。

/**
 * foo color description.
 */
@NotNull
private Color color;
/**
 * color description.
 */
public enum Color {
    /**
     * red description.
     */
    RED,
    /**
     * green description.
     */
    GREEN,
    /**
     * blue description.
     */
    BLUE,
    /**
     * yellow description.
     */
    YELLOW,
    /**
     * cyan description.
     */
    CYAN,
    /**
     * magenta description.
     */
    MAGENTA
}

コード補完

cc6.png

コレクションを使用する

注意点

フィールドがコレクション型の場合、設定ファイルのフォーマット(.properties or .yml)の違いによりいくつか問題が出ます。

List型

フィールドがList型で、その要素にEnumを使用した場合、メタデータのヒントは不要です。

/**
 * foo colors description.
 */
private List<Color> colors = new ArrayList<>();

コード補完

cc7.png

注意点(1)

コード補完されるようになるのですが、Enumに定義されていない値を指定してもIDE上ではエラーになりません。
この例ではEnumに定義されていない"white"を指定してもエラーになりません。

cc8.png

ただ、実行時にプロパティのバインドで失敗してエラーになります。

***************************
APPLICATION FAILED TO START
***************************

Description:

Failed to bind properties under 'my-app.my-module.foo.colors[2]' to com.example.demomavenspring2.Color:

    Property: my-app.my-module.foo.colors[2]
    Value: white
    Origin: class path resource [application.yml]:76:11
    Reason: Failed to convert from type [java.lang.String] to type [com.example.demomavenspring2.Color] for value 'white'; nested exception is java.lang.IllegalArgumentException: No enum constant com.example.demomavenspring2.Color.white

Action:

Update your application's configuration. The following values are valid:

    BLUE
    CYAN
    GREEN
    MAGENTA
    RED
    YELLOW

注意点(2)

.properties形式のファイルでList型のプロパティに複数の値を記述する場合、カンマ区切りで値を記述することができますが、コード補完が有効だとIDE上でエラー扱いになります。(アプリケーションの実行には問題なくプロパティはバインドされます。)

my-app.my-module.foo.colors=red, green, blue

cc0.png

この場合は次のように配列形式で記述することで回避できます。冗長ですがコード補完が有効です。

my-app.my-module.foo.colors[0]= red
my-app.my-module.foo.colors[1]= green
my-app.my-module.foo.colors[2]= blue

cc1.png

Set型

フィールドがSet型で、その要素にEnumを使用した場合は、メタデータのヒントが必要です。

/**
 * foo colors description.
 */
private Set<Color> colors = new HashSet<>();

Enumの列挙子がコード補完されるようにするには以下のヒントを記述します。

{
  "hints": [
    {
      "name": "my-app.my-module.foo.colors",
      "providers": [
        {
          "name": "handle-as",
          "parameters": {
            "target": "com.example.demomavenspring2.Color"
          }
        }
      ]
    }
  ]
}

注意点(1)

List同様にコード補完はされますが、Enumに定義されていない値を指定してもエラーにならいないので注意が必要です。

注意点(2)

List同様にカンマ区切りで複数の値を記述するとIDE上ではエラー扱いになります。
(アプリケーションの実行には問題ありません。)

my-app.my-module.foo.colors= red, green, blue

また、Listのときの回避策である配列形式で記述すると実行時にエラーになるので使えません。

プロパティを非推奨にする

あるプロパティの利用が非推奨であることをIDE上で表示させることができます。
アクセサにDeprecatedアノテーションを付け、getterにDeprecatedConfigurationPropertyアノテーションを付けます。
reason属性に非推奨の理由を記述することもできます。
(additional-spring-configuration-metadata.jsonの編集は不要です。)

/**
 * foo budget description.
 */
private Long budget;

@DeprecatedConfigurationProperty(reason = "reason not to use budget.")
@Deprecated
public Long getBudget() {
    return budget;
}

@Deprecated
public void setBudget(Long budget) {
    this.budget = budget;
}

コード補完時に取り消し線が表示されます。

cc9.png

アノテーションに指定した非推奨の理由が表示されます。

cca.png

マップを使用する

/**
 * foo parts description.
 */
private Map<Part, State> parts = new HashMap<>();
public enum Part {
    UPPER,
    LOWER,
    RIGHT,
    LEFT
}

public enum State {
    START,
    STOP,
    SUSPEND
}
.properties形式の場合

キーと値にEnum型を使った場合、メタデータのヒント無しでコード補完ができます。

cc2.png

cc3.png

.yml形式の場合

.yml形式ではキーと値にEnum型を使った場合、キーのコード補完が期待通りに動きませんでした。

cc4.png

注意点(1)

キーにEnumに定義されていない値を記述してもIDE上ではエラー扱いになりません。
この例の"middle"というキーはEnum Partには定義されていません。

cc5.png

マップの値をString型にして既定値をコード補完させる
/**
 * foo parts description.
 */
private Map<Part, String> parts = new HashMap<>();

マップの値をコード補完させるには、メタデータにヒントを記述します。
name属性にはプロパティ名(この例ではparts)に続けて".values"を付加します。

additional-spring-configuration-metadata.json
{
  "hints": [
    {
      "name": "my-app.my-module.foo.parts.values",
      "values": [
        {
          "value": "TRUE",
          "description": "parts enable description."
        },
        {
          "value": "FALSE",
          "description": "parts disable description."
        }
      ]
    }
  ]
}

コード補完

cc6.png

cc7.png

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?