SIer だけど技術やりたいブログ

SpringBoot @Valueで任意の型にセットする CustomPropertyEditorの作成

Java SpringBoot Spring

はじめに

Springには外部定義から値を読み込んで、Javaのフィールドにセットする機能がある。

application.propertiesにメッセージを記述し、

message=hello

Javaクラスで利用すると、

@Service
public MessageServiceImpl implements MessageService {

@Value("${message}")
String message;

public void say() {
    //helloが出力される
    System.out.println(message);  
}

}

詳細はTERASOLUNAガイドラインがわかりやすい。
5.10. プロパティ管理 — TERASOLUNA Server Framework for Java (5.x) Development Guideline 5.1.0.RELEASE documentation

またSpringBootでは、外部ファイルのほかにも環境変数やJNDIなど、様々なところから値をとってこれる。Spring Boot Features

@Valueの詳細

外部定義の値(String)からJavaの型へのマッピングはPropertyEditorで行われる。
デフォルトで定義されているPropertyEditorは以下の通り。
詳細はリファレンスを参照。http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-beans-conversion

  • ByteArrayPropertyEditor
  • ClassEditor
  • CustomBooleanEditor
  • CustomCollectionEditor
  • CustomDateEditor
  • CustomNumberEditor
  • FileEditor
  • InputStreamEditor
  • LocaleEditor
  • PatternEditor
  • PropertiesEditor
  • StringTrimmerEditor
  • URLEditor

上記で処理できない型にマッピングしようとすると、ConversionNotSupportedExceptionがスローされる。

Caused by: org.springframework.beans.ConversionNotSupportedException: Failed toconvert value of type [java.lang.String] to required type [java.nio.file.Path];
nested exception is java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.nio.file.Path]: no matching editorsor conversion strategy found
        at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverterSupport.java:74)
        at org.springframework.beans.TypeConverterSupport.convertIfNecessary(TypeConverterSupport.java:54)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1033)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1014)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:545)
        ... 24 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [java.nio.file.Path]: no matching editors or conversion strategy found
        at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:302)
        at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:125)
        at org.springframework.beans.TypeConverterSupport.doConvert(TypeConverte
rSupport.java:61)
        ... 28 more

マッピングする型を増やす方法

JavaのPathを例に説明する。

1. マッピングさせたい型のPropertyEditor を作る。

package com.example.path;

import java.beans.PropertyEditorSupport;
import java.nio.file.Paths;

public class PathPropertyEditor extends PropertyEditorSupport{
  @Override
  public void setAsText(String text) throws IllegalArgumentException {
    this.setValue(text == null?null: Paths.get(text));
  }
}

2. PropertyEditorを登録する。

@SpringBootApplication
public class PathPropertyEditorApplication {

  public static void main(String[] args) {
    SpringApplication.run(PathPropertyEditorApplication.class, args);
  }

  @Bean
  public CustomEditorConfigurer getCustomEditorConfigurer(){
    CustomEditorConfigurer configurer = new CustomEditorConfigurer();
    Map<Class<?>, Class<? extends PropertyEditor>> map = new HashMap<>();
    map.put(Path.class, PathPropertyEditor.class);
    configurer.setCustomEditors(map);
    return configurer;
  }
}

実行してみる。

@Component
public class Application implements CommandLineRunner {
  @Value(("${home.dir}"))
  Path path;

  @Override
  public void run(String... strings) throws Exception {
    System.out.println("----------------");
    System.out.println(path);
    System.out.println("----------------");
  }
}

実行結果

----------------
\tmp
----------------

これで外部定義した文字列を任意のJavaの型にマッピングできる。

サンプル

サンプル書いた。
https://github.com/kimullaa/path-property-editor