在尝试使用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"));
}
答案 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)
在我看来,对于类型变量(T
,S
),您并不完全理解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
可以从类定义中提取类型信息。如果您的类包含字段,使用泛型类型声明的方法,则很难轻松找到声明的参数化。但这听起来并不像你在这里真正想要或需要的那样。相反,你应该能够使用杰克逊的类型处理功能来构建它。