I would like to have a singleton bean instance by generic parameter based on a single #Component generic class.
(I am using Spring 4.)
My code :
I have an interface like this :
public interface Mapper<I, O> {
...
}
And multiple implementation of it which are Spring #Components (singletons). Something like this :
#Component
public class MapperA implements Mapper<ClazzAI, ClazzAO> {
...
}
and
#Component
public class MapperB implements Mapper<ClazzBI, ClazzBO> {
...
}
where ClazzAI, ClazzAO, ClazzBI and ClazzBO are basic Java classes.
I have another Spring #Component (singleton) which have a Mapper class as a generic parameter :
#Component
public class TransformerImpl<I, O, M extends Mapper<I, O>> {
/** The Mapper */
protected final M mapper;
#Inject
private TransformerImpl(final M mapper) {
this.mapper= mapper;
}
...
}
and I would like to use it like this :
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
#Inject
private TransformerImpl<ClazzBI, ClazzBO, MapperB> transformerB;
The problem :
But Spring is not able to instantiate those 2 objects because it founds 2 implementations of Mapper : MapperA and MapperB even if I specify which implementation I want as a generic parameter.
Any idea how to make it without the need of instantiate all of those beans in a #Configuration class ?
You're asking for a singleton but requiring two injection points
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
#Inject
private TransformerImpl<ClazzBI, ClazzBO, MapperB> transformerB;
for differently constructed objects. That doesn't make much sense.
You now realize you need two beans. If you can't (don't want to) do it in a #Configuration class with #Bean factory methods, you'll need to declare (and scan) two separate #Component classes. (I made your parent constructor public here.)
#Component
class MapperATransformerImpl extends TransformerImpl<ClazzAI, ClazzAO, MapperA> {
#Inject
public MapperATransformerImpl(MapperA mapper) {
super(mapper);
}
}
#Component
class MapperBTransformerImpl extends TransformerImpl<ClazzBI, ClazzBO, MapperB> {
#Inject
public MapperBTransformerImpl(MapperB mapper) {
super(mapper);
}
}
When processing the injection target
#Inject
private TransformerImpl<ClazzAI, ClazzAO, MapperA> transformerA;
Spring will find the MapperATransformerImpl, which is of type TransformerImpl<ClazzAI, ClazzAO, MapperA> and inject that.
Try with Spring 4. See Using generics as autowiring qualifiers
Edit
Like #SotiriosDelimanolis explained in his answer, Spring 4 can use type parameter information as qualifiers to select which bean definition matches a particular injection point, but in the end, it will only match against bean definition with concrete type definitions. In your case, the problem is that you need a TransformerImpl bean definition for each concrete type you want to inject.
As an alternative to defining all bean definition explicitly, check my answer to Spring autowiring issues on paramaterized class
Related
I have a Singleton class ReadingStratgeyImp that extends from an Interface ReadingStrategy. In readingStrategyImp-getInstance() method will return the instance of ReadingStrategyImp.
Here is my query:
I want to inject the dependency of ReadingStrategyImp in a few of the other classes of the project.
I am achieving this by below code
ReadingStrategy readingStrategy;
#Autowired
public void setReadingStrategy(ReadingStrategyImp readingStrategy) {
this.readingStrategy = ReadingStrategyImp.getInstance();
}
I want to know how one will inject the dependency.
You simply do this :
#Component
public class Sample {
// spring will automatically find the implementation class and inject it.
// so, the ReadingStrategyImp class will automatically injected.
#Autowired
#Qualifier("readingStrategyImp")
private ReadingStrategy readingStrategy;
}
That's all.
If I understand your question correct, you should create first a Bean for ReadingStrategy with ReadingStrategyImp:
#Bean
public ReadingStrategy readingStrategy() {
return ReadingStrategyImp.getInstance();
}
Then you could just autowire the ReadingStrategy where you need it.
#Autowired ReadingStrategy readingStrategy;
Its always better to depend on interfaces not on concrete classes.
I have a parameterized class that implements the FactoryBean interface:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
What I want is to use this factory for spawning objects of different classes (all of these classes extend Dog). So I imagined that I could do something like the following:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
public ShepherdService(
#Autowired
DogFactory<Shepherd> shepherdFactory
) {
this.shepherdFactory = shepherdFactory;
}
// ...
}
Alas, I get the following error: Couldn't autowire. No beans of DogService<Shepherd> type found. :-(
How to inject it and use as DogFactory<Shepherd> or DogFactory<Corgi> (not just DogFactory)?
And another question. I also need to pass the Shepherd.class (or Corgi.class) to this bean, so it could "know" at run-time, objects of what exactly class should it produce. Is there a way to do that?
Or should I forget about FactoryBean and instantiate the factory as a regular class? Of course, I could do it this way:
DogFactory<Shepherd> shepherdFactory = new DogFactory<Shepherd>(Shepherd.class);
It would work perfectly, but I'd like to use FactoryBean as I use it for other factories in this project, so I would like to stick to FactoryBean.
Thanks in advance!
Update 1
Maybe I should clarify it more precise. What I need is a factory that could produce objects of different classes. All these classes should be extensions of the certain class (e.g., Shepherd and Corgi - all these classes extend Dog). And as the final result I actually need something like that:
public class DogService<T extend Dog> {
private DogFactory<T> dogFactory;
#Autowired
public DogService(DogFactory<T> dogFactory) {
this.dogFactory = dogFactory;
}
public T spawnDog(Color color) {
T dog = DogFactory.getObject(color);
return dog;
}
}
But it seems that I can't make a "universal" factory with the FactoryBean interface, so I can't do something like that:
public class DogFactory<T extends Dog> implements FactoryBean<T> {
// ...
}
Instead of that I have to do something like the following:
public class ShepherdFactory implements FactoryBean<Shepherd> {
// ...
}
public class CorgiFactory implements FactoryBean<Corgi> {
// ...
}
Is that true?
Thanks!
What I want is to instantiate this factory in another class
If you mean "having the factory injected in the class instead of the bean it creates", you could inject the factory by prefixing its name with an ampersand:
public class ShepherdService {
private DogFactory<Shepherd> shepherdFactory;
#Qualifier("&dogFactory")
public ShepherdService(DogFactory<Shepherd> shepherdService) {
this.shepherdService = shepherdService;
}
}
From the Spring documentation (section 3.8.3):
When you need to ask a container for an actual FactoryBean instance
itself, not the bean it produces, you preface the bean id with the
ampersand symbol & (without quotes) when calling the getBean method of
the ApplicationContext. So for a given FactoryBean with an id of
myBean, invoking getBean("myBean") on the container returns the
product of the FactoryBean, and invoking getBean("&myBean") returns
the FactoryBean instance itself.
Furthermore, my guess is that the FactoryBean is not picked up as a Spring bean as your snippets did not contain an XML config section, a Java config section, or a #Component annotation. I would explicitly declare the factory bean in a #Configuration annotated class, or annotate the factory class with #Component.
[edit]
But it seems that I can't make a "universal" factory with the
FactoryBean interface, so I can't do something like that:
You could still have a single Configuration class in which you declare all the factory beans.
#Configuration
public class DogFactoryConfig {
#Bean
public DogFactory<Shepherd> shepherdFactory() {
return new DogFactory<Shepherd>();
}
#Bean
public DogFactory<Corgi> corgiFactory() {
return new DogFactory<Corgi>();
}
}
And remove the #Component annotation from your DogFactory if it is present.
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?
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.
I have a question related to Spring injection.
I have a class defined with a generic type parameter. I want to know whether it is possible to inject the class object of the type T ( I mean T.class) ?
Like this:
#Component
public class MyExecutor<T> {
#Autowired
public MyExecutor(<Inject class object of T>) {
....
}
}
Thank you very much.
That concrete example would not work, but there is another way to create beans using generics and keep the type when injecting the bean in other beans.
Spring 4 has extended the support for generics in Java configuration. It is now possible to define two beans that differ only in the generic parameter used, and inject them by type in another bean, see this JIRA:
#Configuration
public class Config {
#Bean("beanA")
public MyExecutor<A> beanA() {
return new MyExecutor<A>(A.class);
}
#Bean("beanB")
public MyExecutor<B> beanB() {
return new MyExecutor<B>(B.class);
}
}
Then beanA or beanB can be injected by type:
#Component
public class OtherClass {
#Autowired
private MyExecutor<A> beanA;
}