在项目开发过程中碰到restemplate.exchange()方法反序列化失败,因为接收接口返回的数据是一个复杂的dto,该dto中存在泛型的属性。期待是转成 xxxDto,可是得到的确实LinkedMap,并且抛出了转换类型错误。
解决
首先看看 exchange源码
public <T> ResponseEntity<T> exchange(String url, HttpMethod method, @Nullable HttpEntity<?> requestEntity, ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) throws RestClientException {
Type type = responseType.getType();
RequestCallback requestCallback = this.httpEntityCallback(requestEntity, type);
ResponseExtractor<ResponseEntity<T>> responseExtractor = this.responseEntityExtractor(type);
return (ResponseEntity)nonNull(this.execute(url, method, requestCallback, responseExtractor, uriVariables));
}
通过exchange()
源码可以看出需序列化的返回类型也是参数化类型(ParameterizedTypeReference),看来exchange()
是支持多级泛型的dto,但只能带一个参数(List<T>)
解决工具
ParameterizedTypeReference<T> 源码
public abstract class ParameterizedTypeReference<T> {
private final Type type;
protected ParameterizedTypeReference() {
Class<?> parameterizedTypeReferenceSubclass = findParameterizedTypeReferenceSubclass(this.getClass());
Type type = parameterizedTypeReferenceSubclass.getGenericSuperclass();
//isInstanceOf(Class clazz, Object obj) / isInstanceOf(Class type, Object obj, String message) 如果 obj 不能被正确造型为 clazz 指定的类将抛出异常;
Assert.isInstanceOf(ParameterizedType.class, type, "Type must be a parameterized type");
ParameterizedType parameterizedType = (ParameterizedType)type;
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
//复杂dto(含有泛型) 只允许有一个参数,例:List<T>
Assert.isTrue(actualTypeArguments.length == 1, "Number of type arguments must be 1");
this.type = actualTypeArguments[0];
}
private ParameterizedTypeReference(Type type) {
this.type = type;
}
public Type getType() {
return this.type;
}
public boolean equals(@Nullable Object other) {
return this == other || other instanceof ParameterizedTypeReference && this.type.equals(((ParameterizedTypeReference)other).type);
}
public int hashCode() {
return this.type.hashCode();
}
public String toString() {
return "ParameterizedTypeReference<" + this.type + ">";
}
public static <T> ParameterizedTypeReference<T> forType(Type type) {
return new ParameterizedTypeReference<T>(type) {
};
}
//查找 ParameterizedTypeReference 类的子类
private static Class<?> findParameterizedTypeReferenceSubclass(Class<?> child) {
Class<?> parent = child.getSuperclass();
if (Object.class == parent) {
throw new IllegalStateException("Expected ParameterizedTypeReference superclass");
} else {
return ParameterizedTypeReference.class == parent ? child : findParameterizedTypeReferenceSubclass(parent);
}
}
}
ParameterizedType(参数化类型)是什么请参考:ParameterizedType详解
实现
xxxDto
public class xxxDto<T> implements Serializable {
private static final long serialVersionUID = 1L;
private String statusCode;
private String statusMsg;
private T data;
public boolean isSuccess(){
return "000000".equals(statusCode);
}
}
restemplate 调用
xxxDto<xxxDto> dto = networkProxy.request(NetworkProxy.Target.XXX, HttpMethod.POST, httpEntity,
new ParameterizedTypeReference<xxxDto<xxxDto>>() {
}, new HashMap<>());
public <T> T request(Target target, HttpMethod httpMethod, HttpEntity httpEntity, ParameterizedTypeReference<T> responseType, Map<String, ?> uriVariables) {
log.info(proxyAddress + target.getUrl());
return restTemplate.exchange(proxyAddress + target.getUrl(), httpMethod, httpEntity, responseType, uriVariables).getBody();
}