我需要在请求的参数之一中发送带有自定义JSON对象的HTTP PUT请求。这是一个问题:当我将它与Retrofit2一起使用时,我的序列化程序不会调用。
我的对象应该是这样的:
{
"ignore":["item1", "item2"]
}
当我直接调用它时效果很好:
final Gson gson = new GsonBuilder()
.registerTypeAdapter(MyModel.class, new MyModelSerializer())
.create();
String s = gson.toJson(new MyModel(MyModel.ActionName.ACCEPT, new ArrayList<String>()));
Log.d("tag", s);
我得到{"accept":[]}
。但是当我用Retrofit调用它时,我在日志中看到:D/OkHttp: name=abc&items=ru.bartwell.myapp.MyModel%4010a3d8b
我使用此代码发出请求:
try {
MyModel myModel = new MyModel(MyModel.ActionName.ACCEPT, new ArrayList<String>());
Response<ResultModel> response = getMyApi().getResult(1, "abc", myModel).execute();
if (response.isSuccessful()) {
ResultModel resultModel = response.body();
// handle resultModel
}
} catch (Exception e) {
e.printStackTrace();
}
MyApi :
@FormUrlEncoded
@PUT("path/{id}")
Call<ResultModel> getResult(@Path("id") long item, @Field("name") @NonNull String name, @Field("items") @NonNull MyModel myModel);
getMyApi()方法:
public static MyApi getMyApi() {
final Gson gson = new GsonBuilder()
.registerTypeAdapter(MyModel.class, new MyModelSerializer())
.create();
return new Retrofit.Builder()
.baseUrl(BuildConfig.END_POINT_MY_API)
.client(MyOkHttpClient.create())
.addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(MyApi.class);
}
模型:
public class MyModel {
@NonNull
private ActionName mActionName;
@NonNull
private List<String> mItems = new ArrayList<>();
public MyModel(@NonNull final ActionName actionName, @NonNull final List<String> items) {
mActionName = actionName;
mItems = items;
}
@NonNull
public ActionName getActionName() {
return mActionName;
}
@NonNull
public List<String> getItems() {
return mItems;
}
public enum ActionName {
ACCEPT("accept"), DECLINE("decline"), IGNORE("ignore");
private String mName;
ActionName(@NonNull final String name) {
mName = name;
}
public String getName() {
return mName;
}
}
}
串行:
public class MyModelSerializer implements JsonSerializer<MyModel> {
@Override
public JsonElement serialize(@NonNull MyModel src, @NonNull Type typeOfSrc, @NonNull JsonSerializationContext context) {
JsonObject obj = new JsonObject();
obj.add(src.getActionName().getName(), new Gson().toJsonTree(src.getItems()));
return obj;
}
}
如何解决?
答案 0 :(得分:1)
这是因为@Field
- 带注释的参数已使用stringConverter
序列化。要覆盖默认行为,您只需添加另一个Converter.Factory
方法并覆盖stringConverter
方法:
.addConverterFactory(new Converter.Factory() {
@Override
public Converter<?, String> stringConverter(final Type type, final Annotation[] annotations, final Retrofit retrofit) {
// Example check for supported classes
if ( type instanceof Class ) {
final Class<?> clazz = (Class<?>) type;
if ( MyModel.class.isAssignableFrom(clazz) ) {
return (Converter<Object, String>) value -> gson.toJson(value, type);
}
}
return super.stringConverter(type, annotations, retrofit);
}
})
然后您的查询参数字符串将如下所示:
名= ABC&安培;项=%7B%22accept%22%3A%5B%5D%7D
(此%7B%22accept%22%3A%5B%5D%7D'
是URI编码的{"accept":[]}
)。
一些附注:
Gson
个实例是线程安全的,可以在整个应用程序中创建一次(并且将单个实例传递给所有组件完全没问题。)MyModelSerializer
可以改进:您不应该在那里创建Gson
实例,因为反序列化器绑定到Gson
实例配置,因此您必须通过给定的上下文委派序列化例如context.serialize(myModel.mItems, itemsType)
,其中itemsType
是new TypeToken<List<String>>() {}.getType()
。