普通类型的Spring问题

时间:2011-07-28 10:00:25

标签: java spring generics

使用泛型时我遇到Spring问题。 以下代码描述了这个问题:

public class TestInj<S> {
    S elem;
    public S getElem() {
        return elem;
    }
    public void setElem(S elem) {
        this.elem = elem;
    }
}

@Component
public class First extends TestInj<String> {
    public First() {
        setElem("abc");
    }
}

@Component
public class Second extends TestInj<Integer> {
    public Second() {
        setElem(2);
    }
}



public class BaseTest<T> {
    @Autowired
    protected TestInj<T> test;

}

@Named
public class Test extends BaseTest<String> {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("conf-spring.xml");
        context.refresh();
        Test test = (Test) context.getBean("test", Test.class);
        System.out.println(test.test.getElem());
    }
}

问题是,在类BaseTest中应该注入类First,因为它具有泛型类型String。但春天没有得到那个并且告诉我,有两种可能的自动装配候选者。原因是,春天忽略了泛型。是否有解决方案或解决方法?

2 个答案:

答案 0 :(得分:7)

Spring对于泛型非常聪明,但是你的要求太高了。 Spring分析包含要注入的属性的类的泛型,即BaseTest。但依赖项test的类型擦除是TestInj<Object>。只有子类Test提供了更多通用信息,可以用于限制注入候选者。

不幸的是,它不是,Spring就是不行。在分析bean类时,Spring永远不会从它所在的层次结构中看到 down 。 (在我想在实现子类中将方法放在抽象超类和@Transactional注释中的其他情况下,我一直反对这一点。)

因此,如果您需要该功能,则必须为Spring的核心组件之一(AutowiredAnnotationBeanPostProcessor或其使用的辅助类之一)编写替代品。由于Spring是以模块化方式设计的,所以如果你只提供一个子类,你应该能够做到这一点而不会破坏任何东西。但是如果你不是绝对需要这个功能,那么简单的答案就是:“它不能那样工作”: - )

答案 1 :(得分:-1)

这是由于类型擦除。参见:

http://download.oracle.com/javase/tutorial/java/generics/erasure.html

When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

由于Spring DI容器在运行时工作,因此无法区分这些类型。