2014-10-07 61 views
1

在尝试使用TypeTools Resolving generic type information with TypeTools后,我试图用https://github.com/cowtowncoder/java-classmate代替。使用java同学解决泛型类型

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

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 cannot be cast to 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")); 
    } 
+0

你的MapperImpl做些什么吗?看起来你创建了一个匿名类而没有实际访问它。或者这只是一个缩写? – 2014-10-07 14:58:59

+0

匿名类在那里提供一个子类型。我认为你需要它来解决泛型类型。看到这个例子:https://github.com/cowtowncoder/java-classmate#resolving-type-parameters-for-a-class – dmz73 2014-10-07 15:04:07

回答

2

没有什么,你可以在你的fromMap方法中做的就是提供的类型参数,这是绑定到你的类型变量T

我建议你创建一个专门用于FooMapper实现。

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。)

+0

你是对的没有必要参数化与S的Mapper接口你为什么说我没有办法获得类型T.不是像TypeTools和同学那样的图书馆的目的吗? – dmz73 2014-10-07 17:13:20

+0

我想要做的就是他们在“4.真实世界的用法”中描述的内容。http://www.cowtowncoder.com/blog/archives/2012/04/entry_471.html – dmz73 2014-10-07 17:24:16

+0

@ dmz73这似乎完全不同。他们可以从'handler'中提取类型。但是'fromMap'方法没有任何东西可以用来提取'T'提供的类型参数。 – 2014-10-08 01:04:36

0

在我看来,你不完全理解的方式Java的泛型类型工作,对于类型变量(T,S)。要了解更多关于这方面的一个很好的地方是:

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编译器,它会添加必要的强制转换以确保值类型正确转换。

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

这并不意味着您无法通过键入,但这意味着它必须从外部传递。有了基本的杰克逊,你有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可以反过来从类定义中提取类型信息。如果你的类有字段,使用泛型类型声明的方法,很难轻易找出声明的参数化。但这听起来不像这是你真正想要或需要在这里。相反,你应该能够使用Jackson的类型处理功能来构建它。