android - 改造通用服务接口(interface)

标签 android generics 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());
        }
    });
}

但是这个给了我:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: a2a.rnd.com.a2ahttplibrary.retrofit.model.User. Forgot to register a type adapter?

我想从通用类型中获取 User 类型,但我遇到了这个异常。

最佳答案

您正在以一种没有意义的方式进行操作,这就是您得到的原因:

java.lang.UnsupportedOperationException: Attempted to serialize java.lang.Class: a2a.rnd.com.a2ahttplibrary.retrofit.model.User. Forgot to register a type adapter?

您的服务没有指定类型参数。 Class处理 完全不同的目的:它是一个对象,表示由 JVM 加载的类。序列化和反序列化 Class instances 如果有的话,意义不大,这就是为什么 Gson 不提供它。您想要的只是通用方法。 Internet 上有无数关于此主题的文章。

接下来,Retrofit 不使用方法类型参数来显着简化引擎盖下的类型分析。没关系。

@GET("/")
<T> Call<T> get();

这行不通。那么你将如何传递必要的类型信息数据呢?我能想到的传递该信息的唯一方法是引入一个包装器来保存值及其类型(或类型标记以简化 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;
    }

}

然后一个示例服务可能声明如下:

interface IGenericService {

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

}

在这里,Call声明不返回任何内容,并且 genericBody有意将其设为原始类型以使其通过 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;
    }

}

它的作用是:

  • 检查它是否可以处理 GenericBody实例;
  • <T> 解析合适的类型适配器通过绑定(bind)类型 token ;
  • 将通用主体值写入输出。

没有实现读取。

使用示例(充满模拟(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();
}

这会写成 ["foo","bar","baz"]到符合正确配置 Gson(反)序列化策略的输出流。

关于android - 改造通用服务接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43932440/

相关文章:

Java 自动装箱和拆箱

php - 改造 2 : NO Request Body even there is

Android使用Retrofit发送HTTP POST触发云功能

Android Studio 以不同方式呈现相同的布局

android - 如何更改/更新抽屉布局中的项目?

C# 模板和特殊构造函数

java - Java 中的对象 vs Class<T>(vs Class<?>?)?

java - 使用response.body中的对象填充ArrayList

java - Android - 如何确定加载到 ImageView 的位图何时显示?

android - 我如何以 5 秒的间隔在 android 中执行后台任务?目前我正在使用警报管理器(setInexactRepeating)但没有成功