How to mock inherited autowired field which used in child constructor? - java

How can be mocked a field which is inherited from the parent class, it is autowired there and it is used in the child's constructor? The constructor:
public A(B b) {
super(b);
fieldA = (C) helper.getSomething(b.getId());
}
The problematic field is the helper.
Tried to mock it with ReflectionTestUtils.setField() but it not worked because it should be handled via the instance, which cannot be created before the constructor call.

Related

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 Overloaded Constructor Autowiring

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.

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.

CDI with unmanaged objects

Suppose that I have two classes, first a class without any properties, fields or annotations:
public class B {}
And a class which gets B injected, like this:
public class A {
#Inject
private B b;
public B getB() {
return b;
}
}
Now class A is pretty useless until we use it, so there are two options:
#Inject it
Construct it manually, using the trusty "new A()"
If A gets injected, CDI manages it and is kind enough to inject B which has the implicit scope of #Dependent. Cool, just what I want.
However, if I manually construct A (let's say in a factory or a builder), CDI completely ignores my object and won't inject an object of type B.
Example I'm talking about when it doesn't work, here object a will always remain null:
public class Builder {
#Inject
private A a;
public static Builder ofTypeSomething() {
// do some magic here
return new Builder();
}
private Builder() {
// and some more here
}
}
Why doesn't this work?
Class A is a valid managed bean and has a valid scope, just like class B. Even if I add #Producer to the static method, it won't change anything (which is fine, cause the idea of the static method is to call it, not to inject Builder anywhere).
Dependency injection, while useful, is not magical. The way DI works is that when you ask the container for an instance of an object the container first constructs it (via new()) and then sets the dependencies (how this happens depends on your framework).
If you construct the entity yourself then the container has no idea you've constructed the entity and can't set the dependencies of the entity.
If you want to use a factory then most frameworks have some way of configuring the entity so that the container knows to make a static factory method call and not call the constructor of the entity. However, you still have to obtain your entity from the container.
Edit: This site seems to demonstrate how to use a factory in CDI.

Categories

Resources