Spring @Value Annotation Guide
In this article, we’ll learn how to inject values for Primitives, List, Map, and Date with inline values and from property file using @Value Annotation with examples. We’ll also see its usage with Constructor-based & Setter-based Injection, and SpEL.
@Value annotation is used for injecting values into fields in a spring-managed beans. The value typically come from:-
- Inline Values
- Property Files ((.properties and .yml files))
- System Properties
- Environment Variables
Inject Inline values using @Value Annotation
Let’s look at the quick examples for how to inject inline values for String
, Integer
, Float
, Double
, Boolean
, and List
using @Value
annotation. Injecting inline values for Map
, Date
, LocalDate
, LocalDateTime
requires SpEL (Spring Expression Language) to use inside @Value
annotation.
@Configuration
public class InlineConfig {
@Value("How to use @Value Annotation with inline values")
private String title;
@Value("30")
private Integer duration;
@Value("4.5")
private Float rating;
@Value("1e+10")
private Double pageViews;
@Value("true")
private Boolean isTrending;
@Value("Spring, Spring Boot, Annotation")
private List<String> tags;
// SpEL expression used to initialize a Map
@Value("#{{'keyword1': '12', 'keyword2': '44', 'keyword3': '85', 'keyword4': '100'}}")
private Map<String, Integer> keywordCountMap;
// Inject Date with given format using SpEL expression
@Value("#{new java.text.SimpleDateFormat('yyyyMMdd').parse('20210530')}")
private Date createdDate;
// Inject LocalDate with ISO_DATE format using SpEL expression
@Value("#{T(java.time.LocalDate).parse('2021-05-31')}")
private LocalDate updatedDate;
// Inject LocalDateTime with ISO_LOCAL_DATE_TIME format using SpEL expression
@Value("#{T(java.time.LocalDateTime).parse('2015-08-04T10:11:30')}")
private LocalDateTime lastAccess;
}
Inject values from Property file using @Value Annotation
application.properties
course.title = "How to use Spring @Value annotation"
course.duration = 30
course.rating = 4.5
course.page_views = 1e+10
course.trending = true
We can set the values of primitive fields such as String, int, float, double and boolean from property file as below:-
@Configuration
public class CourseConfig {
@Value("${course.title}")
private String title;
//How to use Spring @Value annotation
@Value("${course.duration}")
private int duration;
//30
@Value("${course.rating}")
private float rating;
//4.5
@Value("${course.page_views}")
private double pageViews;
//1.0E10
@Value("${course.trending}")
private boolean isTrending;
//true
}
Concat multiple properties in @Value Annotation
Two or more properties can be concatenated from property file like below:-
@Configuration
public class CourseConfig {
@Value("${course.title} (${course.rating})")
private String titleAndRating;
//How to use Spring @Value annotation (4.5)
@Value("${course.title} - ${course.duration} min")
private String titleAndDuration;
//How to use Spring @Value annotation - 30 min
}
Inject with Default values using @Value Annotation
Default values can be provided for properties that might not be defined using below syntax:
@Value("${property: defaultValue}")
For example, property course.review
is not defined so review field will be initialized with default value i.e. “No Reviews Yet”.
@Value("${course.review: No Reviews Yet}")
private String review;
Inject List using @Value Annotation
application.properties
application.properties
course.tags = Java, Spring, Spring Boot, Annotation
Any property having comma separated values can be initialized as a List using @Value
annotation in latest version of Spring.
// Comma separated property values auto initialize a List
@Value("${course.tags}")
private List<String> tags;
Using SpEL expression with List
If you are using older version of Spring, then you need to use SpEL expression to initialize a List:
@Value("#{'${course.tags}'.split(',')}")
private List<String> tags;
SpEL expression can also be used to get specific value from comma separated values:
@Value("#{'${course.tags}'.split(',')[0]}")
private String firstTag;
Inject Map using @Value Annotation
application.properties
course.keyword_count = { 'keyword1': '12', 'keyword2': '44', 'keyword3': '85', 'keyword4': '100'}
Note*: the keys and values in the property Map must be in single quotes ' '
.
We can initialize a Map with above property using SpEL expression inside @Value
annotation
// SpEL expression used to initialize a Map
@Value("#{${course.keyword_count}}")
private Map<String, Integer> keywordCountMap;
Inject Value of specific Key from Map
If we need to get the value of a specific key from Map, all we have to do is add the key’s name in the expression:
We can use any one out of these two ways:-
// way 1 - .key
@Value("#{${course.keyword_count}.keyword1}")
private Integer FirstKeywordCount;
// way 2 - ['key']
@Value("#{${course.keyword_count}['keyword2']}")
private Integer SecondKeywordCount;
If we’re not sure whether the Map contains a certain key, we should choose a safer expression that will not throw an exception but set the value to null when the key is not found:
@Value("#{${course.keyword_count}['unknownKey']}")
private Integer unknownKeywordCount;
Inject Map with Default Value
We can also set default values for the properties or keys that might not exist:
@Value("#{${unknownMap : {key1: '1', key2: '2'}}}")
private Map<String, Integer> unknownMap;
@Value("#{${course.keyword_count}['unknownKey'] ?: 100}")
private Integer unknownKeyWithDefaultValue;
Inject Filtered Map Entries
Map entries can also be filtered before injection. Let’s assume we need to get only those entries whose keyword count is greater than 50:
@Value("#{${course.keyword_count}.?[value > '50']}")
private Map<String, Integer> keywordCountMapFiltered;
Inject Date using @Value Annotation
application.properties
course.created_date = 20210530
course.updated_date = 2021-05-31
course.last_access = 2015-08-04T10:11:30
There is no direct support to initialize Date
, LocalDate
, and LocalDateTime
fields using @Value
annotation. We need to use SpEL (Spring Expression Language) inside @Value
annotation to parse the String based property.
// Inject Date with given format using SpEL expression
@Value("#{new java.text.SimpleDateFormat('yyyyMMdd').parse('${course.created_date}')}")
private Date createdDate;
// Inject LocalDate with ISO_DATE format using SpEL expression
@Value("#{T(java.time.LocalDate).parse('${course.updated_date}')}")
private LocalDate updatedDate;
// Inject LocalDateTime with ISO_LOCAL_DATE_TIME format using SpEL expression
@Value("#{T(java.time.LocalDateTime).parse('${course.last_access}')}")
private LocalDateTime lastAccess;
Inject System Properties using @Value Annotation
We can initialize fields from system properties using @Value
annotation in a similar way as they were defined in a property file. Let’s see examples:-
//UTF-8
@Value("${file.encoding}")
private String fileEncoding;
//Mac OS X
@Value("${os.name}")
private String osName;
// /Users/ashishkumarlahoti
@Value("${user.home}")
private String userHome
Inject all System Properties
We can also use the @Value
annotation to inject all current system properties like this:-
@Value("#{systemProperties}")
private Map<String, String> systemPropertiesMap;
Output
systemPropertiesMap: {
"os.name" : "Mac OS X",
"os.version" : "10.15.7",
"user.name" : "ashl",
"user.country" : "SG",
"user.language" : "en",
"user.timezone" : "Asia/Singapore",
"user.home" : "/Users/ashl",
"user.dir" : "/Users/ashl/IdeaProjects/springboot-examples/springboot-demo",
"file.encoding" : "UTF-8",
"file.separator" : "/",
"line.separator" : "\n",
"path.separator" : ":",
"java.version" : "11.0.10",
"java.vendor" : "Oracle Corporation",
"java.home" : "/Library/Java/JavaVirtualMachines/jdk-11.0.10.jdk/Contents/Home",
"catalina.home" : "/private/var/folders/6p/3ztts6bd4xbdl7nkcq6lpcg80000gn/T/tomcat.8080.8199922893426879147"
}
Inject value of specific System property from Map
We can also use SpEL expressions to get the value from System Property Map:
// /Library/Java/JavaVirtualMachines/jdk1.8.0_211.jdk/Contents/Home/jre
@Value("#{systemProperties['java.home']}")
private String javaHome;
//Oracle Corporation
@Value("#{systemProperties['java.vendor']}")
private String javaVendor;
Inject System Property with default value
We can also initialize some default value if System property is not available:
@Value("#{systemProperties['unknown'] ?: 'Default Value'}")
private String unknownSystemProperty;
Constructor based Injection using @Value Annotation
When we use the @Value
annotation, we’re not limited to a field-based injection. We can use the @Value
annotation for constructor-based injection also.
Let’s see this in practice:
values.properties
priority = high
@Component
@PropertySource("classpath:values.properties")
public class PriorityProvider {
private String priority;
@Autowired
public PriorityProvider(@Value("${priority:normal}") String priority) {
this.priority = priority;
}
}
In the above example, we inject a property priority
directly into the constructor of PriorityProvider
. Note that we also provide a default value “normal” in case the priority
property is not found.
Setter based Injection using @Value Annotation
Similar to field-based and constructor-based injection, we can also use @Value
annotation for setter-based injection.
values.properties
listOfValues = first, second, third
@Component
@PropertySource("classpath:values.properties")
public class CollectionProvider {
private List<String> values = new ArrayList<>();
@Autowired
public void setValues(@Value("#{'${listOfValues}'.split(',')}") List<String> values) {
this.values.addAll(values);
}
}
In the code above, we use the SpEL expression to inject a list of values into the setValues method.
Inject Method Arguments using @Value Annotation
When the @Value
annotation is found on a method, Spring context will invoke it when all the spring configurations and beans are getting loaded. If the method has multiple arguments, then every argument value is mapped from the method annotation. If we want different values for different arguments then we can use @Value
annotation directly with the argument.
@Configuration
public class Config {
@Value("Test")
public void printValues(String a, String b){
System.out.println(a + " & " + b); // Test & Test
}
@Value("Test")
public void printOtherValues(String a, @Value("Another Test") String b){
System.out.println(a + " & " + b); // Test & Another Test
}
}
SpEL (Spring Expression Language) with @Value Annotation
We have already seen usage of SpEL with @Value
annotation to inject complex values such as List, Map, and Date where Spring boot doesn’t provide direct support. SpEL provides us flexibility to transform or parse the property value before injecting. Let’s see some more practical use cases:-
Inject Scheme, Host or Port from URL
application.properties
bootstrap.url = http://localhost:8080
@Value("#{new java.net.URI('${bootstrap.url}').getScheme()}")
private String scheme; //http
@Value("#{new java.net.URI('${bootstrap.url}').getHost()}")
private String host; //localhost
@Value("#{new java.net.URI('${bootstrap.url}').getPort()}")
private Integer port; //8080
Arithmetic Operations
@Value("#{((1 + 2^3 - 4) * (5 % 6)) / 7 }") // 3.0
private Double arithmeticOperation;
@Value("#{((1 + 2^3 - 4) * (5 mod 6)) div 7 }") // 3.0
private Double anotherArithmeticOperation;
@Value("#{'Hello ' + 'World'}") // "Hello World"
private String concatString;
We can use either -
div
or \
for DIVIDE operation,
mod
or %
for MODULO operation.
The +
operator can also be used to concatenate strings.
Relational Operations
// @Value("#{1 == 1}") true
@Value("#{1 eq 1}") // true
private boolean equal;
//@Value("#{1 != 1}") // false
@Value("#{1 ne 1}") // false
private boolean notEqual;
// @Value("#{1 < 1}") // false
@Value("#{1 lt 1}") // false
private boolean lessThan;
//@Value("#{1 <= 1}") // true
@Value("#{1 le 1}") // true
private boolean lessThanOrEqual;
//@Value("#{1 > 1}") // false
@Value("#{1 gt 1}") // false
private boolean greaterThan;
//@Value("#{1 >= 1}") // true
@Value("#{1 ge 1}") // true
private boolean greaterThanOrEqual;
We can use either -
eq
or ==
for EQUAL operation,
!=
or ne
for NOT EQUAL operation,
<
or lt
for LESS THAN operation,
>
or gt
for GREATER THAN operation,
<=
or le
for LESS THAN EQUAL TO operation,
>=
or ge
for GREATER THAN EQUAL TO operation
Logical Operations
//@Value("#{250 > 200 && 200 < 4000}") // true
@Value("#{250 > 200 and 200 < 4000}") // true
private boolean andOperation;
//@Value("#{400 > 300 || 150 < 100}") // true
@Value("#{400 > 300 or 150 < 100}") // true
private boolean orOperation;
//@Value("#{!true}") // false
@Value("#{not true}") // false
private boolean notOperation;
We can use either -
&&
or and
for AND operation,
||
or or
for OR operation,
!
or not
for NOT operation.
Conditional Operations
The ternary operator can be used inside the expression for conditional logic.
@Value("#{2 > 1 ? 'a' : 'b'}") // "a"
private String ternaryOperator;
Most common use case of ternary operator is to check for null and return default value.
@Autowired
private SomeBean someBean;
@Value("#{someBean.someProperty != null ? someBean.someProperty : 'default'}")
private String nullCheckUsingTernaryOperator;
SpEL also provide support for Elvis operator ?:
which is a shorthand of ternary operator for null check. Above example can be written using Elvis operator like this:-
@Value("#{someBean.someProperty ?: 'default'}") // Will inject provided string if someProperty is null
private String nullCheckUsingElvisOperator;
Summary
We learnt different ways to inject values using Spring @Value
annotation. We also understood the power and flexibility provided by SpEL to use expressions inside @Value
annotation.
Download the source code for all the examples from github/springboot-config