I would like to use #Value on a property but I always get 0(on int).
But on a constructor parameter it works.
Example:
#Component
public class FtpServer {
#Value("${ftp.port}")
private int port;
public FtpServer(#Value("${ftp.port}") int port) {
System.out.println(port); // 21, loaded from the application.properties.
System.out.println(this.port); // 0???
}
}
The object is spring managed, else the constructor parameter wouldn't work.
Does anyone know what causes this weird behaviour?
Field injection is done after objects are constructed since obviously the container cannot set a property of something which doesn't exist. The field will be always unset in the constructor.
If you want to print the injected value (or do some real initialization :)), you can use a method annotated with #PostConstruct, which will be executed after the injection process.
#Component
public class FtpServer {
#Value("${ftp.port}")
private int port;
#PostConstruct
public void init() {
System.out.println(this.port);
}
}
I think the problem is caused because Spring's order of execution:
Firstly, Spring calls the constructor to create an instance, something like:
FtpServer ftpServer=new FtpServer(<value>);
after that, by reflection, the attribute is filled:
code equivalent to ftpServer.setPort(<value>)
So during the constructor execution the attribute is still 0 because that's the default value of an int.
This is a member injection:
#Value("${ftp.port}")
private int port;
Which spring does after instantiating the bean from its constructor. So at the time spring is instantiating the bean from the class, spring has not injected the value, thats why you are getting the default int value 0.
Make sure to call the variable after the constructor have been called by spring, in case you want to stick with member injection.
Related
I'm trying to make a CDI extension which will validate a Java object which is bound to configuration values.
public class ExampleConfig {
#Range(min = 1000, max = 9999)
private int value;
#Inject
public ExampleConfig(#ConfigProperty(name = "value") int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
When I make the above class with the #Singleton annotation, it works correctly. On startup the CDI extension validates the class which reads an environment variable called "value".
Class: com.example.ExampleConfig
Property: value
Value: 22222
Reason: must be between 1000 and 9999
When I replace #Singleton with #ApplicationScoped instead, when injecting and using this class myself, it works as intended, but in the CDI extension, javax.validation.Validator appears to always treat the value as 0.
Class: com.example.ExampleConfig$Proxy$_$$_WeldClientProxy
Property: value
Value: 0
Reason: must be between 1000 and 9999
I'm struggling to see why this is the case, is anyone able to provide guidance on how to read the value correctly?
Two things I've been trying to achieve to no avail is:
Have the extension enforce initialization on startup for respective classes.
Make the CDI extension wait until the bean has initialized.
The following is how I'm calling #validate:
public void afterDeploymentValidation(#Observes AfterDeploymentValidation adv, BeanManager bm) {
Set<ConstraintViolation<?>> allViolations = new HashSet<>();
for (Class<?> type : types)
{
final Object typeImpl = BeanProvider.getContextualReference(bm, type, false);
Set<ConstraintViolation<?>> violations = (Set<ConstraintViolation<?>>)(Object)validator.validate(typeImpl);
allViolations.addAll(violations);
}
// Omitted for brevity.
}
Several things:
First of all, if all you're trying to do is get Bean Validation working, just put the Hibernate Validator CDI project on your runtime classpath. Nothing else needed; the end.
If you're doing something else, you're probably running into the fact that a contextual reference to a bean in a normal scope is a client proxy. In less stuffy terms, that means it's a proxy, a shell, a holder—and its "innards" (its referent, the thing it is proxying) is not "inflated" until some method is called on the proxy, like toString() or a business method. I'm guessing that what's happening in your case is the validator is looking for validatable fields directly on the proxy.
One way to "inflate" a contextual reference is to just call toString() on it right away before doing something else. So just call typeImpl.toString() before you do anything else to "inflate" the reference.
I don't think there's any guarantee that the proxy will somehow magically make the proxied object's fields available to you. For that, you'll need to get the inner proxied object. Each CDI implementation does this a little differently, but in Weld you can get this programmatically with some casting.
As the title suggests , I want to know how does field injection internally works in spring , I read many articles on this and got to know few things like below but didn't understood the exact reason behind it :
-> It should not be used because when you do unit testing then you are dependent upon the spring
container to instantiate the class in case of field injection.
-> You cannot use "final" keyword in case of field injection , means you cannot make the field immutable.
-> It internally uses reflection
I want to know how exactly does #Autowired works internally , how does it uses reflection , I am trying to understand the exact reason behind all the above mentioned points, what happens behind the scenes when we write the below code :
#Component
public class B {
#Autowired
private A a1;
}
I have read similar questions on stack overflow about this topic , but I couldn't find the exact explanation that I am looking.
Spring has a concept of Bean Post Processors.
When spring builds a bean it applies registered bean post processors that help to "initialize" the bean.
So, there is org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor that handles autowiring.
Basically it works with an newly created object. Spring introspects the fields of the beans (by using reflection). The fields that have #Autowired is a subject for processing with this bean post processor. It finds the candidate for injection in the application context and actually injects the value.
Now given this information, its understandable why final fields cannot be autowired. Leave alone spring, In pure Java, final fields must be instantiated directly right during the declaration (final int i = 123) or in the constructor of the class. But the autowiring happens after constructor, so its impossible to autowire the final fields.
As for the unit testing, the private properties must be somehow configured from the test. But since they're encapsulated (yes, spring kind of breaks encapsulation in this case for its usage), its impossible to write a good test for the class that contains fields injection. That's is a reason to switch to constructor injection.
public class FieldInjection {
#Autowired
private A a;
}
VS.
public class ConstructorInjection {
private final A a;
// this can be generated by lombok, you don't have to put #Autowired on constructor in the case of single constructor, spring will use it to create a bean
public ConstructorInjection(A a) {
this.a = a;
}
}
Now the test for FieldInjection class is impossible:
public class FieldInjectionTest {
#Test
void test() {
FieldInjection underTest = new FieldInjection();
how do you know that you should instantiate A a. ????
}
}
However in the case of constructor injection its a trivial task:
public class ConstructorInjectionTest {
#Test
void test() {
A a = mock(A.class);
ConstructorInjection underTest = new ConstructorInjection(a);
// the dependencies must be supplied in the constructor
// otherwise its impossible to create an object under test
}
}
Why my code is failing with the below error when I AUTOWIRE the no arg constructor but it runs fine when I autowire only the single arg constructor
Exception in thread "main" java.lang.NullPointerException
Here is TennisCoach Class code snippet
#Component // this is bean id
public class TennisCoach implements Coach {
public TennisCoach(FortuneService thefortuneservice) {
System.out.println(" inside 1 arg constructter");
fortuneservice = thefortuneservice;
}
#Autowired
public TennisCoach() {
System.out.println(" inside 0 arg constructter");
}
}
Coach theCoach = myapp.getBean("tennisCoach", Coach.class);
System.out.println(theCoach.getDailyFortunes());
How are things working behind the scene?
If you have only one constructor in a class, you don't need to use #Autowired--Spring understands that there's only one option, so it uses that one. But you have two constructors, so you need to tell Spring which one to use.
When you invoke the default constructor, however, what do you expect to happen? You don't set up your variables anywhere at all, but you are trying to read from them.
Constructor with no arguments doesn't want you put #Autowired on it as you are not injecting anything in its arguments (since there are none). #Autowired is required for constructor with arguments however.
#Component annotation above the class will create your bean via calling the default constructor and you can use that anywhere but need to make sure that you don't call anything on the fortuneservice as that will result in a null ptr exception unless you initialize it. On the contrary, if you put #Autowired annotation on top of constructor with argument and it runs fine then that means that the fortuneservice bean that you have declared elsewhere will now be injected inside this class and no null ptr exception if you call some method on that.
Adding to the previous to answers - think about the term "constructor injection". You are INJECTING references via constructor parameters. When you #Autowire an empty constructor, there isn't anything to inject. Therefore you get a NullPointerException when attempting to access the field that was supposed to have a reference injected into.
class A {
private String field1="123";
private String field2="prefix"+field1;
getter&setter;
}
filed1 is injected by one value("abc") defined in property file.
In some cases, value of field2 is always "prefix123" rather than "prefixabc".
Does property injection and initialization have order?
It could be safer to initialize field two inside a postconstruct method:
#PostConstruct
void initFieldTwo(){
field2="prefix"+field1;
}
That way you know it will happen after field 1 has been initialized.
I having a Spring class, where I am autowiring a service using constructor, plus in the same constructor I am intializing other field of the same class.
#Component
class Converter {
private TestService testService;
private Interger otherFields;
#Autowired
public Converter(TestService testService) {
this.testService = testService;
this.otherFields = new Integer(10);
}
}
My Functionality is working fine, but is it a good practice?, would #Autowired annotation have any impact on otherFields intialization process
It shouldn't. Back in the xml days, when you want to pass on an argument to a constructor, you mentioned your ref bean for the constructor arg. This just means that you must have a constructor that takes the specified bean type as an argument. It doesn't really matter what you add in the constructor, as long as you are creating a valid object through the constructor (though this is just normal java programming and nothing to do with Spring).
Auto-wiring is just an easy way to create your object with the necessary dependencies and your code is still your code.
No.
When Spring is instantiating your class it will locate the constructor annotated with #Autowired, collect the beans that corresponds to the arguments the constructor takes and then invoke it with those beans as arguments.
It will then scan through all fields and methods in your class and inject beans into any fields that are annotate with #Autowired. It will not touch methods or fields that are not annotated.