Spring @Value

By Arvind Rai, 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.

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;
  ------
} 
myproject.properties
cp.user.name= Shree Mahesh 
In the above code @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; 
The 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;
 ------
} 
When 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} 
b. Space as prefix. Space will be counted in default value.
${cp.user.name: Shree Mahesh} 
c. Space as prefix and suffix. Spaces will be counted in default value.
${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; 
When 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; 
In the above code snippet, for the demo, we are trying to fetch value from system properties for an unknown key. As the value will be null, so default value will be injected to mySystemVal.

4. To assign a null value as default, we can specify #{null} as following.
@Value("${cp.user.country:#{null}}")
private String userCountry; 
When 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 
We can inject them using @Value as following.
@Value("${cp.user.active}")
private Boolean isUserActive; 
Find code to specify Boolean default value.
@Value("${cp.user.active:true}")
private Boolean isUserActive; 
When 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 
We can inject them using @Value as following.
@Value("${cp.user.age}")
private Integer userAge; 
Find code to specify Integer default value.
@Value("${cp.user.age:30}")
private Integer userAge; 
When 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 
We can inject the comma separated value to Array type field using @Value as following.
@Value("${cp.user.skills}")	 
private String[] userSkills; 
To inject default array, we can use ${...} syntax as following.
@Value("${cp.user.skills:Java,Spring,Angular}")	
private String[] userSkills; 
When 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 
We can inject the comma separated value to List type field using @Value with #{...} SpEL syntax and ${...} syntax as following.
@Value("#{'${cp.user.skills}'.split(',')}")
private List<String> userSkills; 
Find the code snippet to inject default list value.
@Value("#{'${cp.user.skills:Java,HTML,Spring}'.split(',')}") 
private List<String> userSkills; 
When 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'} 
We can inject the above key/value to Map type field using @Value as following.
@Value("#{${cp.user.teamMates}}")
private Map<Integer, String> teamMates; 
To inject default map, we can use #{...} SpEL syntax with ${...} syntax as following.
@Value("#{${cp.user.teamMates: {100: 'Krishna', 200: 'Shiva'}}}")
private Map<Integer, String> teamMates; 
When 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 
Find the JavaConfig importing the property file.
AppConfig.java
@Configuration
@PropertySource("classpath:myproject.properties")
public class AppConfig {
------
} 
Now find the component. Here we have injected the value to the component fields using @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 
Find the JavaConfig importing the property file.
AppConfig.java
@Configuration
@PropertySource("classpath:myproject.properties")
public class AppConfig {
------
} 
Find the service that will be instantiated using constructor injection as following.
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;
   }
   ------
} 
In the above constructor, the first argument will be injected picking the value from property file. If the property key for the second argument is not available, default value will be injected.

11. With Enum

We can use enum 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 
Now inject value to 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> 
Using #{...} 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.
Spring @Value
Now find the complete code.
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 
AppConfig.java
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;
	 }
} 
User.java
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
} 
Designation.java
package com.concretepage;
public enum Designation {
    MANAGER,
    DEVELOPER,
    TESTER;
} 
UserAction.java
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);
	}
} 
CompanyService.java
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);	   
   }
} 
MySpringApp.java
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();
	}
} 
Output
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 

15. Reference

Spring Doc: @Value

16. Download Source Code

POSTED BY
ARVIND RAI
ARVIND RAI
LEARN MORE








©2024 concretepage.com | Privacy Policy | Contact Us