Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using ConfigurationProperties to fill Map in generic way

I'm wondering, if there is a generic way to fill a map with properties you just know the prefix.

Assuming there are a bunch of properties like

namespace.prop1=value1 namespace.prop2=value2 namespace.iDontKnowThisNameAtCompileTime=anothervalue 

I'd like to have a generic way to fill this property inside a map, something like

@Component @ConfigurationProperties("namespace") public class MyGenericProps {     private Map<String, String> propmap = new HashMap<String, String>();      // setter and getter for propmap omitted      public Set<String> returnAllKeys() {         return propmap.keySet();     } } 

Or is there another convenient way to collect all properties with a certain prefix, instead of iterating over all PropertySources in the environment?

Thanks Hansjoerg

like image 323
Hansjoerg Wingeier Avatar asked Jun 25 '15 09:06

Hansjoerg Wingeier


People also ask

How do I inject a map from a Yaml file?

How to Inject a Map From a YAML File. Spring Boot has taken data externalization to the next level by providing a handy annotation called @ConfigurationProperties. This annotation is introduced to easily inject external properties from configuration files directly into Java objects.

What is the use of @ConfigurationProperties?

@ConfigurationProperties allows to map the entire Properties and Yaml files into an object easily. It also allows to validate properties with JSR-303 bean validation. By default, the annotation reads from the application.


2 Answers

As long as you're happy having every property added into the map, rather than just those that you don't know in advance, you can do this with @ConfigurationProperties. If you want to grab everything that's beneath namespace then you need to use an empty prefix and provide a getter for a map named namespace:

@ConfigurationProperties("") public class CustomProperties {      private final Map<String, String> namespace = new HashMap<>();      public Map<String, String> getNamespace() {         return namespace;     }  } 

Spring Boot uses the getNamespace method to retrieve the map so that it can add the properties to it. With these properties:

namespace.a=alpha namespace.b=bravo namespace.c=charlie 

The namespace map will contain three entries:

{a=alpha, b=bravo, c=charlie} 

If the properties were nested more deeply, for example:

namespace.foo.bar.a=alpha namespace.foo.bar.b=bravo namespace.foo.bar.c=charlie 

Then you'd use namespace.foo as the prefix and rename namespace and getNamespace on CustomProperties to bar and getBar respectively.

Note that you should apply @EnableConfigurationProperties to your configuration to enable support for @ConfigurationProperties. You can then reference any beans that you want to be processed using that annotation, rather than providing an @Bean method for them, or using @Component to have them discovered by component scanning:

@SpringBootApplication @EnableConfigurationProperties(CustomProperties.class) public class YourApplication {     // … } 
like image 50
Andy Wilkinson Avatar answered Oct 10 '22 17:10

Andy Wilkinson


In addition to this, my problem was that I didn't had multiple simple key/value properties but whole objects:

zuul:   routes:     query1:       path: /api/apps/test1/query/**       stripPrefix: false       url: "https://test.url.com/query1"     query2:        path: /api/apps/test2/query/**        stripPrefix: false        url: "https://test.url.com/query2"     index1:        path: /api/apps/*/index/**        stripPrefix: false        url: "https://test.url.com/index" 

Following Jake's advice I tried to use a Map with a Pojo like this:

@ConfigurationProperties("zuul") public class RouteConfig {     private Map<String, Route> routes = new HashMap<>();      public Map<String, Route> getRoutes() {         return routes;     }      public static class Route {         private String path;         private boolean stripPrefix;         String url;          // [getters + setters]     } } 

Works like a charm, Thanks!

like image 33
MMascarin Avatar answered Oct 10 '22 17:10

MMascarin