【问题标题】:How to transfer type parameters between types?如何在类型之间传递类型参数?
【发布时间】:2016-11-07 02:53:38
【问题描述】:

在使用retrofitGson 时,我遇到了提供的类型和最终类型不同但需要相同类型参数的情况。

我们在服务中有这个方法:

@GET("awesome")
AwesomeCall<AwesomeObject> get();

我希望AwesomeCall 返回一个包含相关AwesomeObjectAwesomeResult 或错误(请记住,这个“很棒的”API 会忽略 HTTP 并始终返回 200,只是给出一个错误对象而不是我们预期的AwesomeObject)

我想要的是改造来解析AwesomeResult并让AwesomeCall在请求没有问题的情况下返回这样的对象。

我遇到的问题是改造只为我提供了服务的返回类型,但我需要获取不同的对象。

PS:这样做是为了让服务没有任何对可能泄漏到代码中更高级别的改造对象的引用。

【问题讨论】:

    标签: java generics gson retrofit


    【解决方案1】:

    因此,在深入研究了反射的深渊之后,我发现您可以实现 ParameterizedType(因为它是一个接口)并使用它来生成与改造不同的调用。

    在我的 CallAdapter.Factory 实现中,我创建了这种类型:

    private static class AwesomeResponseType implements ParameterizedType {
        private final Type innerType;
    
        public BrainResponseType(Type innerType) {
            this.innerType = innerType;
        }
    
        @Override
        public Type[] getActualTypeArguments() {
            return new Type[] {innerType};
        }
    
        @Override
        public Type getRawType() {
            return AwesomeResponse.class;
        }
    
        @Override
        public Type getOwnerType() {
            return null;
        }
    }
    

    在创建适配器时,我会像这样注入内部类型:

    final Type innerType = getParameterUpperBound(0, (ParameterizedType) returnType);
    ParameterizedType parameterizedType = new AwesomeResponseType(innerType);
    

    并使用parameterizedType 创建自定义CallAdapter,如下所示:

    private static class AwesomeCallAdapter<T> implements CallAdapter<AwesomeCall<?>> {
    
        private final Type responseType;
    
        private AwesomeCallAdapter(Type responseType) {
            this.responseType = responseType;
        }
    
        @Override
        public Type responseType() {
            return responseType;
        }
    
        @SuppressWarnings("unchecked")
        @Override
        public <R> AwesomeCall<T> adapt(Call<R> call) {
            return new AwesomeCall<>((Call<AwesomeResponse<T>>)call);
        }
    
    }
    

    AwesomeCall 现在可以愉快地处理需要 AwesomeResponse 的调用:

    public class AwesomeCall<T> {
        private final Call<AwesomeResponse<T>> call;
    
        public AwesomeCall(Call<AwesomeResponse<T>> call) {
            this.call = call;
        }
    
        public AwesomeResponse<T> execute() throws IOException {
            Response<BrainResponse<T>> response = call.execute();
            return response.isSuccessful() ? response.body() : errorResponseFrom(response);
        }
    
        private AwesomeResponse<T> errorResponseFrom(Response<AwesomeResponse<T>> response) {
            return new AwesomeResponse<>(null, new AwesomeError(response.message()));
        }
    
    }
    

    如果你使用 Guava,我相信你不必实现ParameterizedTypeTypeToken 有一个 API 可以做到这一点:

    TypeToken.of(AwesomeResponse.class).where(new TypeParameter<T>() {}, innerType).getType();
    

    但遗憾的是,Gson 中的 TypeToken 不支持该功能 :(

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-12-16
      • 1970-01-01
      • 2010-11-15
      • 1970-01-01
      • 2019-02-27
      • 2020-02-04
      • 1970-01-01
      相关资源
      最近更新 更多