如何获取类型为T的字段的类?


问题内容

我为某些SpringMVC控制器编写JUnit测试。JUnit测试的初始化对于我的所有Controllers测试都是通用的,因此我想创建一个抽象类来执行此初始化。

因此,我创建了以下代码:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "classpath*:spring/applicationContext-test.xml", "classpath*:spring/spring-mvc-test.xml" })
@Transactional
public abstract class AbstractSpringMVCControllerTest<T> {

    @Autowired
    protected ApplicationContext applicationContext;

    protected MockHttpServletRequest request;

    protected MockHttpServletResponse response;

    protected HandlerAdapter handlerAdapter;

    protected T controller;

    @SuppressWarnings("unchecked")
    @Before
    public void initContext() throws SecurityException, NoSuchFieldException {
        request = new MockHttpServletRequest();
        response = new MockHttpServletResponse();
        handlerAdapter = applicationContext.getBean(AnnotationMethodHandlerAdapter.class);
        // Does not work, the problem is here...    
        controller = applicationContext.getBean(T);
    }

}

这个想法是为每个要测试扩展我的JUnit测试类的控制器创建一个AbstractSpringMVCControllerTestextends声明中给出的类型是Controller 的类。

例如,如果要测试我的AccountController,我将创建AccountControllerTest类似的类:

public class AccountControllerTest extends AbstractSpringMVCControllerTest<AccountController> {

    @Test
    public void list_accounts() throws Exception {
        request.setRequestURI("/account/list.html");
        ModelAndView mav = handlerAdapter.handle(request, response, controller);
        ...
    }

}

我的问题位于initContext()抽象类方法的最后一行。这个抽象类将controller对象声明为T对象,但是如何对Spring
Application Context说返回类型的bean T

我已经尝试过类似的方法:

    Class<?> controllerClass = this.getClass().getSuperclass().getDeclaredField("controller").getType();
    controller = (T) applicationContext.getBean(controllerClass);

controllerClass返回java.lang.Object.class类,而不是AccountController.class

当然,我可以创建一个public abstract Class<?> getControllerClass();方法,每个JUnit
Controller测试类都将覆盖该方法,但我宁愿避免这种解决方案。

那么,有什么想法吗?


问题答案:

如果 您的AbstractSpringMVCControllerTestbind 子类T在编译时是可能的。也就是说,你有类似

public class DerpControllerTest extends AbstractSpringMVCControllerTest<DerpController> { }

而不是

public class AnyControllerTest<T> extends AbstractSpringMVCControllerTest<T> { }

我猜你可能是前者。在这种情况下,在运行时会TClass对象中删除for
的类型AbstractSpringMVCControllerTest,但是Classfor对象DerpControllerTest 确实
提供了一种方法来知道是什么T,因为它是T在编译时绑定的。

以下类演示如何访问的类型T

超级java

import java.lang.reflect.ParameterizedType;
public abstract class Super<T> {

    protected T object;

    @SuppressWarnings("unchecked")
    public Class<T> getObjectType() {
        // This only works if the subclass directly subclasses this class
        return (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
    }

}

java

public class Sub extends Super<Double> {
}

Test.java

public class Test {
    public static void main(String...args) {
        Sub s = new Sub();
        System.out.println(s.getObjectType()); // prints "Class java.lang.Double"
    }
}