web-dev-qa-db-ja.com

Spring Boot-application.ymlからマップを挿入します

Spring Boot 以下のapplication.ymlのアプリケーションがあります-基本的に here から取得:

info:
   build:
      artifact: ${project.artifactId}
      name: ${project.name}
      description: ${project.description}
      version: ${project.version}

特定の値を注入できます。

@Value("${info.build.artifact}") String value

ただし、マップ全体、つまり次のようなものを挿入したいと思います。

@Value("${info}") Map<String, Object> info

それ(または同様のもの)は可能ですか?もちろん、yamlを直接読み込むことはできますが、Springで既にサポートされているものがあるのではないかと思っていました。

75
levant pied

@ConfigurationPropertiesを使用してマップを挿入できます。

import Java.util.HashMap;
import Java.util.Map;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAutoConfiguration
@EnableConfigurationProperties
public class MapBindingSample {

    public static void main(String[] args) throws Exception {
        System.out.println(SpringApplication.run(MapBindingSample.class, args)
                .getBean(Test.class).getInfo());
    }

    @Bean
    @ConfigurationProperties
    public Test test() {
        return new Test();
    }

    public static class Test {

        private Map<String, Object> info = new HashMap<String, Object>();

        public Map<String, Object> getInfo() {
            return this.info;
        }
    }
}

質問のyamlでこれを実行すると、以下が生成されます。

{build={artifact=${project.artifactId}, version=${project.version}, name=${project.name}, description=${project.description}}}

プレフィックスの設定、欠落しているプロパティの処理方法の制御など、さまざまなオプションがあります。詳細については、 javadoc を参照してください。

60
Andy Wilkinson

以下のソリューションは、@ Andy Wilkinsonのソリューションの短縮形です。ただし、個別のクラスまたは@Beanアノテーション付きメソッドを使用する必要はありません。

application.yml:

input:
  name: raja
  age: 12
  somedata:
    abcd: 1 
    bcbd: 2
    cdbd: 3

SomeComponent.Java:

@Component
@EnableConfigurationProperties
@ConfigurationProperties(prefix = "input")
class SomeComponent {

    @Value("${input.name}")
    private String name;

    @Value("${input.age}")
    private Integer age;

    private HashMap<String, Integer> somedata;

    public HashMap<String, Integer> getSomedata() {
        return somedata;
    }

    public void setSomedata(HashMap<String, Integer> somedata) {
        this.somedata = somedata;
    }

}

@Valueアノテーションと@ConfigurationPropertiesの両方をクラブできます。問題はありません。ただし、ゲッターとセッターは重要であり、@EnableConfigurationPropertiesが機能するには@ConfigurationPropertiesが必要です。

@Szymon Stepniakが提供するグルーヴィーなソリューションからこのアイデアを試しました。誰かに役立つと思いました。

84
raksja

今日同じ問題に遭遇しましたが、残念ながらアンディのソリューションはうまくいきませんでした。 Spring Boot 1.2.1.RELEASEではさらに簡単ですが、いくつかの点に注意する必要があります。

application.ymlの興味深い部分は次のとおりです。

oauth:
  providers:
    google:
     api: org.scribe.builder.api.Google2Api
     key: api_key
     secret: api_secret
     callback: http://callback.your.Host/oauth/google

providersマップにはマップエントリが1つしか含まれていません。私の目標は、他のOAuthプロバイダーに動的構成を提供することです。このマップを、このyamlファイルで提供された設定に基づいてサービスを初期化するサービスに挿入します。私の最初の実装は:

@Service
@ConfigurationProperties(prefix = 'oauth')
class OAuth2ProvidersService implements InitializingBean {

    private Map<String, Map<String, String>> providers = [:]

    @Override
    void afterPropertiesSet() throws Exception {
       initialize()
    }

    private void initialize() {
       //....
    }
}

アプリケーションの起動後、OAuth2ProvidersServiceprovidersマップが初期化されませんでした。 Andyが提案した解決策を試しましたが、うまくいきませんでした。そのアプリケーションではGroovyを使用しているので、privateを削除し、Groovyにゲッターとセッターを生成させることにしました。したがって、私のコードは次のようになりました。

@Service
@ConfigurationProperties(prefix = 'oauth')
class OAuth2ProvidersService implements InitializingBean {

    Map<String, Map<String, String>> providers = [:]

    @Override
    void afterPropertiesSet() throws Exception {
       initialize()
    }

    private void initialize() {
       //....
    }
}

その小さな変更の後、すべてが機能しました。

言及する価値があるかもしれないものが1つありますが。動作させた後、このフィールドをprivateにして、setterメソッドでセッターにストレート引数タイプを提供することにしました。残念ながらそれは機能しません。次のメッセージでorg.springframework.beans.NotWritablePropertyExceptionが発生します。

Invalid property 'providers[google]' of bean class [com.zinvoice.user.service.OAuth2ProvidersService]: Cannot access indexed value in property referenced in indexed property path 'providers[google]'; nested exception is org.springframework.beans.NotReadablePropertyException: Invalid property 'providers[google]' of bean class [com.zinvoice.user.service.OAuth2ProvidersService]: Bean property 'providers[google]' is not readable or has an invalid getter method: Does the return type of the getter match the parameter type of the setter?

Spring BootアプリケーションでGroovyを使用している場合は、注意してください。

15
Szymon Stepniak

構成からマップを取得するには、構成クラスが必要です。残念ながら、@ Valueアノテーションではうまくいきません。

Application.yml

entries:
  map:
     key1: value1
     key2: value2

構成クラス:

@Component
    @ConfigurationProperties("entries")
    @Getter
    @Setter
    public static class MyConfig {
        private Map<String, String> map;
    }
5
Orbite
foo.bars.one.counter=1
foo.bars.one.active=false
foo.bars[two].id=IdOfBarWithKeyTwo

public class Foo {

  private Map<String, Bar> bars = new HashMap<>();

  public Map<String, Bar> getBars() { .... }
}

https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-Configuration-Binding

2
emerson moura