Java Generics Issue (w / Spring)

I think that I can become a victim of erasing styles, but I thought that I would check with others first.

I have a requirement to do something like this:

public interface FooFactory { public <T extends Bar> Foo<T> createFoo( Class<T> clazz ); } 

It is completely natural to write this code. However, I am trying to implement this functionality using Spring BeanFactory , and I cannot do this.

What I would like to do is ...

 public class FooFactoryImpl implements BeanFactoryAware { private BeanFactory beanFactory; public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) { return beanFactory.getBean( ????????? ); } public void setBeanFactory( BeanFactory beanFactory ) { this.beanFactory = beanFactory; } } 

As you can see, I put ???????? where I would like to get a bean of type Foo<T> , where T extends Bar. However, it is not possible to get an object of a class like Foo<T> , and therefore, I assume that what I'm trying to do is impossible?

Does anyone else see a way around this or an alternative way to implement what I'm trying to do?

Thanks,

Andrew

+4
source share
2 answers

Since you cannot define beans of type Foo<T> with a specialized T context in Spring, I assume that you really have subclasses of Foo<T> :

 abstract public class Foo<T> { ... } public class FooString extends Foo<String> { ... } public class FooInteger extends Foo<String> { ... } 

-

 <bean id = "fooInteger" class = "FooInteger" /> <bean id = "fooString" class = "FooString" /> 

In this case, you can use the fact that type parameters are not removed from the superclass definition:

 public class FooFactory implements ApplicationContextAware { private Map<Class<?>, Foo<?>> beans = new HashMap<Class<?>, Foo<?>>(); @SuppressWarnings("unchecked") public <T> Foo<T> createFoo(Class<T> c) { return (Foo<T>) beans.get(c); } @SuppressWarnings("unchecked") public void setApplicationContext(ApplicationContext ctx) throws BeansException { Collection<Foo> candidates = ctx.getBeansOfType(Foo.class).values(); for (Foo candidate: candidates) { Type superclass = candidate.getClass().getGenericSuperclass(); if (superclass instanceof ParameterizedType) { ParameterizedType t = (ParameterizedType) superclass; Class<?> p = (Class<?>) t.getActualTypeArguments()[0]; beans.put(p, candidate); } } } } 
+1
source

Yes, this is a type erase situation. Since you cannot get Class for Foo<T> , you need to work with Foo and suppress the warning.

 @SuppressWarnings("unchecked") public <T extends Bar> Foo<T> createFoo( Class<T> clazz ) { return (Foo<T>) beanFactory.getBean("Name of Bean", Foo.class); } 

You may find this file interesting - it is a utility class with warnings that have been suppressed that Apache CXF uses to centralize all these unfortunate incidents.

Of course, all this assumes that your XML (or any other) config will lead to the use of Foo .

+3
source

Source: https://habr.com/ru/post/1311722/


All Articles