Max
Max

Reputation: 15975

How can I tell Spring to use a Java map to resolve property placeholder?

I have a Map<String, String> and I would like to tell Spring to use this when creating beans and resolving property placeholders. What is the easiest way to do this? Here is an example:

@Component
public class MyClass {
   private String myValue;

    @Autowired
    public MyClass(@Value("${key.in.map}") String myValue) {
        this.myValue = myValue;
    }

    public String getMyValue() {
        return myValue;
    }
}

public static void main(String[] args) {
    Map<String, String> propertyMap = new HashMap<>();
    propertyMap.put("key.in.map", "value.in.map");
    ApplicationContext ctx = ...;
    // Do something???
    ctx.getBean(MyClass.class).getMyValue(); // Should return "value.in.map"
}

Upvotes: 7

Views: 2387

Answers (3)

Sotirios Delimanolis
Sotirios Delimanolis

Reputation: 280132

Spring provides a MapPropertySource which you can register with your ApplicationContext's Environment (you'll need a ConfigurableEnvironment which most ApplicationContext implementations provide).

These registered PropertySource values are used by the resolvers (in order) to find a value for your placeholder names.

Here's a complete example:

@Configuration
@ComponentScan
public class Example {

    @Bean
    public static PropertySourcesPlaceholderConfigurer configurer() {
        PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
        // can also add it here
        //configurer.setPropertySources(propertySources);
        return configurer;
    }

    public static void main(String[] args) {
        Map<String, Object> propertyMap = new HashMap<>();
        propertyMap.put("key.in.map", "value.in.map");
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        MapPropertySource propertySource = new MapPropertySource("map-source", propertyMap);
        ctx.getEnvironment().getPropertySources().addLast(propertySource);
        ctx.register(Example.class);
        ctx.refresh();

        MyClass instance = ctx.getBean(MyClass.class);
        System.out.println(instance.getMyValue());
    }
}

@Component
class MyClass {
    private String myValue;
    @Autowired
    public MyClass(@Value("${key.in.map}") String myValue) {
        this.myValue = myValue;
    }
    public String getMyValue() {
        return myValue;
    }
}

Upvotes: 3

TheCodingFrog
TheCodingFrog

Reputation: 3514

I was able to achieve the similar functionality although may not what you're looking.

Here's my code:

application.properties

key.in.map=value.in.map

beans.xml

http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">

    <context:component-scan base-package="com.chatar" />
</beans:beans>

Config.java

package com.chatar.batch;

import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@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;
    }
}

MyClazz.java

package com.chatar.batch;

import java.util.Map;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Component;

@Component
public class MyClazz {
    @Value("#{mapper}")
    private Map<String, String> props;

    public Map<String, String> getProps() {
        return props;
    }

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

        System.out.println("Value:: " + context.getBean(MyClazz.class).getProps().get("key.in.map")); // Should return
    }
}

Output: Value:: value.in.map

Upvotes: -1

Max
Max

Reputation: 15975

Here is the solution I ended up using. I convert the Map to a properties file.

Map<String, String> propertyMap = ...;
Properties properties = new Properties();
properties.putAll(propertyMap);

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ConfigurableBeanFactory beanFactory = ctx.getBeanFactory();
PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer = new PropertySourcesPlaceholderConfigurer();
propertySourcesPlaceholderConfigurer.setProperties(properties);
beanFactory.registerSingleton(PropertySourcesPlaceholderConfigurer.class.getSimpleName(),
                    propertySourcesPlaceholderConfigurer);

Upvotes: 0

Related Questions