Bohemian
Bohemian

Reputation: 424973

Injecting a map of properties via @Value alone

How does one populate a map of values using the @Values annotation, without defining anything in applicationContext.xml or any other XML file.

I am using spring boot, which doesn't have any XML files, and nor do I want any XML files, so please don't tell me to declare any property reader beans in XML etc.

Also, this is a properties injection question - please don't suggest using a database to store the data - that's not an answer, and not possible for my situation anyway.

Also, I can't use YAML either (due to deployment/operational requirements).

I have tried declaring this injection:

@Value("${myprop}")
Map<Integer, String> map;

And this one

@Value("${myprop.*}")
Map<Integer, String> map;

with these entries application.properties:

myprop.1=One
myprop.2=Two
myprop.3=Three

and then tried

myprop[1]=One
myprop[2]=Two
myprop[3]=Three

But no good - just explodes with

Could not autowire field: ... Could not resolve placeholder 'myprop'

I have found a work-around with an injected String[] specified as key1:value1,key2:value2,... that I then parse in code, but I'd prefer to not do that because a) it's more code, and b) the list is going to be quite long, and all pairs on one line is going to be hard to read and maintain.

Is there a way to automatically build a map from several properties?

I don't care what the property names are, what the field type or the annotation is; I'm just trying to inject one key/value pair per property.

Upvotes: 3

Views: 3105

Answers (3)

Davide Castronovo
Davide Castronovo

Reputation: 1396

Hello for people serach a simply solution to this problem. 😄

put the sequent line to your application.properties:

myprop = "{1:'One',2:'Two',3:'Three'}"

then in your Spring application put the line:

@Value("#{${myprop}}")
Map<Integer, String> map;

Upvotes: 0

Andrei Stefan
Andrei Stefan

Reputation: 52368

Not sure if this applies to your scenario entirely (you have there a Map<Integer, String> but in the end you say you just need a key-value pair in a Map), but maybe it could give you some more ideas:

  • assuming a @Configuration class where the .properties file is loaded as a java.util.Properties object:
@Configuration
public class Config {

    @Bean(name = "mapper")
    public PropertiesFactoryBean mapper() {
        PropertiesFactoryBean bean = new PropertiesFactoryBean();
        bean.setLocation(new ClassPathResource("META-INF/spring/application.properties"));
        return bean;
    }

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}
  • the MyBean class where those Properties are being used, injected using SPeL:
public class MyBean {

    @Value("#{mapper}")
    private Map props;

    public Map getProps() {
        return props;
    }
}

So, in the end you don't use xml (of course), you need to use a PropertiesFactoryBean to load the .properties file and, using @Value, Spring will inject the Properties into a Map. The extra code (compared to, probably, @PropertySource) is the PropertiesFactoryBean and you don't need to parse the values in your code manually (compared to your workaround that injects a String[]).

Hope this helps.

Upvotes: 1

micha
micha

Reputation: 49542

How about defining a bean in your Java config for this?

@Bean
public Map<Integer, String> myProps(Properties properties) {
  Map<Integer, String> map = new HashMap<>();

  // implement logic to populate map from properties

  return map;
}

And in your class:

@Autowirded
Map<Integer, String> map;

Upvotes: 0

Related Questions