4
votes

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);
3
add a slash before application.propertiesJens
Or you can just autowire Environment which is a Properties-type bean containing all values from the filerorschach
With Environment you can get the properties, but it doesn't have a list of all properties. you only can use env.getProperty("propertyName") to get the propertyArsen Davtyan
For Can this be done ? , what is the result of your experiment?Sabir Khan
However, the Environment is very likely a ConfigurableEnvironment, which allows you to iterate the property sources, and you can iterate the properties of any PropertySource that is an EnumerablePropertySource. --- The advantage of using Environment is that you gain support for features like Profiles and YAML. But the question is: Why do you need to iterate them? Don't you know the names of the properties that are of interest to you?Andreas

3 Answers

1
votes

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;
    }
}
0
votes

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;
}
0
votes

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