改造通用服务接口

Chi*_*nda 0 generics android retrofit retrofit2

我正在为Retrofit创建一个通用的API层

这是我的服务类:

public interface ApiService {

    @POST("api/authenticate")
    Call<Class> postData(@Body Class postBody);

}

public  void  postRequest(String actionUrl,GenericModelClass postBodyModel){
    mApiService.postData(postBodyModel.getClass()).enqueue(new Callback<Class>() {


        @Override
        public void onResponse(Call<Class> call, Response<Class> response) {
            response.getClass().getComponentType();

            Log.d("TFFF", response.toString());
        }

        @Override
        public void onFailure(Call<Class> call, Throwable t) {
          Log.d("TFFF", t.toString());
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

但是这个给了我:

java.lang.UnsupportedOperationException:尝试序列化java.lang.Class:a2a.rnd.com.a2ahttplibrary.retrofit.model.User.忘了注册一个类型适配器?

我想User从泛型类型中获取类型,但我得到此异常.

Lyu*_*riv 12

你这样做的方式没有意义,这就是你得到的原因:

java.lang.UnsupportedOperationException:尝试序列化java.lang.Class:a2a.rnd.com.a2ahttplibrary.retrofit.model.User.忘了注册一个类型适配器?

您的服务未指定类型参数.Class处理另一个目的:它是一个表示由JVM加载的类的对象.序列化和反序列化Class实例非常有意义(如果有的话),这就是Gson不提供它的原因.你想要的只是通用方法.互联网上有无数关于这个主题的文章.

接下来,Retrofit不能与方法类型参数一起使用,以简化引擎盖下的类型分析.没关系.

@GET("/")
<T> Call<T> get();
Run Code Online (Sandbox Code Playgroud)

这不行.那么你如何传递必要的类型信息数据呢?传递我能想到的信息的唯一方法是引入一个包装来保存值及其类型(或类型标记以简化Gson).

final class GenericBody<T> {

    final T body;
    final TypeToken<T> typeToken;

    GenericBody(final T body, final TypeToken<T> typeToken) {
        this.body = body;
        this.typeToken = typeToken;
    }

}
Run Code Online (Sandbox Code Playgroud)

然后可以如下声明示例服务:

interface IGenericService {

    @POST("/")
    Call<Void> post(@Body @SuppressWarnings("rawtypes") GenericBody genericBody);

}
Run Code Online (Sandbox Code Playgroud)

在这里,Call声明不返回任何内容,并且genericBody有意地使其为raw-typed以允许它通过Retrofit验证.

接下来,Gson部分.

final class GenericBodyTypeAdapterFactory
        implements TypeAdapterFactory {

    private static final TypeAdapterFactory genericBodyTypeAdapterFactory = new GenericBodyTypeAdapterFactory();

    private GenericBodyTypeAdapterFactory() {
    }

    static TypeAdapterFactory getGenericBodyTypeAdapterFactory() {
        return genericBodyTypeAdapterFactory;
    }

    @Override
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) {
        if ( !GenericBody.class.isAssignableFrom(typeToken.getRawType()) ) {
            return null;
        }
        final TypeAdapter<GenericBody<T>> genericBodyTypeAdapter = new TypeAdapter<GenericBody<T>>() {
            @Override
            public void write(final JsonWriter out, final GenericBody<T> value)
                    throws IOException {
                final T body = value.body;
                final TypeAdapter<T> typeAdapter = gson.getDelegateAdapter(GenericBodyTypeAdapterFactory.this, value.typeToken);
                typeAdapter.write(out, body);
            }

            @Override
            public GenericBody<T> read(final JsonReader in) {
                throw new UnsupportedOperationException();
            }
        };
        @SuppressWarnings("unchecked")
        final TypeAdapter<T> typeAdapter = (TypeAdapter<T>) genericBodyTypeAdapter;
        return typeAdapter;
    }

}
Run Code Online (Sandbox Code Playgroud)

它的作用是:

  • 检查它是否可以处理GenericBody实例;
  • <T>通过绑定类型标记解析适当的类型适配器;
  • 将通用主体值写入输出.

没有实现读取.

使用示例(完整的mocks(staticResponse(applicationJsonMediaType, "OK"))可以很容易地转换为您的代码):

private static final TypeToken<List<String>> stringListTypeToken = new TypeToken<List<String>>() {
};

private static final Gson gson = new GsonBuilder()
        .registerTypeAdapterFactory(getGenericBodyTypeAdapterFactory())
        .create();

private static final OkHttpClient client = new OkHttpClient.Builder()
        .addInterceptor(staticResponse(applicationJsonMediaType, "OK"))
        .build();

private static final Retrofit retrofit = new Retrofit.Builder()
        .baseUrl("http://whatever")
        .client(client)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

private static final IGenericService genericService = retrofit.create(IGenericService.class);

public static void main(final String... args)
        throws IOException {
    final GenericBody<List<String>> body = new GenericBody<>(asList("foo", "bar", "baz"), stringListTypeToken);
    genericService.post(body).execute();
}
Run Code Online (Sandbox Code Playgroud)

这将写入["foo","bar","baz"]关于正确配置的 Gson(de)序列化策略的输出流.