Retrofit generic service interface(改装通用服务接口)
问题描述
我正在为重新调整创建通用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:尝试序列化java.lang.Class:a2a.rnd.com.a2ahttplibrary.retrofit.model.User.忘记注册类型适配器?
我希望从泛型类型获取User
类型,但我得到此异常。
推荐答案
您正在以一种没有意义的方式进行操作,这就是您收到以下消息的原因:
java.lang.UnsupportedOperationException:尝试序列化java.lang.Class:a2a.rnd.com.a2ahttplibrary.retrofit.model.User.忘记注册类型适配器?
您的服务未指定类型参数。Class
句柄另一个用途:它是一个表示JVM加载的类的对象。序列化和反序列化Class
实例的意义非常小(如果有的话),这就是为什么gson不提供它的原因。您需要的只是泛型方法。互联网上有无数关于这个主题的文章。
接下来,Retrofit不使用方法类型参数来显著简化幕后的类型分析。那很好。
@GET("/")
<T> Call<T> get();
这不起作用。那么您将如何传递必要的类型信息数据呢?我能想到的传递该信息的唯一方法是引入一个包装器来同时保存值及其类型(或键入Token以简化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>
的相应类型适配器; - 将泛型正文值写入输出。
未实现读取。
使用示例(充满了可以轻松转换为您的代码的模拟(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();
}
这将根据正确配置的gson(反)序列化策略将["foo","bar","baz"]
写入输出流。
这篇关于改装通用服务接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!