Issue
I have an abstract configuration class in a Spring 4 based project. The class looks something like this:
public abstract class C<B> {
@Bean
public B b() {
return a();
}
protected abstract B a();
}
Of course, this is not the actual class, but let's work with this theoretical class, that involves the most important parts of the real problematic class.
This class C
is extended by multiple classes. For example:
@Configuration
public class E extends C<X> {
@Override
protected X a() { return new X(); }
}
@Configuration
public class F extends C<Y> {
@Override
protected Y a() { return new Y(); }
}
The goal is to let every extending class instantiate and set up the bean the way they are intended to be and to expose the instance as a Spring bean to be injected into other beans. In other words, all of the fields should have a bean instance injected in the following bean:
@Component
public class Bean {
private final X x;
private final Y y;
public Bean(X x, Y y) {
this.x = x;
this.y = y;
}
}
The problem is that the bean created by b()
will always have a name of b
, which means that even if I have more than 1 extension of C
, only one of the beans will be available. In the above example, it would mean that either x
, or y
field is null (or would throw an exception).
How can I give unique names to these beans, so that all of the extensions of C
can expose its own bean instance without overlap?
Solution
Indeed, without specifying the bean name it will fail to start with the following message:
The bean 'b', defined in class path resource
Here's a way, which is counter intuitive because if the subclass extender doesn't call super.b()
, then some important logic would never be executed.
But for the sake of answering your specific question:
C superclass
public abstract class C<B> {
protected B b() {
return a();
}
protected abstract B a();
}
Extending subclasses
@Configuration
public class E extends C<X> {
@Bean("X)// Bean name qualifier
@Override
protected X b() {
return super.b();
}
@Override
protected X a() {
return new X();
}
}
@Configuration
public class F extends C<Y> {
@Bean("Y") // Bean name qualifier
@Override
protected Y b() {
return super.b();
}
@Override
protected Y a() {
return new Y();
}
}
Spring component
@Component
public class Bean {
private final X x;
private final Y y;
public Bean(X x, Y y) {
this.x = x;
this.y = y;
}
}
Hope this helps
Answered By - J11
Answer Checked By - Clifford M. (JavaFixing Volunteer)