Reputation: 123
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
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
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
Reputation: 1
public TaskService(@Value("${a}") String aa, RestTemplateBuilder restTemplateBuilder){
System.out.println("----------xxxxxxxxxxx-------------" +aa);
this.restTemplate = restTemplateBuilder.build();
}
Upvotes: 0
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
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
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