用java classmate解析泛型类型

时间:2014-10-07 14:50:56

标签: java generics classmate

在尝试使用TypeTools Resolving generic type information with TypeTools失败后,我试图改为使用https://github.com/cowtowncoder/java-classmate

有人可以帮我修复此代码吗?

public T fromMap(S map) {
    TypeResolver typeResolver = new TypeResolver();        
    ResolvedType type = typeResolver.resolve((new MapperImpl<T, S>() {}).getClass());
    List<ResolvedType> params = type.typeParametersFor(MapperImpl.class);
    ResolvedType typeT = params.get(0);

    ObjectMapper objectMapper = new ObjectMapper();
    T obj = objectMapper.convertValue(map, (Class<T>) typeT.getErasedType());
    return obj;

}

我收到此错误:

  

java.util.LinkedHashMap无法强制转换为LoginInputMapTest $ Foo   java.lang.ClassCastException at   shouldMapToFoo(LoginInputMapTest.java:83)

这个最小的测试用例:

public static class Foo {
       private String a;

        public String getA() {
            return a;
        }

        public void setA(String a) {
            this.a = a;
        }

   }

   @Test
   public void shouldMapToFoo() {
       Map<String, Object> map = new HashMap<>();
       map.put("a", "aaa");

       Mapper<Foo, Map<String, Object>> mapper = new MapperImpl<>();
       Foo foo = mapper.fromMap(map);
       Assert.assertEquals(foo.getA(), map.get("a"));
   }

2 个答案:

答案 0 :(得分:2)

在您的fromMap方法中,您无法获得与类型变量T绑定的类型参数。

我建议您专门为Mapper创建Foo实施。

class FooMapperImpl<S> implements Mapper<Foo, S> {
    public Foo fromMap(S map) {
        ObjectMapper objectMapper = new ObjectMapper();
        Foo obj = objectMapper
                .convertValue(map, Foo.class);
        return obj;
    }
}

(虽然我不知道为什么你需要一个源类型S,如果它始终是Map。)

答案 1 :(得分:0)

在我看来,对于类型变量(TS),您并不完全理解Java泛型类型的工作方式。了解更多相关信息的好地方是:

http://www.angelikalanger.com/GenericsFAQ/FAQSections/ParameterizedTypes.html

但基本上类型变量不携带任何运行时泛型类型信息。因此,当您名义上使用某些参数化调用方法时,除非您传递适当参数化的实际Class实例,否则不会发生任何事情。因此,编译为字节码的方法只不过是:

public Object fromMap(Object map) { ... }

现在,如果将Map作为map传递,则运行时类型将只是Map.class并且没有指定类型参数:Java值没有任何运行时类型参数化信息。基础类在Map<String,Number>Map<UUID,byte[]>之间是相同的。参数声明仅影响Java编译器,它会添加必要的强制转换以确保正确地转换值类型。

遗憾的是,没有图书馆可以找到那里的信息。因此,按照您的建议使用不可能按原样实现。

这并不意味着您无法通过输入,但这意味着它必须从外部传递。使用基本的Jackson,您可以TypeReference使用:

new TypeReference<Map<KeyType, ValueType>>() { };

将构造对Map<KeyType,ValueType>类型的引用。 或者您可以使用TypeFactory以编程方式构建这些内容;类似的东西:

mapper.getTypeFactory().constructMapType(Map.class, KeyType.class, ValueType.class);
// or with recursively constructing nested generic types

现在:相反,ClassMate可以从类定义中提取类型信息。如果您的类包含字段,使用泛型类型声明的方法,则很难轻松找到声明的参数化。但这听起来并不像你在这里真正想要或需要的那样。相反,你应该能够使用杰克逊的类型处理功能来构建它。