Spring - Inject proper service implementation in abstract class level autowired field - java

I have 2 class hierarchies:
* ClassA
* ClassB
* AbstractClass
* Class1
* ...
* Class5
AbstractClass autowires ClassA as follows:
public abstract class AbstractClass {
#Autowired
protected ClassA classA;
}
Now I would like to inject ClassA into Class1, .., Class4 implementations but ClassB into Class5. I'm aware that I can do that by injecting directly in implementing classes rather than in abstract class (as in Similar Question) but that means that I have to have the same field declared not once but five times. Additionally if I want to use this field in abstract class I would have to enforce creating getter in implementing class and use it to get that service. It works but it doesn't seem to me like right way to do it.

Here's one way to do it
#Component
class ClassA {}
#Component
class ClassB extends ClassA {}
abstract class AbstractClass {
protected ClassA classA;
}
#Component
class Class1 extends AbstractClass {
public Class1(ClassA classA) {
this.classA = classA;
}
}
//... Same for Class2/3/4
#Component
class Class5 extends AbstractClass {
public Class5(ClassB classB) {
this.classA = classB;
}
}
This lets you have the common property and methods in the abstract class and if qualify them in the child classes using constructor injection

Related

spring boot interface extends multiple interfaces

I have an interface A and a class AImpl that implements it.
public interface A {a()}
#Component
class AImpl implements A{...}
and I have an interface B and a class BImpl that implements it.
public interface B {b()}
#Component
class BImpl implements B{...}
A and B have different methods
interface C extends A, B {...}
is there a way to Autowired C c; without putting any qualifier and call
c.a();
AFAIK you don't need any qualifier to autowire a bean of type C. Just do:
#Component
class CImpl implements C {...}
#Service
class OtherService {
#Autowired
C c;
}

Dynamically create Spring beans that extend an abstract class with parameterized types

I would like to take advantage of Spring 4.0's support for autowiring of generic types but I would like to avoid having to create explicit concrete or anonymous classes for each type. To use an example, lets say I have an interface:
public interface Cache<T extends Entity>
And an abstract implementation of the interface:
public abstract class AbstractCache<T extends Entity> implements Cache<T>
{
#Autowired
private EntityDao<T> dao;
#Autowired
private List<CacheListener<T>> listeners;
...
}
And entity classes A to Z that implement Entity (e.g):
public class A implements Entity
public class B implements Entity
...
public class Z implements Entity
Is there a way I can create instances of Cache<A> through Cache<Z> such that I can autowire these generic types in other classes? E.g.
#Autowire
private Cache<Z> zCache;
I know I can achieve this by individually defining each bean, E.g.
#Bean
public Cache<Z> cacheZ() {
return new AbstractCache<Z> () {};
}
But I have been unable to come up with a way to do this for all Entity classes in a particular package. E.g.
public void registerEntityCaches (BeanFactory beanFactory) {
for (Class<? extends Entity> cls : entityPackage.getAllClasses()) {
beanFactory.registerBean(new AbstractCache<cls>() {});
}
}
Is something like this possible or do I have to define them individually?

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.

Spring Bean implementing multiple interfaces

I have a bean which implements two interfaces. The barebones code is as follows:
interface InterfaceA {
...
}
interface InterfaceB {
...
}
public class ClassC implements InterfaceA, InterfaceB {
...
}
In my AppConfig I am specifying the following:
#Bean(name = "InterfaceA")
public InterfaceA interfaceA() {
return new ClassC();
}
#Bean(name = "InterfaceB")
public InterfaceB interfaceB() {
return new ClassC();
}
And I use it so:
public class MyClass {
#Inject
private final InterfaceA a;
public MyClass(#Named("InterfaceA") InterfaceA a) {
this.a = a;
}
...
}
However, Spring complains that:
No qualifying bean of type
[com.example.InterfaceA] is
defined: expected single matching bean but found 2:
InterfaceA, InterfaceB
Similar question was asked and answered for EJB here but I could not find anything for Spring beans. Anybody know the reason?
The workaround is to introduce a new interface which extends both InterfaceA and InterfaceB and then let ClassC implement that. However, I am loath to change my design because of framework constraints.
Thank you for your excellent question.
In my case, I created an interface that extends both A and B:
public interface InterfaceC extends InterfaceA, InterfaceB {}
... and the common implementation implements the unified interface:
public class ClassC implements InterfaceC {
//...
}
This unified interface allows then to create a single bean:
#Bean
public InterfaceC implementationForAandB() {
return new ClassC();
}
The Spring framework is then able to inject or autowire the common implementation to dependencies expressed in terms of the primary interfaces:
public class MyClass {
#Inject
private final InterfaceA a;
#Inject
private final InterfaceB b;
public MyClass(InterfaceA a, InterfaceB b) {
//...
}
}
Spring is right ... When you write
#Bean(name = "InterfaceA")
public InterfaceA interfaceA() {
return new ClassC();
}
#Bean(name = "InterfaceB")
public InterfaceB interfaceB() {
return new ClassC();
}
Spring creates to ClassC objects, one named InterfaceA, the other InterfaceB, both implementing InterfaceA and InterfaceB.
Then when you write :
#Inject
private final InterfaceA a;
you ask Spring to find a bean implementing InterfaceA, but as said above there are 2 so the error.
You could either create only one object of type ClassC, or use #Qualifier or #Named annotations :
#Inject
#Named("InterfaceA")
private final InterfaceA a;
That way, you explicitely ask Spring to find the bean named InterfaceA, and hopefuly it is now unique.

How to specify which subclass Spring should use

In my spring-based project I have a core module ('core') with a class
#Component
public class Superclass {
// stuff
}
instances of which are injected by type throughout the code like this:
public class AService {
#Autowired
private Superclass superclass;
// service stuff
}
I also have two other modules that depend on the core module and one of which (let's call it 'module1') extends Superclass:
#component
public class Subclass extends Superclass {
// overridden stuff
}
The other module ('module2') uses Superclass as is.
Now I want that when I compile and run 'child1' an instance of Subclass is used everywhere an instance of Superclass is expected. So I write a configuration class:
#Configuration
public class Module2Configuration {
#Bean
public Superclass superclass(){
return new Subclass();
}
}
When I run this I see both Superclass and Subclass instantiated which is definitely not what I want. How do specify in 'module1' which type Spring should instantiate?
You can use #Qualifier("some name") annotation.
There is more information about that: http://blogs.sourceallies.com/2011/08/spring-injection-with-resource-and-autowired/
Spring eagerly instantiates singleton beans as stated in the documentation:
By default, ApplicationContext implementations eagerly create and configure all singleton beans as part of the initialization process.
which might explain why both #Components are created.
To specifiy which implementation is provided as a dependency you might want to check on Qualifiers that enable to choose between different implementations. In combination with lazy loading this should do the trick.
Depending on your personal taste you could also use delegation instead of inheritance using a separated interface:
public interface MyService {
public String foobar(int baz);
}
public static class CommonBehavior {
// whatever is used by Superclass and Subclass
}
#Component #Lazy
public class FormerSuperClass implements MyService {
private final CommonBehavior ...;
...
}
#Component #Lazy
public class FormerSubClass implements MyService {
private final CommonBehavior ...;
...
}
Good luck!
There are 2 methods: Use #Qualifier("SubclassName") Or Mark your subclass as #Component and declare the subclass when #Autowired
In your case:
Use #Qualifier("SubclassName")
#Component
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
#Qualifier("Subclass")
private Superclass superclass;
// service stuff
}
2.Mark your subclass as #Component and declare the subclass when #Autowired
public class Superclass {
// stuff
}
#component
public class Subclass extends Superclass {
// overridden stuff
}
public class AService {
#Autowired
private Subclass subclass;
// service stuff
}

Categories