2017-04-07 26 views
1

我需要在请求参数之一中发送带有自定义JSON对象的HTTP PUT请求。这是一个问题:当我使用Retrofit2时,我的序列化程序不会调用。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":[]}。但是,当我与改造称它为我在日志中看到这一点:D/OkHttp: name=abc&items=ru.bartwell.myapp.MyModel%4010a3d8b

我就与这个代码的请求:)

@FormUrlEncoded 
@PUT("path/{id}") 
Call<ResultModel> getResult(@Path("id") long item, @Field("name") @NonNull String name, @Field("items") @NonNull MyModel myModel); 

getMyApi(方法:

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

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; 
    } 
} 

如何解决呢?

回答

1

发生这种情况是因为@Field -annated参数与stringConverter串行化。若要覆盖默认行为,你只需要添加另一个Converter.FactorystringConverter方法重写:

.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),其中itemsTypenew TypeToken<List<String>>() {}.getType()