Spring @Value annotation in @Controller class not evaluating to value inside properties file

Viewed 107206

I am new to Spring and trying to inject a string with a value using the @Value("${loginpage.message}") annotation inside of a controller annotated with the @Controller annotation and the value of my string is being evaluated as the string "${loginpage.message}" and not what is inside my properties file.

Below is my controller with the string 'message' that I want to inject.

@Controller
public class LoginController extends BaseController {
    @Value("${loginpage.message}")
    private String message;

    @RequestMapping("/")
    public String goToLoginPage(Model model) {
        model.addAttribute("message", message);

        return "/login";
    }
}

My application context looks like this:

<context:property-placeholder location="classpath:properties/application.properties" />

<context:annotation-config />

<context:component-scan base-package="com.me.application" />

My properties file has the line:

loginpage.message=this is a test message

Spring must be picking up the value at some point because whenever I change @Value("${loginpage.message}") to a value not in the properties file like @Value("${notInPropertiesFile}"), I get an exception.

6 Answers

You need to use PropertySourcePlaceHolder if you are using @Value annotation because it can extract the value from a properties file. If you are using java config base you need to create a bean like this

@Bean
public static PropertySourcesPlaceholderConfigurer propertyConfigInDev() {
    return new PropertySourcesPlaceholderConfigurer();
}

Or if you are using xml based then declare the bean accordingly.

I'm sorry to ask the obvious, but how do you know that the @Value annotation is not working? One of the problems with the way Spring works is that the Bean pre-processing is carried out after construction of the Bean.

So if you were inspecting your Bean in the constructor with a debugger, you will not see the fields being set. You can add a method in your Bean called, say, audit() and annotate it with @PostConstruct and if you put a log statement in there, put a breakpoint on it, you should see the fields with their @Value values.

If you do that and you still do not see your @Value fields, then you might not even has scanned the Bean. A class that you think implements a Bean is still a Java class, which can be instantiated and will have its fields assigned null, if it is not being pre-processed.

To make sure your Beans are being scanned, the classes should have at least the @Component and you need to add the package of the classes to the @ComponentScan.

@ComponentScan(basePackages = { "com.example.springboot", "org.bilbo.baggins" })

If you don't have the source to the main() method is, which is where you can usually find @ComponentScan, then you can add a @Configuration class in the same package and add a @ComponentScan to that.

In this example, I have the @ComponentScan as a commented-out line in the wrong place (it should replace @ImportResources).

package com.example.springboot;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

// @ComponentScan(basePackages = { "com.example.springboot", "org.bilbo.baggins" })
@Configuration
@ImportResource({"classpath*:applicationContext.xml"})
public class Configurer {
}

I did that, to show how to use an XML file: applicationContext.xml. This contains a component-scan and creates a Bean.

(Note: only one package is stated to be scanned, component-scan seems to accumulate.)

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/sc
hema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/
beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema
/context/spring-context.xsd">

    <context:annotation-config />

    <context:component-scan base-package="org.bilbo.baggins" />
          <bean id="applicationProperties"
                      class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
                    <property name="location" value="classpath:application.properties" />
          </bean>
</beans>

It is useful to build a bean in the XML file, so that you list it and demonstrate that you have loaded the XML file. You can list the beans using the method String[] beanNames = ctx.getBeanDefinitionNames();

Related