Class Autowiring <T> for any T

So, I have some common components that use reflection to initialize themselves, and so they need Class<T> objects during initialization. These components use annotations to generate useful metadata and / or transform the object into another representation that is more suitable for the task.

I reduced my problem to this sample:

 @Component public class Instantiator<T> { final Class<T> klass; @Autowired public Instantiator(Class<T> klass) { this.klass = klass; } public T instantiate() { try { return klass.newInstance(); } catch (InstantiationException|IllegalAccessException e) { throw new RuntimeException(e); } } } 

Spring doesn't know how to automatically inject instances of Class<T> , so I tried to write the following boilerplate code for every T for which I want Class<T> be available.

 @Bean Class<Instantiatee> instantiateeClass() { return Instanciatee.class; } 

This does not work.

Spring, since version 4 supports Autowiring generic types, but in my case it should determine to which T Class<T> assigned. Since Spring creates singleton beans by default and therefore cannot output the corresponding T , I tried adding @Scope("prototype") , but I ended up with ClassCastException , since the container does not know how to draw T output anyway.

So, I removed the @Component annotation from Instantiator and set this workaround for every T I have:

 @Bean Instantiator<Instantiatee> instantiator() { return new Instantiator<>(Instantiatee.class); } 

Do you know a workaround to do this work so that T output every time I want Instantiator or another common component in it?

FYI, we are using Spring 4.1.4 with download.


I posted a more complete sample: https://gist.github.com/anonymous/79e1a7ebe7c25c00a6c2 .

+5
source share
1 answer

By defining beans with @Bean , you specify the bean name in the default method name - in your case getInstanciateeClass . Also, when auto-paused, the default bean is considered the parameter name, in your case klass . Because of this, Spring cannot match beans because they have different names and most likely there is more than one Class instance in the ApplicationContext . It doesn’t matter if one is Class<Foo> and the other is Class<Bar> , Spring sees them as Class , so it cannot autoconnect by type.

You can fix this by using the same default name, both when defining a bean or when it is auto-updated.

 @Autowired public Instanciator(Class<T> klass) { this.klass = klass; } @Bean Class<Instanciatee> klass() { return Instanciatee.class; } 

You can also specify the bean name in the @Bean annotation:

 @Autowired public Instanciator(Class<T> klass) { this.klass = klass; } @Bean(name = "klass") Class<Instanciatee> getInstanciateeClass() { return Instanciatee.class; } 

Or you can also name the bean when auto-provisioning:

 @Autowired @Qualifier("getInstanciateeClass") public Instanciator(Class<T> klass) { this.klass = klass; } @Bean Class<Instanciatee> getInstanciateeClass() { return Instanciatee.class; } 
0
source

All Articles