1

在尝试使用 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 不能在 shouldMapToFoo(LoginInputMapTest.java:83) 处转换​​为 LoginInputMapTest$Foo java.lang.ClassCastException

使用这个最小的测试用例:

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"));
   }
4

2 回答 2

3

在您的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。)

于 2014-10-07T15:22:14.477 回答
0

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

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

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

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

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

不幸的是,没有图书馆可以找到那里的信息。因此,您建议的用法无法按原样实施。

这并不意味着您不能通过打字,而是意味着它必须从外部传递。有了基本的杰克逊,你TypeReference可以使用:

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

将构造对 type 的引用Map<KeyType,ValueType>TypeFactory或者您可以使用;以编程方式构建这些。就像是:

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

现在:ClassMate相反,可以从类定义中提取类型信息。如果你有带字段的类、使用泛型类型声明的方法,那么很难轻松找出声明的参数化。但听起来这并不是你真正想要或需要的。相反,您应该能够使用 Jackson 的类型处理功能来构建它。

于 2015-05-18T22:19:30.947 回答