Spring Boot: inyecta el mapa de la aplicación.yml

Tengo una aplicación Spring Boot con la siguiente application.yml – tomada básicamente desde aquí :

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

Puedo inyectar valores particulares, por ejemplo

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

Me gustaría, sin embargo, inyectar todo el mapa, es decir algo como esto:

 @Value("${info}") Map info 

¿Es eso (o algo similar) posible? Obviamente, puedo cargar yaml directamente, pero me preguntaba si hay algo que ya sea compatible con Spring.

Puede inyectar un mapa utilizando @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 info = new HashMap(); public Map getInfo() { return this.info; } } } 

Ejecutar esto con el yaml en la pregunta produce:

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

Hay varias opciones para establecer un prefijo, controlar cómo se manejan las propiedades que faltan, etc. Consulte el javadoc para obtener más información.

La siguiente solución es una abreviatura de la solución de @Andy Wilkinson, excepto que no tiene que usar una clase separada o un método @Bean anotado.

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 somedata; public HashMap getSomedata() { return somedata; } public void setSomedata(HashMap somedata) { this.somedata = somedata; } } 

Podemos @Value tanto la anotación @ConfigurationProperties como @ConfigurationProperties , sin problemas. Pero getters y setters son importantes y @EnableConfigurationProperties es imprescindible para que @ConfigurationProperties funcione.

Intenté esta idea a partir de la solución maravillosa proporcionada por @Szymon Stepniak, pensé que sería útil para alguien.

Me encuentro con el mismo problema hoy, pero lamentablemente la solución de Andy no funcionó para mí. En Spring Boot 1.2.1.RELEASE es aún más fácil, pero debes tener en cuenta algunas cosas.

Aquí está la parte interesante de mi 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 mapa de providers contiene solo una entrada de mapa, mi objective es proporcionar una configuración dinámica para otros proveedores de OAuth. Quiero insertar este mapa en un servicio que inicializará los servicios según la configuración proporcionada en este archivo yaml. Mi implementación inicial fue:

 @Service @ConfigurationProperties(prefix = 'oauth') class OAuth2ProvidersService implements InitializingBean { private Map> providers = [:] @Override void afterPropertiesSet() throws Exception { initialize() } private void initialize() { //.... } } 

Después de iniciar la aplicación, el mapa de providers en OAuth2ProvidersService no se inicializó. Intenté con la solución sugerida por Andy, pero no funcionó tan bien. Utilizo Groovy en esa aplicación, así que decidí eliminar private y dejar que Groovy genere getter y setter. Entonces mi código se veía así:

 @Service @ConfigurationProperties(prefix = 'oauth') class OAuth2ProvidersService implements InitializingBean { Map> providers = [:] @Override void afterPropertiesSet() throws Exception { initialize() } private void initialize() { //.... } } 

Después de ese pequeño cambio, todo funcionó.

Aunque hay una cosa que vale la pena mencionar. Después de hacerlo funcionar, decidí hacer que este campo fuera private y proporcionarle a setter un tipo de argumento recto en el método setter. Desafortunadamente no funcionará eso. Causa org.springframework.beans.NotWritablePropertyException con mensaje:

 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? 

Téngalo en cuenta si está usando Groovy en su aplicación Spring Boot.

 foo.bars.one.counter=1 foo.bars.one.active=false foo.bars[two].id=IdOfBarWithKeyTwo public class Foo { private Map bars = new HashMap<>(); public Map getBars() { .... } } 

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

Para recuperar el mapa de la configuración, necesitará una clase de configuración. La anotación @Value no funcionará, desafortunadamente.

Application.yml

 entries: map: key1: value1 key2: value2 

Clase de configuración:

 @Component @ConfigurationProperties("entries") @Getter @Setter public static class MyConfig { private Map map; }