
1. Overview
In this article, we will focus on Spring use property value in annotation-based configurations.
The @Value annotation helps to inject property values into fields, constructor, or method arguments from property files, system properties, environment variables, etc., @Value annotation also supports SpEL expression.
Let’s see few examples to understand this annotation.
2. Spring inject property value using @Value annotation
Consider you have a set of configurable properties in your application.properties file. If your application requires those properties, then we need to fetch those values and use them.
For example, the below reporting.email
property is present in the application.properties file and you need to get that property’s value in your Java code to send your reporting details in an email.
reporting.required=true reporting.email=contactus@tedblob.com
First, let’s load the key \ value property pairs from application.properties file to your application by using the @PropertySource annotation.
package com.tedblob.value; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; @Configuration @ComponentScan @PropertySource("classpath:application.properties") public class ApplicationConfiguration { }
After adding the property file as your application’s property source, now let’s inject the reporting.email
property into the Java field using the @Value annotation. The Spring’s default resolver resolves the property value and injects the email address into the Reporting
bean field accordingly.
package com.tedblob.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class Reporting { private final String emailAddress; public Reporting(@Value("${reporting.email}") String emailAddress) { this.emailAddress = emailAddress; } public void print() { System.out.println("Email Address : " + emailAddress);
If you call the print function on the reporting bean, then it prints the email address correctly.
package com.tedblob.value; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class Runner { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfiguration.class); context.registerShutdownHook(); Reporting reporting = context.getBean(Reporting.class); reporting.print(); } }
3. Error for missing properties
Assume you missed adding the reporting.email
property in your properties file but you are trying to inject it using @Value annotation. So, what would happen?
If the Spring cannot resolve the property, then it assigns the property name itself as value (${reporting.email}
).
reporting.required=true
So when you print the variable emailAddress
of reporting
bean, it will print the value as ${reporting.email}
Reporting reporting = context.getBean(Reporting.class); reporting.print();
Sometimes you do not want this default behavior instead prefer Spring to throw an error for the missing properties. You can achieve it by using the PropertySourcesPlaceholderConfigurer in your configuration class as below.
This configurer resolves the placeholders in the properties and attributes.
package com.tedblob.value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.PropertySourcesPlaceholderConfigurer; @Configuration @ComponentScan @PropertySource("classpath:application.properties") public class ApplicationConfiguration { @Bean public static PropertySourcesPlaceholderConfigurer propertyPlaceholderConfigurer() { return new PropertySourcesPlaceholderConfigurer(); } }
It also throws the below initialization failure when it cannot resolve the property.
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'reporting.email' in value "${reporting.email}"
4. Spring value annotation integer type conversion
Spring automatically performs the simple type conversion. For example, think you have the below properties in your file.
reporting.required=true reporting.email=contactus@tedblob.com reporting.reportCount=5
In the below code, we are trying to inject the property reporting.required
into the boolean argument and reporting.reportCount
into the int argument.
Spring’s build-in converter automatically converts the property value to the corresponding argument types boolean
and int
and injects them.
package com.tedblob.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class Reporting { private final String emailAddress; private final boolean required; private final int count; public Reporting(@Value("${reporting.email}") String emailAddress, @Value("${reporting.required}") boolean required, @Value("${reporting.reportCount") int count) { this.emailAddress = emailAddress; this.required = required; this.count = count; } public void print() { System.out.println("Email Address : " + emailAddress); System.out.println("Reporting required : " + required); System.out.println("Reporting count : " + count); } }
5. Spring value annotation list
Assume you have a list of admin users separated by commas in the property file as below.
admin.users=praj,siv,jb
We have more than one admin user here. @Value annotation can convert the multiple comma-separated property value to String array automatically. Thus, you need not spend any additional effort to get the admin users as an array in your code.
In the below code, we are injecting the admin.users
property into the array field users
. This code will work fine and prints Users : [praj, siv, jb]
package com.tedblob.value; import java.util.ArrayList; import java.util.Arrays; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class Admin { private final ArrayList<String> users; public Admin(@Value("${admin.users}") String[] users) { this.users = new ArrayList<String>(Arrays.asList(users)); } public void print() { System.out.println("Users : " + users.toString()); } }
6. Spring inject map from properties file
In the previous section, we have been injecting a list of values from the property file. Similarly, you can inject the map from the properties file with no additional effort from your end.
Assume you have a key \ value map for admin roles in your property file as below. If the map’s value is of type String, then you can use single or double quotes to enclose the map values. However, use single quotes for Integer values.
admin.roles={role1: 'high', role2: 'medium', role3: 'low'} (or) admin.roles={role1: "high", role2: "medium", role3: "low"} number.squares={1:'1', 2: '4', 3: '9'}
You can inject the above Map property into your Java field easily by using the @Value annotation and SpEL expression. In the below code, SpEL automatically converts the Map property to Java Map.
Note the SpEL syntax #{ }
around the ${admin.roles}
. It treats the ${admin.roles}
as an expression and converts it to Map.
package com.tedblob.value; import java.util.ArrayList; import java.util.Arrays; import java.util.Map; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class Admin { private final ArrayList<String> users; private final Map<String, String> roles; public Admin(@Value("${admin.users}") String[] users, @Value("#{${admin.roles}}") Map<String,String> roles) { this.users = new ArrayList<String>(Arrays.asList(users)); this.roles = roles; } public void print() { System.out.println("Users : " + users.toString()); System.out.println("Roles : " + roles.toString()); } }
7. SpEL with value annotation
@Value annotation supports SpEL expressions. Let’s see few examples for SpEL expression.
7.1. Spring get value from system property
You can set the system property on the Java command line using the -Dpropertyname=value syntax or at runtime using System.setProperty function.
To inject the value from the system property, annotate your field using the @Value annotation with SpEL expression as below. Then, the #{ expression } syntax of SpEL dynamically evaluates the expression at runtime.
package com.tedblob.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class HealthCheck { private final String healthcheck; public HealthCheck(@Value("#{systemProperties['healthcheck']}") String healthcheck) { this.healthcheck = healthcheck; } public void print() { System.out.println("healthcheck : " + healthcheck); } }
7.2. Spring boot get value from environment variable
Similar to system variables, you can also inject environment variables into your field or method arguments using the @Value annotation and SpEL expression.
@Value("#{systemEnvironment['JAVA_HOME']}") String javaHome;
The above @Value annotation looks for the System environment variable JAVA_HOME and then injects the value into the field javaHome
.
package com.tedblob.value; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component class HealthCheck { private final String healthcheck; private final String javaHome; public HealthCheck(@Value("#{systemProperties['healthcheck']}") String healthcheck, @Value("#{systemEnvironment['JAVA_HOME']}") String javaHome) { this.healthcheck = healthcheck; this.javaHome = javaHome; } public void print() { System.out.println("healthcheck : " + healthcheck); System.out.println(javaHome); } }
7.3. SpEL in @Value for complex expressions
You can also use SpEL for more complex operations. See the SpEL document for the complete list of functionalities supported.
@Value("#{'${admin.users}'.contains('praj')}") boolean isRole3Valid; @Value("#{{'Praj': 100, 'Siv': 300}}") Map<String, Integer> userList;
8. Conclusion
To sum up, we have focused on getting the properties using the Spring annotation value.
1 thought on “Spring use property value in annotation”