如何获得类的类型T的领域?(How to get the class of a field of t

2019-09-18 09:51发布

我写了一些Spring MVC控制器JUnit测试。 JUnit测试的初始化是我所有的控制器测试常见的,所以我想创造一个抽象类,这是否初始化。

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

@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测试类AbstractSpringMVCControllerTest 。 在给定的类型extends声明是类的控制器

例如,如果我想测试我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应用上下文返回类型的豆怎么能说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测试类被重写,但我更喜欢以避免该溶液中。

因此,任何想法?

Answer 1:

如果你的子类,这是可能AbstractSpringMVCControllerTest绑定T在编译时。 也就是说,你碰到这样的

public class DerpControllerTest extends AbstractSpringMVCControllerTest<DerpController> { }

而不是

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

我猜你可能是前者。 在这种情况下,类型T从清除Class对象AbstractSpringMVCControllerTest在运行时,但Class的对象DerpControllerTest 确实提供了一种方法来知道什么T的,因为它势必T在编译时。

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

Super.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];
    }

}

Sub.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"
    }
}


Answer 2:

这是从类型擦除我们通常看到的不同。 有了类型擦除,我们不知道当前的类(你得到一个参数getClass()但你可以得到那些超类/超接口(那些你得到getGenericSuperxxxxx()因为这是部分的类型声明。

这不会给你的类型的controller领域,但我希望这是足以让你的目的。

码:

public class A<P> {
}

import java.lang.reflect.ParameterizedType;

public class B extends A<String> {

    public  static void main(String[] arg) {
        System.out.println(
                ((ParameterizedType)B.class.getGenericSuperclass()).getActualTypeArguments()[0]);
    }
}

输出:

class java.lang.String

对你来说,这将是

Class controllerClass = (Class)( ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0]);

东西笔记:

如果该类B也参数如下:

public class B<X> extends A<X> {}

这将无法正常工作。 或者,如果您有其他类扩展了B,它将有问题了。 我不会去到所有这些情况下,但你应该明白我的意思。



Answer 3:

你不能因为在运行时,由于输送到消失,JVM可以不知道班级的“控制器”属性。 它被认为是对象...



文章来源: How to get the class of a field of type T?