Spring @Value annotation tricks

Habeeb Okunade
6 min readFeb 29, 2020

Spring framework provides@Value annotation in the org.springframework.beans.factory.annotationpackage. This annotation is used at various level in our application either at field level for expression-driven dependency injection in which a value can be injected into a variable in a class or at the parameter level of a method or a constructor that indicates a default value expression for the main argument. It is also used for dynamic resolution of handler method parameters like in Spring MVC.

@Value annotation can be used within classes annotated with @Configuration, @Component and other stereotype annotations like @Controller, @Service etc. The actual processing of @Value annotation is performed by BeanPostProcessor and so @Value cannot be used within BeanPostProcessor class types.

@Value annotation uses property placeholder syntax ${...} and Spring Expression Language, SpEL, syntax #{$...} to formulate expressions. ${...} is a property placeholder syntax while#{$...} is a SpEL syntax. #{$...} syntax can also handle property placeholders and a lot more.

In this write-up, I will discuss some tricks in using @Value annotation in a sample Spring Boot application. Let go to https://start.spring.io/ to generate and bootstrap our project.

Choose Maven Project, Java as the language, give your project the group name and artefact Id. Select Spring Web as the only dependency for our project.

Spring project initializer page (https://start.spring.io/)

Click ‘Generate’ button to download the bootstrapped project as a zip file. Unzip the file and open it with your prefered IDE as a Maven project to download all the required dependencies.

The structure of the project. (Using IntelliJ IDE)

Create a new package, name it ‘controller’ and create a new class called ‘ValueController.java’. Make sure to have the following in it

ValueControler.java class

Here, I have annotated the class with @RestController a child of stereotype Controller so that the value annotation can inject and work properly.

1. @Value Placeholder Syntax @Value("")

package com.habeebcycle.springvalueannotation.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ValueController {

@Value("Hello World")
private String greetingMessage;

@GetMapping("")
public String sendGreeting(){
return greetingMessage;
}
}

The value annotation is used to hold the value for the variable greetingMessage. When the project is run and the endpoint http://localhost:8080 is hit, the world Hello World is displayed on the browser. This shows that the @Value annotation works very well with class variables to inject the default value at runtime. As it works with String data type, it also works for other primitives and wrapper types like int, double, boolean, Integer, Double and Boolean as shown below:

@Value("1.234")
private double doubleValue; //could be Double
@Value("1234")
private Integer intValue; //could be int
@Value("true")
private boolean boolValue; //could be Boolean
@Value("2000")
private long longValue;

2. @Value Property Placeholder Syntax ${...}

Most of the spring applications have a property file that is used to configure some values or properties in the application. SpringApplication loads properties from application.properties files in the classpath and add them to the Spring Environment. In the example above, the spring boot initializer has already bootstrapped application.properties file in the application under src/main/resource folder. Let’s create some properties and access them in the application using the @Value annotation.

#application.propertiesgreeting.message=Hello World!

We can use @Value("${...property's name}")annotation to access the above property in the Java class as follows:

package com.habeebcycle.springvalueannotation.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ValueController {

@Value("${greeting.message}")
private String greetingMessage;

@GetMapping("")
public String sendGreeting(){
return greetingMessage;
}
}

Hitting the endpoint http://127.0.0.1:8080 will display the variable greetingMesssage as Hello World! on the browser.

The property value is injected at runtime from the property file to the variable. If the property name is not present in the application.properties file, the application throws errors as shown below:

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-02-29 21:54:43.953 ERROR 2996 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'valueController': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'greeting.message' in value "${greeting.message}"

A default value can be provided to the annotation, which can be used if the property name in the @Value annotation is not present in the application.properties file. The implementation is shown below:

package com.habeebcycle.springvalueannotation.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class ValueController {

@Value("${greeting.message:Greeting not found!}")
private String greetingMessage;

@GetMapping("")
public String sendGreeting(){
return greetingMessage;
}
}

A colon : is placed in front of the property name and the default value is provided to the annotation. This tells the annotation to use the default value provided to it if the property name is not found in the application.properties file. Caution needs to be taken when providing the default value as to where the colon : is placed. If there is a space between the property name and colon : as shown @Value(“${greeting.message :Greeting not found!}”) , the default value provided will always be used even if the property name exists in the properties file. Therefore, space should not be inserted before the colon : as it might cause unexpected behaviour. This also applies to other primitives and wrapper types like int, double, boolean, Integer, Double and Boolean as shown below:

#application.propertiesmy.int.value=20
my.double.value=3.142
my.boolean.value=true
//In the Java file@Value("${my.int.value:0}")
private int intValue; //injects 20 at runtime
@Value("${my.double.value: 0.0}")
private double doubleValue; //injects 3.142 at runtime
//This takes the default value provided despite having the property //name in the properties file.
@Value("${my.boolean.value :false}")
private boolean boolValue; //injects false because of the space
//Property name not found in the properties file
@Value("${my.long.value:300}")
private long longValue; //injects 300 at runtime

3. @Value Property Placeholder Syntax ${...} with List of values

@Value("${…}") can be used to inject list values from properties file at runtime. Consider the properties file below:

#application.propertiesmy.weekdays=Mon,Tue,Wed,Thu,Fri//In the Java file@Value("${my.weekdays}")
private List<String> strList; // injects [Mon, Tue, Wed, Thu, Fri]
//Providing default value
@Value("${my.weekends:Sat,Sun,Fri}")
private List<String> strList2; // injects [Sat, Sun, Fri]

4. @Value Spring Expression Language Syntax #{${...}} with Map (Key-value pair)

@Value("#{${…}}")can be used to inject map key-value pair from properties file at runtime. The example below shows how to do this:

#application.propertiesdatabase.values={url: 'http://127.0.0.1:3306/', db: 'mySql', username: 'root', password: 'root'}

We can use SpEL as follows to inject the database.values property.

package com.habeebcycle.springvalueannotation.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

@RestController
public class ValueController {

@Value("#{${database.values}}")
private Map<String, String> dbValues;

@GetMapping("")
public Map getDBProps(){
return dbValues;
}
}

Hitting endpoint http://localhost:8080 will return the following output

{
"url": "http://127.0.0.1:3306/",
"db": "mySql",
"username": "root",
"password": "root"
}

To use the default value in case the property name is not found on the properties file.

@Value("#{${database.values: {url: 'http://127.0.0.1:3308/', db: 'mySql', username: 'root', password: ''}}}")
private Map<String, String> dbValues;

When database.values property is not defined in the properties file, the default map {url:'http://127.0.0.1:3308/', db:'mySql', username:'root', password:''}will be injected to the variable dbValues

5. @Value Construction Injection with @Value("${…}")

@Value can be used with constructor parameter and then in constructor injection, Spring will inject value specified by @Value annotation. Suppose we have the following properties in the properties file.

company.name= Scopesuite Pty ltd
#company.location= Sydney

We can use @Value annotation during construction as follows

package com.habeebcycle.springvalueannotation.service;import org.springframework.stereotype.Service;@Service
public class CompanyService {
private String compName;
private String location;

public CompanyService(@Value("${company.name}") String compName,
@Value("${company.location:Washington}") String location){

this.compName = compName;
this.location = location;
}
------
}

In the above constructor, the first argument will be injected using the value from the properties file. If the property key for the second argument is not found, the default value will be injected.

--

--

Habeeb Okunade

Innovative software development professional. Loves sharing knowledge and learning latest stacks. Expertise in microservices architecture using spring boot.