Spring Overloaded Constructor Autowiring - java

I have a class with overloaded constructors, like this:
#Component
public class MyClass {
private ClassA myMemberA;
private ClassA myMemberB;
#Autowire
public MyClass(#Qualifier ("qualifierA") ClassA objectA, ClassA objectB) {
myMemberA = objectA;
myMemberB = objectB;
}
#Autowire
public MyClass(ClassA objectA) {
myMemberA = objectA;
}
}
Basically, one constructor has two arguments of ClassA, and one constructor has just one argument. I have two beans of type ClassA defined.
I would like to have one of the two constructors invoked and autowired accordingly depending on the use case.
When I ran this code, I got the error:
Invalid autowire-marked constructor: ...
Found another constructor with 'required' Autowired annotation: ...
Is it possible to have overloaded autowired constructors? If yes, what is the right way to do it?
Thank you!

You need to define which constructor Spring will be prioritizing by writing something like this: #Autowired(required=true) or #Autowired(required=false). You are only allowed to have one constructor with #Autowired(required=true). By default, if you don't define the required property, it will be set to true, which is the problem in your case.
I don't see the point of having two Autowired constructors if only one of them will be wired anyway. If you're trying to Autowire the two instances of ClassA, it might be better to add the #Autowired annotation to the setters or the variables.

Related

Autowiring both the constructor and the field

Is it wrong to autowire both the field and the constructor when doing the automatic configuration of the spring container. For example:
#Component
public class Test1 {
#Autowired
private Test2 B;
#Autowired
Test(Test2 C) {
this.B=C;
}
}
And could you explain what happened exactly ?
It's wrong. You may have two Test2 beans, one named "B" and one named "C" (names should be lowercase BTW). That constructor will be called first, setting the field to C; after that the field will be injected, overwriting the field with B. If there is only one Test2 bean then it will work, but keep in mind that the point of constructor injection is to avoid field injection and enable use of final fields instead.

Injecting #EJB into explicitly created object -> NullPointerException

I am trying to figure out how object instantiation works in Java EE. I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container. My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it. Can we make the container manage such objects?
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
#Stateless
public class ClassA {
public void bar() {
// Does something fun
}
}
#Stateless
public class ClassB {
#EJB
private ClassA A;
public void foo() {
A.bar(); // throws NullPointerException if ClassB
// is explicitly instantiated works fine
// if injected with #EJB
}
}
public class ClassC {
//#EJB // Only way to go? Can we choose an implementation of ClassB?
private ClassB B;
public ClassC() {
this.B = new ClassB(); // Bad idea? Possible??
this.B.foo();
}
}
The reason I'm looking in to it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
I have noticed that I get a NullPointerException if I try to access a member that is supposed to be injected through #EJB if the Class defining the member has been instantiated explicitly by me rather than the container.
This is obvious as the dependencies are injected by the container. So if you are creating the instance and not setting any value for the dependency, then the dependency will be null. On the other hand, when instances are created by the container, it also sets the values of its dependencies.
My conclusion is that even if a bean is marked to be managed it is not if one doesn't let the container instantiate it.
Yes, that is correct. When you create the instance, the instance is therefore, not managed.
Let's say that we have the following setup, would it be possible to instantiate (explicitly) ClassB in ClassC and have ClassB invoke a method from ClassA without throwing a NullPointerException?
No, when you create the instance, the dependencies will be null.
The reason I'm looking into it is because I in my, equivalent of, ClassA need to use an EntityManager to persist some data, at the same time my ClassB is actually an interface so I need to be able to decide at runtime which implementation to instantiate in ClassC. Maybe there are other ways of doing this?
If you need to inject a specific implementation, the you can do that by specifying bean name.
#EJB(beanName="DefaultService")
private Service defautService;
#EJB(beanName="SpecificService")
private Service specificService;
Refer to this link: http://www.adam-bien.com/roller/abien/entry/injecting_different_implementations_into_an
Alternatively, if you're using CDI you can use #Qualifier
The other way to get an EJB reference if you cannot use injection is to use JNDI to look it up.
Context initialContext = new InitialContext();
ClassB b = (ClassB)initialContext.lookup("java:global/yourappname/ClassB!com.package.containing.ClassB");
Therefore you can use whatever logic you need to determine the JNDI name of the actual ClassB implementation you need and then look it up.

Spring/DI: Constructor injection in child class

I've got a parent class with a constructor injected dependency:
class ParentClass {
private final MyService service;
#Autowired
ParentClass(MyService service) {
this.service=service;
}
// ...
}
If I inherit from this class, do I always need to redefine a constructor calling the parent constructor?
class ChildClass extends ParentClass {
// Do I really need this?
#Autowired
ChildClass(MyService service) {
super(service);
}
// ...
}
Using setter injection, I seem to be able to keep the dependency in the parent class and do not need to rewire it in the child, which sounds good to me if the child class does not touch the functionality linked to the dependency:
class ParentClass {
private MyService service;
#Autowired
void setMyService(MyService service) {
this.service=service;
}
// ...
}
class ChildClass extends ParentClass {
// ...
}
It seems that if I want to avoid repeating the autowiring code and handling the dependency in the child, I can only do this using setter or field injection.
Is there a cleaner pattern to do this dependency injection or is this a case where field/setter injection has to be used, even though constructor injection is recommended?
Thanks!
It's not a Spring issue, it's Java. Try removing child class constructor, and see what happens for yourself - your code shouldn't compile. See this answer, it was described before.
Answering your question on dependency injection, yes, #Autowired works for setter in the parent class, but as long as you don't override it in the subclass (give it a try). The reason is that Spring deals with objects, not classes, so when a subclass is instantiated Spring is not checking annotations on overridden methods in the parent class, unless annotation is marked as #Inherited (#Autowired is not).
So, you would either have to use #Autowired for each subclass (which I don't see as a big problem, actually), switch to setter injection, replace subclassing with delegation, or make parent class abstract and use constructor injection only in subclasses.

Spring constructor autowiring and initializing other field

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.

Spring can only register contructor beans?

If let's say I have a class A (#Component) and a class B (#Component). Class A needs an instance of B. If I put class B as a field in A with #Autowired, even though Spring will find the B component (through #ComponentScan), the class A field will be null. However, if I put B as an argument in the A's contructor and annotate the constructor with #Autowired, it will work perfectly.
Is there any way to exclude B from A's constructor?
As #LuiggiMendoza mentioned: Creating a #PostConstruct method is easy: you should only annotate your method with #PostConstruct:
public class A {
#PostConstruct
void init(){
//do smth here
}
}
Or if you use XML configuration you can add init-method parameter to your bean definition.

Categories

Resources