如何获得T类字段的类?

Rom*_*las 7 java generics spring spring-mvc

我为一些Spring MVC控制器编写了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);
    }

}
Run Code Online (Sandbox Code Playgroud)

我的想法是创建,为每个控制器我想测试一个扩展我的JUnit测试类AbstractSpringMVCControllerTest.extends声明中给出的类型是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);
        ...
    }

}
Run Code Online (Sandbox Code Playgroud)

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

我尝试过类似的东西:

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

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

当然,我可以创建一个public abstract Class<?> getControllerClass();方法,它将被每个JUnit Controller测试类覆盖,但我更喜欢避免这个解决方案.

那么,任何想法?

mat*_*tts 4

如果您在编译时AbstractSpringMVCControllerTest绑定子类,这是可能的。T也就是说,你有类似的东西

public class DerpControllerTest extends AbstractSpringMVCControllerTest<DerpController> { }
Run Code Online (Sandbox Code Playgroud)

而不是

public class AnyControllerTest<T> extends AbstractSpringMVCControllerTest<T> { }
Run Code Online (Sandbox Code Playgroud)

我猜你可能有前者。在这种情况下, of 的类型会在运行时从for 对象T中删除,但for 对象确实提供了一种了解其类型的方法,因为它在编译时绑定。ClassAbstractSpringMVCControllerTestClassDerpControllerTest TT

以下类演示了如何访问 的类型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];
    }

}
Run Code Online (Sandbox Code Playgroud)

java子程序

public class Sub extends Super<Double> {
}
Run Code Online (Sandbox Code Playgroud)

测试.java

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