usr-local-ΕΨΗΕΛΩΝ
usr-local-ΕΨΗΕΛΩΝ

Reputation: 26874

Retrieve a generic bean via BeanFactory.getBean(Class<T>)

With Spring 4.x I can easily autowire a generic bean and have Spring find it safely, even if the container bean is generic.

E.g. the following work (see also)

class MyBean {

    @Autowired
    private Dao<Entity> dao;

}

class MyBean<T> {

    @Autowired
    private Dao<T> dao;

}

However I sometimes need to retrieve beans at runtime during method execution instead of relying on autowiring (e.g. the beans may not be ready yet during context initialization)

private myCode() {

    BeanFactory beanFactory; //or ConfigurableListableBeanFactory too

    Dao<Entity> dao = beanFactory.getBean(....????....);
}

Considerations:

Questions is:

How do I invoke BeanFactory to get a bean instance that is bound to a given type?

Related: I know that Spring's RestTemplate requires a ParameterizedTypeReference when you need to bind a call to a return type of List<T> (when you know T)

Upvotes: 4

Views: 5583

Answers (2)

Guillermo
Guillermo

Reputation: 791

Since Spring version 4.X.X you simply autowire the ApplicationContext as it now implements the BeanFactory interface. Example:

@Component     
public class BeanUtil {

    @Autowired
    private ApplicationContext applicationContext;     
    
    public Parent get() {
        ResolvableType resolvableType = ResolvableType.forClassWithGenerics(Parent.class, ResolvableType.forClass(Child.class));
        String[] beanNames = applicationContext.getBeanNamesForType(resolvableType);
        assert beanNames.length == 1;
        String beanName = beanNames[0];
        Parent parent = applicationContext.getBean(beanName, Parent.class);
        return parent;
    }         

}

Upvotes: 3

usr-local-ΕΨΗΕΛΩΝ
usr-local-ΕΨΗΕΛΩΝ

Reputation: 26874

The following workaround works. However I will NOT accept my answer because the workaround lacks readability and is affected by an unchecked cast

String[] names = beanFactory.getBeanNamesForType(ResolvableType.forClassWithGenerics(Dao.class, Entity.class));
Dao<Entity> dao = beanFactory.getBean(names[0], Dao.class);

Rationale: Spring allows to get bean names for a parameterized type. Under the assumption that the first call returns only one result, the second works by returning that bean. Unfortunately, the second call generates a compiler time warning

Upvotes: 5

Related Questions