How to specify which subclass Spring should use - java

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
}

Related

Injection issue for exception mapper with abstract parent (Quarkus REST client)

I'm trying to create an ExceptionMapper with an abstract parent class and some injected fields. Here is the part of code, simplified:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class MyExceptionMapper extends GenericExceptionMapper<MyException> {
#Override
public Response toResponse(MyException exception) {
...
}
}
public abstract class GenericExceptionMapper<T extends WebApplicationException> implements ExceptionMapper<T> {
#Inject
private ClassA fieldInParentA; // will be null.
#Inject
private ClassB fieldInParentB; // will be null.
// all kind of other stuff, including getters
...
}
ClassA and ClassB are simple classes with #Dependent, #ApplicationScoped or #Singleton scopes (tried all these).
The problem is, that the fields of the parent don't get injected (nor do I see any error report in logs) and the result of getFieldInParentA() or of getFieldInParentB() return null in toResponse(), although the problem is not with the injected objects (they gets injected properly in other places).
Further, to my biggest surprise, all of fieldInParentA, fieldInParentB and fieldInChild will be injected when also the child class contains injected field. This is so with any dependent, singleton or application scoped fields:
#Provider
#Produces(MediaType.APPLICATION_JSON)
public class MyExceptionMapper extends GenericExceptionMapper<MyException> {
#Inject
private ClassC fieldInChild; // **will be initialized!**
#Override
public Response toResponse(MyException exception) {
...
}
}
public abstract class GenericExceptionMapper<T extends WebApplicationException> implements ExceptionMapper<T> {
#Inject
private ClassA fieldInParentA; // **will be initialized!**
#Inject
private ClassB fieldInParentB; // **will be initialized!**
...
}
I might not understand properly the scopes (might it be the #Provider for blame?) or the inheritance of injected fields in Jakarta Dependency Injection, but besides not being able to initialize my classes (you might have guessed, that I don't want fields in the child class :) ) it is also bothering, that I do not understand this (apparently strange) behavior: how can the injection of a field in a parent depend on whether we there are fields in the child or not?!
1.
I did a lot of search, but I unfortunately couldn't find anything useful.

EJB override injection of abstract bean

I have an abstract bean with injected ISomeOtherBean interface:
public abstract class AbstractBean {
#EJB ISomeOtherBean myService;
}
The ISomeOtherBean is interface. He have many implementations, for example: SomeBeanA, SomeBeanB...
#Stateless
public class SomeBeanA implements ISomeOtherBean {
}
#Stateless
public class SomeBeanB implements ISomeOtherBean {
}
How can I inject concrete implementation of ISomeOtherBean inside some implementation of the AbstractBean?
#Stateless
public class BeanImpl extends AbstractBean {
// how write that I want inject SomeBeanB which implements ISomeOtherBean
}
First i tried to inject concrete implementation inside BeanImpl, then I passed it to additional method of superclass (Abstractbean) which writed it to field myService.
But this solution is bad for me. I remember Spring has ability to pass some beans to constructor of given bean. But it was inside XML configuration. I want something like this, but with EJB and annotation configurations.
Anyone knows how do it?

Spring: Choosing constructor while Autowiring a Component

I've a Component as follows:
#Component
class A(){
private s;
public A(){}
public A(String s){this.s=s;}
}
Here is the other class Where I'm auto wiring the above class:
#Component
class B(){
#Autowire
private A a;
}
In the above autowiring, I need to use the parameterized constructor. How can I pass the constructor args?
You can't, at least not via #Autowired in B but there are other ways to do it:
Wire the parameter into A's constructor:
One constructor is annotated with #Autowired because:
As of Spring Framework 4.3, the #Autowired constructor is no longer
necessary if the target bean only defines one constructor. If several
constructors are available, at least one must be annotated to teach
the container which one it has to use.
#Component
class A(){
private s;
public A(){}
#Autowired
public A(#Value("${myval}") String s){this.s=s;}
}
Expose A as a #Bean
Straight from the docs:
#Configuration
public class AppConfig {
#Bean
public A a(#Value("${myval}") String s) {
return new A(s);
}
}
Construct A in B using an initialization callback
Docs
#Component
class B(){
private A a;
#Value("${myval}")
private String myval;
#PostConstruct
private void init()
{
a = new A(myval);
}
}
There is a concept of prototype bean which I think you require in your case. #Component will create a singleton bean and changing it in one place will change in all parent classes where this was injected.
You need to understand how to inject a prototype bean in singleton bean.
Follow this example
https://stackoverflow.com/a/25165971/949912
Just use setters instead of constructor.
If you want to create object by yourself with new keyword then this object will not be managed by container.

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.

What's the proper way to inject Entity-based classes in Spring IoC

Please bear with me:
We have a setup of Hibernate and Spring IoC, in which for each entity (User, Customer, Account, Payment, Coupon, etc) there's a bunch of "singleton" interfaces and implementation classes that support it.
For example: forCustomer:
#Entity
public class Customer extends BaseEntity {
...
public name();
}
/* base API */
public interface Service {
public create();
public list();
public find();
public update();
public delete();
}
/* specific API */
public interface CustomerService extends Service {
public findByName();
}
/* specific implementation */
public class CustomerServiceImpl extends BaseService implements CustomerService {
...
}
And this pattern goes on and on (CustomerManager, CustomerDataProvider, CustomerRenderer, etc.).
finally, in order work against an instance of a specific API (e.g. CustomerService.findByName()), a static global holder had evolved - which makes references like the following available:
public class ContextHolder {
private static AbstractApplicationContext appContext;
public static final CustomerService getCustomerService() {
return appContext.getBean(CustomerService.class);
}
//... omitting methods for each entity class X supporting class
}
#Configuration
public class ServicesConfiguration {
#Bean(name = "customerService")
#Lazy(false)
public CustomerService CustomerService() {
return new CustomerServiceImpl();
}
//... omitting methods for each entity class X supporting class
}
So, the question is:
what would be the proper way to inject those supporting classes, e.g. CustomerService, given an entity instance, for the following uses:
I have a specific entity (e.g. a Customer), and would like to get a service and call a specific API (e.g. findByName())?
I have an entity (don't care which one in specific), and would like to call a general API (e.g. find())
All this, while avoiding global static references (and thus, swap implementations in e.g. tests, and simplify the caller code).
So i can get a any supporting class if I have an entity instance
BaseEntity entity = ... // not injected
Iservice service = ...// should be injected
service.create(entity);
or, get all the supporting classes I need for a given entity type
/* specific implementation */
public class CustomerServiceImpl extends BaseService implements CustomerService {
// inject specific supporting classes
#Autowire CustomerManager manager;
#Autowire CustomerDataProvider provider;
#Autowire CustomerRenderer renderer;
#Autowire CustomerHelper helper;
...
}
and, change the configuration a bit in other scenarios
// how to configure Spring to inject this double?
Class CustomerManagerDouble extends CustomerManager {...}
#Autowired #Test public void testSpecificAPI(CustomerService service) {
service.doSomethingSpecific();
assert ((CustomerManagerDouble) service.getManager()).checkSomething();
}
I'm not entirely sure what you're asking, but I think you want to inject entity objects (created by Hibernate) with services, right?
If that's the case, use the #Configurable annotation as described in the Spring 3.1 documentation:
http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-atconfigurable
Note that you have to use AspectJ to weave the entity classes (load-time or compile-time) for this to work.

Categories