Did it ever happen to you that after spending some time and gaining experience with a framework or a programming language, you learn things that would have made your programmer's life much easier if you had known them right from the start? You would have done things differently, more quickly, in a simpler, cleaner and more maintainable way?
I decided to write a series of posts about features and aspects of Spring Framework (the framework in which I spend most of my professional software development time) that I found useful (usually far later than I'd like to admit :) ), but which are often not covered in entry level guides and tutorials.
In this first post I would like to discuss the @Value
annotation.
I started working with Spring framework since the 2.5 version. Later on, when 3.0 was released, JavaConfig became the part of the core framework along with the @Value
that was part of it. I unfortunately didn't notice that improvement for quite some time, mostly because the projects I worked on relied on XML based config.
Here's what Spring javadocs say about @Value
:
Annotation at the field or method/constructor parameter level that indicates a default value expression for the affected argument.
Typically used for expression-driven dependency injection. Also supported for dynamic resolution of handler method parameters, e.g. in Spring MVC.
A common use case is to assign default field values using "#{systemProperties.myProp}" style expressions.
Let's see how we can make use of it.
This is likely the most common use case for @Value
annotation. @Value
allows us to easily inject a value from a property file to, for example, a bean's field or a constructor argument.
If we had a property file that looks like this:
app.name = My Excellent Application
Then we could use that property definition in, say, a controller using@Value("${propertyName}")
syntax:
@Controller
public class HelloController {
@Value("${app.name}")
private String appName;
@RequestMapping("/")
@ResponseBody
public String hello() {
return "Hello from " + appName;
}
}
The code in the example will read the property app.name from property file and inject it into appName
field. The ${...}
syntax is Spring's property placeholder syntax used in property placeholder replacement mechanism. If app.name
is not defined, then an exception will be thrown. Which brings us to a less known fact about property placeholders - it's possible to set a default value for a property that Spring would use if the property is not defined. The syntax for default values in property placeholders is ${property:defaultValue}
. You can read about it the javadocs for PlaceholderConfigurerSupport class. I find default values quite useful, especially in situations where a particular property of a bean is not likely to be changed in different environments and as such you don't want to introduce it needlessly into a property file, but still want to give yourself an option to change your mind later. If we were to modify our example to use a default value, it would look like this:
@Controller
public class HelloController {
@Value("${app.name:My Excellent Application}")
private String appName;
@RequestMapping("/")
@ResponseBody
public String hello() {
return "Hello from " + appName;
}
}
Do you remember @Value
's javadoc that was shown previously? It described a #{...}
syntax rather than property replacement ${...}
syntax that we used in our example. What's the difference? The #{...}
syntax invokes Spring Expression Language (SpringEL) and evaluates the expression dynamically. For example we could obtain a value from the system settings:
@Value("#{systemSettings['user.region']}")
private String locale;
The above expression works because systemSettings is a variable that's always available to SpringEL when it's invoked in this context (e.g. when configuring beans).
We may even inject a return value of a method of another bean:
@Value("#{'V1.0S' + migrationService.version}")
private String version;
In this example Spring will inject string "V1.0S" prepended to the return value of method getVersion()
of a bean with name migrationService
(all beans in Spring's context are available as variables in SpringEL).
To conclude,@Value
annotation is indispensable asset when configuring your beans. When pursing convention-over-configuration style, default values for property placeholders used in@Value
configs may come in handy. And finally, always keep on your mind that you can invoke SpringEL to help you to simplify scenarios that may otherwise require complex config or workarounds.