Spring @Value
December 09, 2023
1. Spring @Value
annotation is used at field level for expression-driven dependency injection.
2.
@Value
is also used at parameter level of a method or a constructor that indicates a default value expression for the affected argument.
3.
@Value
is also used for dynamic resolution of handler method parameters like in Spring MVC.
4.
@Value
can be used within classes annotated with @Configuration
, @Component
and other stereotype annotations.
5. The actual processing of
@Value
annotation is performed by BeanPostProcessor
and so we cannot use @Value
within BeanPostProcessor
types.
6.
@Value
uses ${...}
and #{...}
syntax to write expressions. ${...}
is a property placeholder syntax and #{...}
is a SpEL syntax. #{...}
syntax can also handle property placeholders and a lot more.
We read property file using
@PropertySource
annotated at JavaConfig and resolve dependency injection using @Value
annotation. Here we will discuss using @Value
in detail.
Contents
1. Using ${...}
${...}
is a property placeholder syntax. It is used with @Value
as following.
AppConfig.java
@Configuration @PropertySource("classpath:myproject.properties") public class AppConfig { @Value("${cp.user.name}") private String userName; ------ }
cp.user.name= Shree Mahesh
@PropertySource
reads the property file that contains cp.user.name
property key. The value of this property will be injected to userName
field by @Value
.
We can also assign hard-coded value to a field using
@Value
annotation.
@Value("India") private String userCountry;
userCountry
field will injected with specified value.
2. Using #{...}
#{...}
is a SpEL syntax. It handles property placeholders and a lot more.
@Value("#{systemProperties['java.home']}") private String mySystemVal;
systemProperties
provides system property values such as file.separator
, java.home
, os.name
etc. In the above code @Value
will inject the value of java.home
to mySystemVal
field.
3. Default Value
To specify default value for@Value
, we need to use colon (:)
with ${...}
syntax and Elvis Operator (?:)
with #{...}
syntax to write expression.
1. We need to use colon
(:)
to specify default value with ${...}
syntax. Suppose we have a property file myproject.properties
. In our JavaConfig, we read property file with @PropertySource
annotation.
AppConfig.java
@Configuration @PropertySource("classpath:myproject.properties") public class AppConfig { @Value("${cp.user.name:Shree Mahesh}") private String userName; ------ }
cp.user.role
property is not defined in property file, the default value Shree Mahesh will be injected to userName
field. To specify default value with ${...}
syntax, we need not to enclose default value with single quotes ('').
If we prefix a space to default value after
:
, then that will be included in default value. If we suffix a space to default value before }
, it will also be included in default value. Look into the following code snippet.
a. No space as prefix and suffix.
${cp.user.name:Shree Mahesh}
${cp.user.name: Shree Mahesh}
${cp.user.name: Shree Mahesh }
2. If we want to pick default value from property file then we can use
${...}
syntax as following.
@Value("${cp.user.role:${cp.user.role.default}}") private String userRole;
cp.user.role
property is not defined in property file, the default value will be injected to userRole
picking it from cp.user.role.default
property.
3. To specify default value with
#{...}
SpEL syntax, we need to use Elvis Operator (?:)
as following.
@Value("#{systemProperties['unknown_prop_key'] ?: 'Default System Value'}") private String mySystemVal;
mySystemVal
.
4. To assign a
null
value as default, we can specify #{null}
as following.
@Value("${cp.user.country:#{null}}") private String userCountry;
cp.user.country
is not defined in property file, then userCountry
will be injected with null
value.
4. Boolean Value
Suppose we have a property key value as true/false in property file.cp.user.active= true
@Value
as following.
@Value("${cp.user.active}") private Boolean isUserActive;
@Value("${cp.user.active:true}") private Boolean isUserActive;
cp.user.active
property is not defined in property file, then true will be injected to isUserActive
.
5. Integer Value
Suppose we have a property key with integer value.cp.user.age= 50
@Value
as following.
@Value("${cp.user.age}") private Integer userAge;
@Value("${cp.user.age:30}") private Integer userAge;
cp.user.age
property is not defined in property file, then 30 will be injected to userAge
.
6. With Array
Suppose we have following property key in property file with comma separated value.cp.user.skills= Java, Spring, Angular
Array
type field using @Value
as following.
@Value("${cp.user.skills}") private String[] userSkills;
${...}
syntax as following.
@Value("${cp.user.skills:Java,Spring,Angular}") private String[] userSkills;
cp.user.skills
property is not defined in property file, the default array will be injected to userSkills
.
In the same way, we can inject primitive datatype integer array as default value, too.
@Value("${cp.user.skillids:5,6,7}") private int[] userSkillIds;
7. With List
Suppose we have following property key in property file with comma separated value.cp.user.skills= Java, Spring, Angular
List
type field using @Value
with #{...}
SpEL syntax and ${...}
syntax as following.
@Value("#{'${cp.user.skills}'.split(',')}") private List<String> userSkills;
@Value("#{'${cp.user.skills:Java,HTML,Spring}'.split(',')}") private List<String> userSkills;
cp.user.skills
property is not defined in property file, the default list will be injected to userSkills
.
8. With Map
Suppose we have following key in property file.cp.user.teamMates= {100: 'Krishna', 200: 'Shiva'}
Map
type field using @Value
as following.
@Value("#{${cp.user.teamMates}}") private Map<Integer, String> teamMates;
#{...}
SpEL syntax with ${...}
syntax as following.
@Value("#{${cp.user.teamMates: {100: 'Krishna', 200: 'Shiva'}}}") private Map<Integer, String> teamMates;
cp.user.teamMates
property is not defined in property file, the default map will be injected to teamMates
.
9. With @Component
@Value
can be used within classes annotated with @Configuration
, @Component
and other stereotype annotations.
Suppose we have a property file with some properties.
myproject.properties
cp.user.name= Shree Mahesh cp.user.actiontype= Write
AppConfig.java
@Configuration @PropertySource("classpath:myproject.properties") public class AppConfig { ------ }
@Value
annotation.
UserAction.java
@Component public class UserAction { @Value("${cp.user.name}") private String userName; @Value("${cp.user.actiontype}") private String actionType; ------ }
10. Constructor Injection
@Value
can be used with constructor parameter and then in constructor injection, Spring will inject value specified by @Value
annotation. Suppose we have following properties in property file.
myproject.properties
cp.company.name= ABC Ltd #cp.company.location= Delhi
AppConfig.java
@Configuration @PropertySource("classpath:myproject.properties") public class AppConfig { ------ }
CompanyService.java
@Service public class CompanyService { private String compName; private String location; public CompanyService(@Value("${cp.company.name}") String compName, @Value("${cp.company.location:Varanasi}") String location) { this.compName = compName; this.location = location; } ------ }
11. With Enum
We can useenum
with @Value
annotation. A field or constructor parameter can be injected with enum
value using @Value
annotation.
Find a sample
enum
file.
Designation.java
public enum Designation { MANAGER, DEVELOPER, TESTER; }
Suppose we have a property file with following property.
myproject.properties
cp.user.designation= DEVELOPER
enum
field as following.
UserAction.java
@Component public class UserAction { @Value("${cp.user.designation}") protected Designation designation; ------ }
12. With @ImportResource
We can use@Value
with @ImportResource
. Suppose we have an XML configuration that has imported property file using util:properties
.
app-conf.xml
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:util="http://www.springframework.org/schema/util" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <util:properties id="userProp" location="classpath:myproject.properties" /> </beans>
#{...}
syntax, we can fetch value from userProp
as following.
AppConfig.java
@Configuration @ImportResource("classpath:app-conf.xml") public class AppConfig { @Value("#{userProp['cp.user.name']}") private String userName; @Value("#{userProp['cp.user.role']?: 'Admin'}") private String userRole; ------ }
13. JUnit Test
In our JUnit test cases, we can inject test class fields using@Value
as following.
MySpringAppTest.java
@ExtendWith(SpringExtension.class) @ContextConfiguration(classes = AppConfig.class) @TestPropertySource("/myproject.properties") public class MySpringAppTest { @Value("${cp.user.name}") private String userName; @Value("${cp.user.country:India}") private String userCountry; @Test public void userNameTest() throws Exception { assertTrue("Shree Mahesh".equals(userName)); } @Test public void userCountryTest() throws Exception { assertTrue("USA".equals(userCountry)); } }
14. Complete Example
Find the project structure.myproject.properties
cp.user.name= Shree Mahesh cp.user.country= USA cp.user.role.default= Contributor cp.user.role= Moderator cp.user.active= true #cp.user.age= 50 cp.user.skills= Java, Spring, Angular cp.user.teamMates= {100: 'Krishna', 200: 'Shiva'} cp.company.name= ABC Ltd cp.company.location= Delhi cp.user.actiontype= Write cp.user.designation= DEVELOPER
package com.concretepage; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; import org.springframework.context.annotation.PropertySource; @Configuration @PropertySource("classpath:myproject.properties") @ComponentScan("com.concretepage") //@ImportResource("classpath:app-conf.xml") public class AppConfig { @Value("${cp.user.name}") private String userName; // @Value("#{userProp['cp.user.name']}") // private String userName; // @Value("#{userProp['cp.user.role']?: 'Admin'}") // private String userRole; @Value("${cp.user.role:Admin}") private String userRole; @Value("India") private String userCountry; @Value("${cp.user.active:false}") private Boolean isUserActive; @Value("${cp.user.age:30}") private Integer userAge; @Value("#{systemProperties['java.home']}") private String mySystemVal; @Value("#{'${cp.user.skills:Java,HTML,Spring}'.split(',')}") private List<String> userSkills; @Value("#{${cp.user.teamMates: {300: 'Mahesh', 400: 'Surya'}}}") private Map<Integer, String> teamMates; @Bean public User getUser() { User user = new User(); user.setUserName(userName); user.setUserRole(userRole); user.setUserCountry(userCountry); user.setUserActive(isUserActive); user.setUserAge(userAge); user.setMySystemVal(mySystemVal); user.setUserSkills(userSkills); user.setTeamMates(teamMates); return user; } }
package com.concretepage; import java.util.List; import java.util.Map; public class User { private String userName; private String userRole; private String userCountry; private Boolean userActive; private Integer userAge; private String mySystemVal; private List<String> userSkills; private Map<Integer, String> teamMates; //Setters and Getters }
package com.concretepage; public enum Designation { MANAGER, DEVELOPER, TESTER; }
package com.concretepage; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class UserAction { @Value("${cp.user.name}") private String userName; @Value("${cp.user.actiontype}") private String actionType; @Value("${cp.user.designation}") protected Designation designation; public void show() { System.out.println(userName); System.out.println(actionType); System.out.println(designation); } }
package com.concretepage; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class CompanyService { private String compName; private String location; public CompanyService(@Value("${cp.company.name}") String compName, @Value("${cp.company.location:Varanasi}") String location) { this.compName = compName; this.location = location; } public void showCompanyDetails() { System.out.println("Company Name: "+ compName); System.out.println("Company Location: "+ location); } }
package com.concretepage; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class MySpringApp { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); ctx.scan("com.concretepage"); ctx.refresh(); User user = ctx.getBean(User.class); System.out.println("userName: " + user.getUserName()); System.out.println("userRole: " + user.getUserRole()); System.out.println("userCountry: " + user.getUserCountry()); System.out.println("userActive: " + user.getUserActive()); System.out.println("userAge: " + user.getUserAge()); System.out.println("mySystemVal: " + user.getMySystemVal()); System.out.println("userSkills: " + user.getUserSkills()); System.out.println("teamMates: " + user.getTeamMates()); System.out.println("---UserAction---"); UserAction userAction = ctx.getBean(UserAction.class); userAction.show(); System.out.println("---CompanyService---"); CompanyService compService = ctx.getBean(CompanyService.class); compService.showCompanyDetails(); ctx.registerShutdownHook(); ctx.close(); } }
userName: Shree Mahesh userRole: Moderator userCountry: India userActive: true userAge: 30 mySystemVal: C:\Program Files\Java\jdk-11.0.1 userSkills: [Java, Spring, Angular] teamMates: {100=Krishna, 200=Shiva} ---UserAction--- Shree Mahesh Write DEVELOPER ---CompanyService--- Company Name: ABC Ltd Company Location: Delhi