I'm trying to figure out the neatest and working way to use multiple copies of a component in Spring 5 differentiated by the generic type. Clearly I'm missing a concept, because based on what I read I feel this (below) should work and it doesn't, so I'm probably misunderstanding how generic types work as qualifiers.
I have this arrangement:
- Two concrete types: Beer and Coffee
- A Shop < T >
- An Order < T >
- A Manager class to @Autowire an Order < Beer > and an Order < Coffee >
- (Then each Order < T > @Autowires a Shop < T >)
public class Beer {}
public class Coffee {}
@Component
public class Order<T> {
@Autowired
Shop<T> shopToSendOrderTo;
void place(int quantity) {
log.info("Inside the order: " + this);
shopToSendOrderTo.sendOrder(quantity);
}
}
@Component
public class Shop<T> {
void sendOrder(int quantity) {
log.info("Inside the shop: " + this);
}
}
@Configuration
public class Manager implements InitializingBean {
@Autowired
Order<Beer> beerOrder;
@Autowired
Order<Coffee> coffeeOrder;
@Override
public void afterPropertiesSet() {
beerOrder.place(2);
coffeeOrder.place(0);
}
}
However I end up creating only one shop bean and one order bean when I wanted a shop < Beer > and a shop < Coffee > and an order < Beer > and an order < Coffee >
I can see this clearly from the actuator/beans output:
"shop":{
"aliases":[
],
"scope":"singleton",
"type":"com.example.generics.Generics.Shop",
"resource":"file [...]",
"dependencies":[
]
},
"order":{
"aliases":[
],
"scope":"singleton",
"type":"com.example.generics.Generics.Order",
"resource":"...",
"dependencies":[
"shop"
]
}
And you can see there is only one of each when you print the this reference:
2020-06-15 00:40:05.600 INFO 849 --- [ restartedMain] c.e.g.Generics.Order : Inside the order: com.example.generics.Generics.Order@70792f0a
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Shop : Inside the shop: com.example.generics.Generics.Shop@41e7f2d5
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Order : Inside the order: com.example.generics.Generics.Order@70792f0a
2020-06-15 00:40:05.602 INFO 849 --- [ restartedMain] c.e.g.Generics.Shop : Inside the shop: com.example.generics.Generics.Shop@41e7f2d5
@Beanmethods.@Autowiredbut either based on the@Beaninformation or detected through@Component. It won't automagically create an instance based on the generic type you want (unless you start to extend the framework for that purpose). Create a configuration class that constructs both instances and remove@Component.new, so the Shop inside each does not get autowired (?) How would you deal with that?@Beanis the same as<bean>in xml and basically there is no difference how a bean comes into existence. Unless you aren't exposing theOrder<Coffee>etc. as beans but just instantiate them. You have to make sure that also aShop<Coffee>is available as a bean.@Beanstill gets autowired. I tried making concrete types for each of my generics: BeerShop extends Shop<Beer> etc but reverted to the idea about using@Bean. Naturally the codebase I'm working on is more complex than this example and it helped a lot. Still though Spring won't wire through the@Autowiredproperties in those@Beans where they have generic type <T>, but still it is much neater. Thanks.