Jackson 的
TypeReference
允许通过子类化具体化类型的泛型类型参数。示例:
final var typeRef = new TypeReference<List<MyType<MyArg>>>() {};
final List<MyType<MyArg>> list = mapper.readValue(input, typeRef);
final MyType<MyArg> first = list.get(0);
这仅在子分类时已知完整类型的情况下才有效。在通用方法中提取转换调用将不起作用:
<T> T convert(final String input) {
final var typeRef = new TypeReference<List<MyType<T>>>() {};
final List<MyType<T>> list = mapper.readValue(input, typeRef);
return list;
}
final MyType<MyArg> first = list.get(0);
(因为它会擦除到
new TypeReference<List<MyType<Object>>>() {}
,这可能会被反序列化为 List<MyType<Map<String, Object>>>
)。
我想反序列化和解包泛型类型的实例,而不在调用站点提供完整的类型签名。调用站点应该只关心内部(包装)类型,因为这是它将与之交互的唯一类型。给出以下记录定义:
private record MyResponse<T>(MyResult<T> result) {}
private record MyResult<T>(List<T> values) {}
private record MyStringValue(String name) {
@Override public String toString() {
return "'" + name + "'";
}
}
和方法
<T> MyResult<T> convert(final String input, final TypeReference<MyResponse<T>> typeRef) {
try {
return objectMapper.readValue(input, typeRef).result();
} catch (final JsonProcessingException ex) {
throw new RuntimeException(ex);
}
}
如何解开此函数的结果并仅返回
T
的实例,而不提供完整类型引用 TypeReference<MyResponse<MyResult<T>>>
?
我有:
<T> List<T> unwrap(final String input, final TypeReference<MyResponse<T>> typeRef) {
return convert(content, typeRef).values();
}
必须称为:
final List<MyStringValue> values = unwrap(input, new TypeReference<MyResponse<MyResult<MyStringValue>>>() {});
// or with diamond operator:
final List<AnotherType> values = unwrap(input, new TypeReference<>() {});
unwrap
的呼叫者不需要了解MyResponse
或MyResult
。是否可以通过隐藏这些实现细节的方式定义unwrap
?
final List<MyStringValue> values = unwrap(input, new TypeReference<MyStringValue>() {});
<T> List<T> unwrap(final String input, final TypeReference<T> typeRef) { // <- callers do not need to know about MyResponse/MyResult
final TypeReference<MyResponse<MyResult<T>>> wrappedTypeRef = typeRef.wrap(MyResponse<MyResult<T>>.class); // obviously not valid Java syntax
return convert(content, typeRef).values();
}
或者由于类型擦除,我只是坚持向此方法的所有调用者公开完整类型?
(
MyResponse
和<T>
在实际代码中都是不同的具体类型:MyResponse
有一个父/子类,T
有3个实现)
TypeReference
仅设计为通过子类化它来创建。
您可以添加一个新的
convert
重载,它需要 JavaType
,您可以使用 TypeFactory
动态创建它。
<T> MyResult<T> convert(final String input, final JavaType typeRef) {
try {
return objectMapper.<MyResponse<T>>readValue(input, typeRef).result();
} catch (final JsonProcessingException ex) {
throw new RuntimeException(ex);
}
}
<T> MyResult<T> convert(final String input, final TypeReference<MyResponse<T>> typeRef) {
return convert(input, TypeFactory.defaultInstance().constructType(typeRef));
}
使用
constructParametricType
中的 unwrap
创建您想要的类型:
<T> List<T> unwrap(final String input, final TypeReference<T> typeRef) {
var typeFactory = TypeFactory.defaultInstance();
var responseResultType = typeFactory.constructParametricType(
MyResponse.class,
typeFactory.constructParametricType(
MyResult.class,
typeFactory.constructType(typeRef)
)
);
return this.<T>convert(input, responseResultType).values();
}