Using @Value

@Value is typically used to inject externalized properties:

  • Java

@Component
public class MovieRecommender {

    private final String catalog;

    public MovieRecommender(@Value("${catalog.name}") String catalog) {
        this.catalog = catalog;
    }
}

With the following configuration:

  • Java

@Configuration
@PropertySource("classpath:application.properties")
public class AppConfig {

}

And the following application.properties file:

catalog.name=MovieCatalog

In that case, the catalog parameter and field will be equal to the MovieCatalog value.

A default lenient embedded value resolver is provided by Infra. It will try to resolve the property value and if it cannot be resolved, the property name (for example ${catalog.name}) will be injected as the value. If you want to maintain strict control over nonexistent values, you should declare a PropertySourcesPlaceholderConfigurer bean, as the following example shows:

  • Java

@Configuration
public class AppConfig {

  @Bean
  public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() {
    return new PropertySourcesPlaceholderConfigurer();
  }
}
When configuring a PropertySourcesPlaceholderConfigurer using JavaConfig, the @Bean method must be static.

Using the above configuration ensures Infra initialization failure if any ${} placeholder could not be resolved. It is also possible to use methods like setPlaceholderPrefix, setPlaceholderSuffix, setValueSeparator, or setEscapeCharacter to customize placeholders.

Infra App configures by default a PropertySourcesPlaceholderConfigurer bean that will get properties from application.properties and application.yml files.

Built-in converter support provided by Infra allows simple type conversion (to Integer or int for example) to be automatically handled. Multiple comma-separated values can be automatically converted to String array without extra effort.

It is possible to provide a default value as following:

  • Java

@Component
public class MovieRecommender {

  private final String catalog;

  public MovieRecommender(@Value("${catalog.name:defaultCatalog}") String catalog) {
    this.catalog = catalog;
  }
}

A Infra BeanPostProcessor uses a ConversionService behind the scenes to handle the process for converting the String value in @Value to the target type. If you want to provide conversion support for your own custom type, you can provide your own ConversionService bean instance as the following example shows:

  • Java

@Configuration
public class AppConfig {

  @Bean
  public ConversionService conversionService() {
    DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
    conversionService.addConverter(new MyCustomConverter());
    return conversionService;
  }
}

When @Value contains a SpEL expression the value will be dynamically computed at runtime as the following example shows:

  • Java

@Component
public class MovieRecommender {

  private final String catalog;

  public MovieRecommender(@Value("#{systemProperties['user.catalog'] + 'Catalog' }") String catalog) {
    this.catalog = catalog;
  }
}

SpEL also enables the use of more complex data structures:

  • Java

@Component
public class MovieRecommender {

  private final Map<String, Integer> countOfMoviesPerCatalog;

  public MovieRecommender(@Value("#{{'Thriller': 100, 'Comedy': 300}}") Map<String, Integer> countOfMoviesPerCatalog) {
    this.countOfMoviesPerCatalog = countOfMoviesPerCatalog;
  }
}