Issue with spring auto wiring with abstract class? - java

I have below abstract class.
Sender.java
public abstract class Sender{
public abstract void send(String id);
}
AttachSender.java
#Service("attachSender")
public class AttachSender extends Sender{
//It implements send() method here
}
SomeOtherClass.java
public class SomeOtherClass implements SomeOther{
#Autowired
private AttachSender attachSender;
}
Here i have an issue and the above code is not working.
My question is can i autowire the class instead of interface as above?
In my case AttachSender is a class but not interface.,
Thanks!

Yes, you can. If you have issues they should be elsewhere.
This thread deals with wiring a superclass, which might be of interest.

#service annotation looks wrong.
should be #Service

Related

Autowiring a Generic Implementation. Error: NoSuchBeanDefinitionException

Below are the classes and the error mentioned.
Spring version: 5+
public interface CustomGenerator<T,R> {
void generate();
}
#Service
public abstract class AbstractGenerator<T extends CustomClassA, R extends CustomClassB>
implements CustomGenerator<T,R> {}
#Service
public class ConcreteC1 extends AbstractGenerator<CustomClassA, CustomClassB>{
void generate(){
...
}
}
#Service
public class ConcreteC2 extends AbstractGenerator<CustomClassA, CustomClassB>{
void generate(){
...
}
}
#Service
public class CustomService {
#Autowired
private List<CustomGenerator<CustomClassA, CustomClassB>> customGenerators;
// Expected: ConcreteC1 & ConcreteC1 instances in the list
}
Error:
org.springframework.beans.factory.UnsatisfiedDependencyException
Unsatisfied dependency expressed through field 'customGenerators'
nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type.
I want a list of concrete classes instead of utilizing qualifiers to pick one by one, as I want to execute the generate method for all the elements in the list at once.
Thanks for any help in advance.
Rewrite the definition of List
#Service
public class CustomService {
#Autowired
private List<? extends CustomGenerator<? extends CustomClassA, ? extends CustomClassB>> customGenerators;
}
Spring will help to inject the list with ConcreteX bean.
Tested this example as exactly as I could with version 5.3.2 and it seems to work for me.
Perhaps your problem is something different? Some follow up questions that might help getting to the bottom of it:
Are all the classes correctly configured in the component scan, for example?
Exact spring version info
The below fix while autowiring made this silly mistake go away.
Thanks, everyone for your time & responses :)
#Service
public class CustomService {
#Autowired
private List<CustomGenerator<? extends CustomClassA, ? extends CustomClassB>> customGenerators;
}

How to test a function in an abstract class that implements another class

You can down vote me if you please. I am new to mockito. How do I use mockito to test a function of an abstract class that extends another class.
I trying implementing it below but got a nullPointerException.
I know you are not supposed to use an abstract like this but this is an old code developed by an old team and I need to test my function.
If there is not possibility let me know.
I have seen example in
Testing class that extends abstract class
public abstract class AbstractClass implements SomeInterface {
protected final WebServiceClient webServiceClient;
protected final AnotherWebServiceClient anotherWebServiceClient;
public BaseParser(
WebServiceClient webServiceClient,
AnotherWebServiceClient anotherWebServiceClient
) {
this.webServiceClient = webServiceClient;
this.anotherWebServiceClient = anotherWebServiceClient;
}
public functionToTest(String msg) {
System.out.println(msg)
}
My Test
#InjectMocks
#Spy
private AbstractClass aClass;
#Test
public void testSave() {
AbstractClass spy = Mockito.spy(aClass);
Mockito.doNothing().when((SomeInterface) spy).getId();
spy.functionToTest(any());
verify(spy).functionToTest(any());
}
You could write an anonymous implementation of that abstract class in your test case and test that class exposing the method. This way you have a minimal change to your code under test completely in your test code (thus not affecting production code).

How to create a default overridable Component in Spring?

I am trying to create a Component that will be Autowired unless the user creates a different implementation.
I used the following code to try and isolate the problem:
The interface:
public interface A {...}
The implementation:
#Component
#ConditionalOnMissingBean(A.class)
public class AImpl implements A {...}
The usage code:
public class AUsage {
#Autowired
private A a;
}
In this example, I don't get AImpl autowired into AUsage.
If I implement A in another class without the ConditionalOnMissingBean it works.
I tried copying existing uses of #ConditionalOnMissingBean from the internet and noticed that they all reference a #Bean method.
Indeed, when I added this code to AUsage:
public class AUsage {
#Autowired
private A a;
#Bean
#ConditionalOnMissingBean
public A createA() {
return new AImpl();
}
}
and removed the annotations from AImpl:
public class AImpl implements A {...}
everything works as expected.
I'd be pleased to get an explanation to this, if anyone knows.

Spring's #Autowired constructor gets overriden/ignored

I have SomeStartegy interface with two implementations:
#Primary
#Component
public class OneStrategy implements SomeStrategy {...}
#Component
public class SecondStrategy implements SomeStrategy {...}
I need one of them to be used as a default (primary) implementation and the other to override the default in some cases.
So I wrote something like this:
public class SuperClass {
#Autowired
SomeStrategy strategy;
}
public class SubClass extends SuperClass {
#Autowired
public SubClass(SecondStrategy secondStrategy) {
this.strategy = secondStrategy;
}
}
Injecting SubClass, I can see in debug that it's ctor is called and the assignment is done like I would expect.
However, somehow it ends up with an instance of OneStrategy instead.
What am I missing here? or am I doing this all wrong?
Field injection is made after constructor injection.
Use constructor injection for the superclass too, and call super(secondStrategy) from the subclass constructor.

Resolving Spring conflict with #Autowired and #Qualifier

I have an interface
public interface ParentService{}
And Two Implementation Class
#Service("child1service")
public class Child1 implements ParentService{}
#Service("child2service")
public class Child2 implements ParentService{}
Now my Controller
public class ServeChild1Controller extendds AbstractController{
#Autowired
public ServeChild1Controller(#Qualifier("child1service") ParentService child1service){
super(child1service)
}
Similarly there is ServeChild2Controller..
So when i run I get the following error
Error for ServeChild1Controller: No unique bean of type [com.service.ParentService] is defined: expected single matching bean but found 2 child1service, child2service
Am trying to read more about these Annotations but not able to resolve it ..
Any pointers will be of help
Thanks
In order to use a specific instance you need to provide Annotate the service with #Qualifier(id) and in the constructor anotate the parameter with #Qualifier again, as follows:
#Service("child1service")
#Qualifier("child1service")
public class Child1 implements ParentService{}
#Service("child2service")
#Qualifier("child2service")
public class Child2 implements ParentService{}
And you constructor:
public class ServeChild1Controller extendds AbstractController{
#Autowired
public ServeChild1Controller(#Qualifier("child1service") ParentService child1service){
super(child1service)
}
}
With Spring (beans) 4.3 it works exactly the way you wrote it in your question.
I can give you example with implementation groupping that I faced recently. Spring can autowire based on on type and qualifier distinction. Using service names is not enough as they need to be unique so you would end up with type conflict.
Example:
public interface ServiceA {}
public interface ServiceB {}
#Qualifier("mockedA")
#Service
public class MockedA implements ServiceA {}
#Qualifier("realA")
#Service
public class RealA implements ServiceA {}
#Qualifier("mockedB")
#Service
public class MockedB implements ServiceB {}
#Qualifier("realB")
#Service
public class RealB implements ServiceB {}
#Autowired
public ABController (
#Qualifier("mockedA") ServiceA mockedA,
#Qualifier("realA") ServiceA realA,
#Qualifier("mockedB") ServiceB mockedB,
#Qualifier("realB") ServiceB realB) {
}
I think the #Qualifier annotation might need to be provided at the same level as the #Autowired annotation.

Categories