I have a bunch of repository beans that implement type Repository<T ? extends Node>
. Now I can get a list of random nodes from the user and I want to get the appropriate repository for each node. Since Spring 4.0RC1 we can autowire repositories like this:
@Autowired Repository<SomeNode> someNodeRepository;
As documented here.
This works fine, but my question is how I can do this dynamically based on the generic type.
What I want to do is something like:
public <T extends Node> T saveNode(T node) {
Repository<T> repository = ctx.getBean(Repository.class, node.getClass());
return repository.save(node);
}
Where the second parameter is the generic type. This of course does not work, although it compiles.
I can't find any/the documentation on this.
getBean() method. Simply put, as the name of the method also suggests, this is responsible for retrieving a bean instance from the Spring container.
To get a reference to the ApplicationContext in a Spring application, it can easily be achieved by implementing the ApplicationContextAware interface. Spring will automatically detect this interface and inject a reference to the ApplicationContext: view rawMyBeanImpl. java hosted by GitHub.
Bean Definition In Spring, the objects that form the backbone of your application and that are managed by the Spring IoC container are called beans. A bean is an object that is instantiated, assembled, and otherwise managed by a Spring IoC container.
You can do something like this:
String[] beanNamesForType = ctx.getBeanNamesForType(ResolvableType.forClassWithGenerics(Repository.class, node.getClass()));
// If you expect several beans of the same generic type then extract them as you wish. Otherwise, just take the first
Repository<T> repository = (Repository<T>) ctx.getBean(beanNamesForType[0]);
If you could be sure that for every concrete subclass of Node
(say SomeNode
), every object of type SomeNode
will be an actual SomeNode
and not a subclass or a proxy, it would be easy. Just use a convention for the repository name (say SomeNodeRepository
) and it would be trivial :
Repository<T> repository = ctx.getBean(node.getClass().getSimpleName()
+ "Repository", Repository.class);
But you know that there's a high risk of getting a subclass or proxy ...
So you can try to have each Node subclass to implement a nameForRepo
method :
class Node {
...
abstract String getNameForRepo();
}
and then in the subclasses
class SomeNode {
static private final nameForRepo = "SomeNode";
...
String getNameForRepo() {
return nameForRepo;
}
}
That way, even if you get a proxy or subclass, you will be able to do :
public <T extends Node> T saveNode(T node) {
Repository<T> repository = ctx.getBean(node.getNameForRepository()
+ "Repository", Repository.class);
return repository.save(node);
}
Alternatively, the method could directly return the repository name.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With