Restemplate多级泛型反序列化问题解决

在项目开发过程中碰到restemplate.exchange()方法反序列化失败,因为接收接口返回的数据是一个复杂的dto,该dto中存在泛型的属性。期待是转成 xxxDto,可是得到的确实LinkedMap,并且抛出了转换类型错误。

RestTemplate的多级泛型和消息转换器

RestTemplate 反序列化带泛型的返回值

ParameterizedTypeReference官网

解决

首先看看 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)

解决工具

ParameterizedTypeReference 源码

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
        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();
    }

你可能感兴趣的:(Spring)