nocoder
nocoder

Reputation: 99

Loading application.properties file to java.util.Properties in Spring Boot

I read through the Spring Boot documentation for externalized configuration and I see that it automatically loads the src/main/resources/application.properties file which can be then wired to the bean properties using annotation.

However I want to have a generic PropertyHelper class which can be used to build the java.util.Properties with the properties in application.properties. Can this be done?

We are currently achieving this manually as below:

public class PropertyHelper {

    private static Properties loadProperties() {
        try {

             String propsName = "application.properties";
             InputStream propsStream = PropertyHelper.class
                    .getClassLoader().getResourceAsStream(propsName);
            if (propsStream == null) {
                throw new IOException("Could not read config properties");
            }

            Properties props = new Properties();
            props.load(propsStream);

Upvotes: 4

Views: 9222

Answers (3)

Zon
Zon

Reputation: 19918

Inject application context arguments in constructor and relay it into java.util.properties:

import java.util.Properties;
import org.springframework.boot.ApplicationArguments;

public MyComponentClass(ApplicationArguments arguments) {

  Properties properties = getProperties(arguments);
}

private static Properties getProperties(ApplicationArguments arguments) {

  Properties properties = new Properties();

  for (String argementName : arguments.getOptionNames()) {

    List<String> argumentValues = arguments.getOptionValues(argementName);

    if (argumentValues.size() > 0) {
      properties.put(argementName, argumentValues.get(0));
    }
  }

  return properties;
}

Upvotes: 0

Leif John
Leif John

Reputation: 818

Here is how I derive a Properties object from Spring's Environment. I look for property sources of type java.util.Properties, which in my case will give me system properties and application properties.

@Resource
private Environment environment;


@Bean
public Properties properties() {
    Properties properties = new Properties();

    for (PropertySource<?> source : ((ConfigurableEnvironment) environment).getPropertySources()) {
        if (source.getSource() instanceof Properties) {
            log.info("Loading properties from property source " + source.getName());
            Properties props = (Properties) source.getSource();
            properties.putAll(props);
        }
    }

    return properties;
}

Note however that the order may be significant; you would probably want to load the system properties after other properties, so they can override application properties. In that case, add some more control code using source.getName() to pick out "systemProperties":

@Bean
public Properties properties() {
    Properties properties = new Properties();

    Properties systemProperties = null;

    for (PropertySource<?> source : ((ConfigurableEnvironment) environment).getPropertySources()) {
        if (source.getSource() instanceof Properties) {
            if ("systemProperties".equalsIgnoreCase(source.getName())) {
                log.info("Found system properties from property source " + source.getName());
                systemProperties = (Properties) source.getSource();
            } else {
                log.info("Loading properties from property source " + source.getName());
                Properties props = (Properties) source.getSource();
                properties.putAll(props);
            }
        }
    }

    // Load this at the end so they can override application properties.
    if (systemProperties != null) {
        log.info("Loading system properties from property source.");
        properties.putAll(systemProperties);
    }

    return properties;
}

Upvotes: 0

alexbt
alexbt

Reputation: 17085

You could create a Wrapper around Environment, which would return a ready-to-use PropertySource:

You would use it this way:

@PropertySource(name="myName", value="classpath:/myName.properties")
public class YourService {

    @Autowired
    private CustomMapProperties customMapProperties;
    ...
    MapPropertySource mapPropertySource = customMapProperties.getMapProperties("myName");
    for(String key: mapPropertySource.getSource().keySet()){
        System.out.println(mapPropertySource.getProperty(key));
    }

CustomMapProperties is injected with Environment and returns the request & loaded property file based on its name:

@Component
public class CustomMapProperties {

    @Autowired
    private Environment env;

    public MapPropertySource getMapProperties(String name) {
        for (Iterator<?> it = ((AbstractEnvironment) env).getPropertySources().iterator(); it.hasNext();) {
            Object propertySource = it.next();
            if (propertySource instanceof MapPropertySource
                    && ((MapPropertySource) propertySource).getName().equals(name)) {
                return (MapPropertySource) propertySource;
            }
        }
        return null;
    }
}

Upvotes: 1

Related Questions