For Helidon MP..
I am observing some problem, in field injection, when accessed in constructor.
In below scenario, getting the null value in constructor, with or without @Inject over the constructor
The GreetingProvider
class is annotate with ApplicationScoped
@Inject
@ConfigProperty(name = "app.greeting")
private String message;
@Inject //Getting the field as null with or without @Inject annotation
public GreetingProvider() {
LOG.debug("Message {}, message);
}
Can get the value in the event listener for ApplicationScoped
.
It works fine if I used constructor based injection.
@Inject
public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) {
this.message.set(message);
}
Shouldn't the constructor get the initialised value from the field injection?
Expecting the initialised field injected with @ConfigProperty
to be accessible in constructor.
It is accessible in the method annotated with @PostConstruct
or method which observes the event activated(@Observes @Initialized(ApplicationScoped.class) final Object event)
.
Field values can only be injected once the object is instantiated. Instantiating the object requires a call to the constructor. So, if you think about this, your default constructor is invoked to build the instance of the object first and only post-construction are the fields injected in the order they are declared. This is why all the @Inject fields will be null when you access them through the default constructor.
The right way to handle this situation is through constructor injection, using @Inject on the constructor like in your second example.
@Inject
public GreetingProvider(@ConfigProperty(name = "app.greeting") String message) {
this.message.set(message);
}
Here, you are identifying the dependencies required by your class and CDI manager will ensure that the dependencies are passed into the constructor annotated with @Inject. You can now access the dependencies as formal arguments of the constructor and initialize the fields yourself.
The method annotated @PostConstruct OTOH is invoked only once per instance, and after the constructor, field and method injections have finished. If you have some logic to be executed once per instance @PostConstruct is the ideal way.
@PostConstruct
public void executeOncePerInstance(){
// You can safely access all the field & constructor-injected properties here
}
The behaviour would be similar to constructor injection, but some container implementations of CDI might invoke the constructor more than once during the process of setting up a Java proxy for the bean.