Spring Boot - Resolve Application Properties Programmatically

This tutorial shows you how to read or resolve the values of application property placeholders in a Spring Boot application programmatically.

You may already know that Spring supports loading environment variables from an application.properties or application.yml file. If you define a property value correctly, you should be able to read it using @Value annotation. It's the responsibility of Spring to resolve and inject the value. However, you may find cases where you want to get the value of a property, but it's not possible to use the @Value annotation. For example, if you have a custom annotation whose attribute value depends on a property which requires you to write a custom code for resolving the value.

While you can write a code for parsing the file that contains the property list, you don't need to do that because Spring already provides some methods that can be used for that purpose. Below are the examples.

Resolve Application Properties Using EmbeddedValueResolverAware Interface

To resolve the value of an application property in a Spring Bean class, you can utilize the EmbeddedValueResolverAware interface. You can make a class to be registered as a Spring Bean by adding @Component, @Service, @Repository, or @Controller annotation to the class. The class needs to implement EmbeddedValueResolverAware.

To implement the interface, you have to override the following method.

  void setEmbeddedValueResolver(StringValueResolver resolver);

When the application is being started, Spring finds all classes that implement the interface. Then, the method will be invoked with an instance of StringValueResolver. Inside the method, most likely you'll need to store the passed resolver instance to a class variable. Therefore, you can use it later when necessary.

  @Service
  public class MyService implements EmbeddedValueResolverAware {
  
    private StringValueResolver embeddedValueResolver;
  
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
      this.embeddedValueResolver = resolver;
    }
  }

StringValueResolver has a method named resolveStringValue which can be used to resolve the value of an application property. You need to pass the property name in the placeholder format (e.g. "${your.property-name}"). It's the same format used by @Value annotation. If the property is defined, Spring will return the value as a String.

For example, we have the following property.

  config.my-value=Woolha.com

The code below shows you how to resolve a property value using StringValueResolver.

  String value = this.embeddedValueResolver.resolveStringValue("${config.my-value}");

Below is another example with an undefined property.

  String value = this.embeddedValueResolver.resolveStringValue("${config.undefined-prop}");

If the resolveStringValue method is unable to resolve the value, it will throw an IllegalArgumentException.

  java.lang.IllegalArgumentException: Could not resolve placeholder 'config.undefined-prop' in value "${config.undefined-prop}"

To handle that case, you can set a default value to be used if the property is undefined. It can be added by adding : after the property name, followed by the default value.

  String value = this.embeddedValueResolver.resolveStringValue("${config.undefined-prop:java}");
  System.out.println("value: " + value);

Here's the full code of the class.

  @Service
  public class MyService implements EmbeddedValueResolverAware {
  
    private StringValueResolver embeddedValueResolver;
  
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
      this.embeddedValueResolver = resolver;
    }
  
    public void resolveExistingProp() {
      String value = this.embeddedValueResolver.resolveStringValue("${config.my-value}");
      System.out.println("value: " + value); // Woolha.com
    }
  
    public void resolveUndefinedProp() {
      String value = this.embeddedValueResolver.resolveStringValue("${config.undefined-prop}");
      System.out.println("value: " + value); // Throw IllegalArgumentException
    }
  
    public void resolveUndefinedPropWithDefaultValue() {
      String value = this.embeddedValueResolver.resolveStringValue("${config.undefined-prop:java}");
      System.out.println("value: " + value); // java
    }
  }

Resolve Application Properties Using Environment

In a Spring Boot application, you have access to an Environment object . Environment is an interface representing the environment in which the current application is running. Accessing the Environment object is quite easy as it can be injected to a Spring Bean class.

The Environment interface has a method named resolvePlaceholders. It can be used to resolve the value of an application property. The format of the property name is the same as the resolveStringValue method of StringValueResolver. It must be in the "${your.property-name}" format and it supports default value as well. The difference is it doesn't throw an exception if the property name cannot be resolved, unless the passed argument is null. Instead, it will return the passed argument unchanged.

  @Service
  public class MyComponent {
  
    private final Environment environment;
  
    public MyComponent(Environment environment) {
      this.environment = environment;
    }
  
    public void resolveExistingProp() {
      String value = this.environment.resolvePlaceholders("${config.my-value}");
      System.out.println("value: " + value); // Woolha.com
    }
  
    public void resolveUndefinedProp() {
      String value = this.environment.resolvePlaceholders("${config.undefined-prop}");
      System.out.println("value: " + value); // ${config.undefined-prop}
    }
  
    public void resolveUndefinedPropWithDefaultValue() {
      String value = this.environment.resolvePlaceholders("${config.undefined-prop:java}");
      System.out.println("value: " + value); // java
    }
  }

The Environment interface has another method named resolveRequiredPlaceholders that throws an IllegalArgumentException if the property cannot be resolved.

  public void resolveExistingProp() {
    String value = this.environment.resolveRequiredPlaceholders("${config.my-value}");
    System.out.println("value: " + value); // Woolha.com
  }

  public void resolveUndefinedProp() {
    String value = this.environment.resolveRequiredPlaceholders("${config.undefined-prop}");
    System.out.println("value: " + value); // Throw IllegalArgumentException
  }

  public void resolveUndefinedPropWithDefaultValue() {
    String value = this.environment.resolveRequiredPlaceholders("${config.undefined-prop:java}");
    System.out.println("value: " + value); // java
  }

Resolve Application Properties in a Non-Bean Class

Sometimes, it's necessary to access the property value in a class that's not a Spring Bean. A little workaround is needed in that case. For example, you want to get a StringValueResolver instance in a utility class not managed by Spring. A simple solution is by creating a Spring Bean class that stores the StringValueResolver instance in a static variable. The class has to provide a public static getter as well, so that it can be accessed from any class.

  @Component
  public class EmbeddedValueResolverProvider implements EmbeddedValueResolverAware {
  
    private static StringValueResolver embeddedValueResolver;
  
    @Override
    public void setEmbeddedValueResolver(StringValueResolver resolver) {
      EmbeddedValueResolverProvider.embeddedValueResolver = resolver;
    }
  
    public static StringValueResolver getEmbeddedValueResolver() {
      return embeddedValueResolver;
    }
  }

Below is the example of how to access the StringValueResolver to resolve a property value.

  public class MyUtil {
  
    private MyUtil() {
      throw new AssertionError();
    }
  
    public static void test() {
      String value = EmbeddedValueResolverProvider.getEmbeddedValueResolver()
          .resolveStringValue("${config.my-value:java}");
      System.out.println("value: " + value);
    }
  }

Summary

There are several ways to resolve the value of an application property programmatically in Spring Boot. You can create a Spring Bean class that implements EmbeddedValueResolverAware. Then, use the resolveStringValue method of the passed StringValueResolver instance. It can also be done by using the resolvePlaceholders or resolveRequiredPlaceholders method of Environment.