Using ConfigurationProperties to fill Map in generic way

ghz 1years ago ⋅ 7555 views

Question

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


Answer

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 {
    // …
}