user7700138
user7700138

Reputation: 123

Spring Boot - @Value returning null

I'm trying to use @Value annotation and auto-populate my variable from the properties file, but with no luck. Values are not being set and are null.

taskService.java

@Service
public class TaskService {
    @Value("${a}")
    String aa;

    public final RestTemplate restTemplate;

    public TaskService(RestTemplateBuilder restTemplateBuilder){
        System.out.println("----------xxxxxxxxxxx-------------" +aa);
        this.restTemplate = restTemplateBuilder.build();
    }

    public Task getTask(int taskId) throws TaskDoesNotExistException {
        try {
            return this.restTemplate.getForObject("/tasks/{taskId}", Task.class, taskId);
        } catch (HttpClientErrorException e) {
            if(e.getRawStatusCode() == 404)
                throw new TaskDoesNotExistException("Task not found", e);
        }
        return null;
    }
}

eventhandler.java

@Component
@RepositoryEventHandler(Application.class)
public class ApplicationRepositoryEventHandler {

    @Autowired
    TaskService taskService;

    @HandleBeforeCreate
    public void handleApplicationCreate(Application application) throws TaskDoesNotExistException {
        for (Integer taskId: application.getTasks()){
            taskService.getTask(taskId);
        }
    }
}

Upvotes: 2

Views: 11388

Answers (6)

WesternGun
WesternGun

Reputation: 12807

It is because you don't define a constructor with aa as argument, neither does the class have a setter, so there is no way to inject it.

Please read https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#beans-setter-injection.

Upvotes: 0

Gondy
Gondy

Reputation: 5305

You code can't work because Spring needs to first create instance of class (call the constructor) and THEN inject values to the fields.

public TaskService(RestTemplateBuilder restTemplateBuilder, ){
        System.out.println("----------xxxxxxxxxxx-------------" +aa); // 1
        this.restTemplate = restTemplateBuilder.build();
    }

1) in this moment there is no way Spring can inject value to the fields

Fix it like this:

@Service
public class TaskService {

    private final String aa;

    private final RestTemplate restTemplate;

    public TaskService(RestTemplateBuilder restTemplateBuilder, @Value("${a}" String aa){
        this.aa = aa;
        System.out.println("----------xxxxxxxxxxx-------------" +this.aa); // 1
        this.restTemplate = restTemplateBuilder.build();
    }

Upvotes: 0

Ganesh
Ganesh

Reputation: 1

 public TaskService(@Value("${a}") String aa, RestTemplateBuilder restTemplateBuilder){
        System.out.println("----------xxxxxxxxxxx-------------" +aa);
        this.restTemplate = restTemplateBuilder.build();
    }

Upvotes: 0

hameiste
hameiste

Reputation: 41

Quite often the problem is that the field injection is finished after the constructor has finished. That means you can access the value that was injected with @Value only after that. If a method getAA() ist added to TaskService:

public String getAA() {
 return aa;
}

and this method is called, the value of aa is not null, because the constructor was executed before and the field injection of @Value("${a}") set the value.

Upvotes: 0

surya
surya

Reputation: 2749

First check if your property file is loaded, Normally beginning of your output log, you should see name of the property file.

And then configure following bean in one of your configuration file, if not already done . This bean resolves '${}' in @Value.

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

Then use the way you are doing, It should resolve that property.And make sure that, TaskService bean is actually loaded (component scan package should includes this class)

Although i normally use above way, there is another way, you may need to check (just fyi, above should work)

 @Autowired
 private Environment env

Then use property wherever needed

 env.getRequiredProperty(“some.property”)

Upvotes: 0

Magnus
Magnus

Reputation: 8310

Field injection occurs after the object is constructed.
See https://stackoverflow.com/a/6336013/1544715
Just inject aa via the constructor along with the testTemplateBuilder.
In general you should avoid field injection, or at least try and only use one type of injection per class.

Upvotes: 4

Related Questions