2017-04-07 10 views
1

リクエストのパラメータの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":[]}を取得します。

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()メソッドD/OkHttp: name=abc&items=ru.bartwell.myapp.MyModel%4010a3d8b

が、私はこのコードを使用して要求を行います。私は改修でそれを呼び出すときしかし、私は、このログに参照してください。

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 - 注釈付きパラメータがstringConverterでシリアル化されているためです。デフォルトの動作をオーバーライドするには、単に上書きstringConverter方法で別のConverter.Factoryを追加する必要があります。

.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'{"accept":[]}をURIエンコードされています)。

少数サイドノート:

  • Gsonインスタンスはスレッドセーフであり、全体のアプリケーションごとに一度作成された(そして、これはすべてのコンポーネントに単一のインスタンスを渡すために完全に罰金です)することができます。
  • あなたMyModelSerializer改善することができます。デシリアライザはGsonインスタンス構成にバインドされているので、あなたがそこにGsonインスタンスを作成するべきではありませんので、あなたはitemsTypenew TypeToken<List<String>>() {}.getType()あるcontext.serialize(myModel.mItems, itemsType)、同様に指定されたコンテキストを経由してシリアライズを委任する必要があります。
関連する問題