2017-05-05 5 views
0

おはようございます。私はこれを理解するのに少し苦労している。オブジェクトのネストされたJSON配列をカスタムGsonデシリアライザで解析するにはどうすればよいですか?

{ 
     "data": [ 
     { 
      "id": "43", 
      "type": "position", 
      "attributes": { 
      "address-id": "1", 
      "employer-id": "11" 
      } 
     } 
     ], 
     "included": [ 
     { 
      "id": "1", 
      "type": "address", 
      "attributes": { 
      "line-1": "21 london london", 
      "line-2": "", 
      "line-3": "", 
      "locality": "", 
      "region": "London", 
      "post-code": "", 
      "country": "UK", 
      "latitude": "", 
      "longitude": "" 
      } 
     }, 
     { 
      "id": "11", 
      "type": "employer", 
      "attributes": { 
      "title": "Mr", 
      "first-name": "S", 
      "last-name": "T" 
      } 
     } 
     ] 
    } 

そして、私のレトロフィット・コールは次のとおりです:

@GET("/api/positions") 
Single<PositionResponse> getPosition(); 

そして、私のPositionResponseクラス:

public class PositionResponse { 

     @SerializedName("data") 
     @Expose 
     private List<DataResponse> data; 
     @SerializedName("included") 
     @Expose 
     private List<IncludedModel> included; 

     public List<DataResponse> getData() { 
      return data; 
     } 

     public void setData(List<DataResponse> data) { 
      this.data = data; 
     } 

     public List<IncludedModel> getIncluded() { 
      return included; 
     } 

     public void setIncluded(List<IncludedModel> included) { 
      this.included = included; 
     } 

     } 
    } 

は、今では多くのデータを持っている想像し、私はこのようになりますJSONを持っています。 List<IncludedModel>を解析するためのカスタムTypeAdapterまたはJsonDeserializerを作成するにはどうすればよいですか?何らかの理由でObjectのカスタムJsonDeserializerまたはTypeAdapterを作成することができますが、Listになると、それを動作させることができないようです。次のように

TypeAdapterは次のとおりです。

public class IncludedTypeAdapter extends TypeAdapter<ArrayList<IncludedModel>> { 

     @Override 
     public void write(JsonWriter out, ArrayList<IncludedModel> value) throws IOException { 

     } 

     @Override 
     public ArrayList<IncludedModel> read(JsonReader in) throws IOException { 
      ArrayList<IncludedModel> list = new ArrayList<>(); 
      IncludedModel model = new IncludedModel(); 
      Gson gson = new Gson(); 
      in.beginArray(); 
      String id = null; 
      //in.beginObject(); 
      while(in.hasNext()){ 
       JsonToken nextToken = in.peek(); 

       if(JsonToken.BEGIN_OBJECT.equals(nextToken)){ 
        in.beginObject(); 

       } else if(JsonToken.NAME.equals(nextToken)){ 

        if(JsonToken.NAME.name().equals("id")){ 
         id = in.nextString(); 
         model.setId(id); 

        } else if(JsonToken.NAME.name().equals("type")){ 
         String type = in.nextString(); 
         model.setMytype(type); 

         switch (type) { 
          case BaseModelType.Employer: 
           EmployerResponse employer = gson.fromJson(in, EmployerResponse.class); 
           model.setEmployer(employer); 
           break; 
         } 
        } 
       } 
      } 
      list.add(model); 

      return list; 
     } 

と私は私のGsonに登録します。私はGsonConverterFactoryを通じて改造に登録

GsonBuilder gsonBuilder = new GsonBuilder(); 
     gsonBuilder.registerTypeAdapter(IncludeModel.class, new IncludedTypeAdapter()); 
    //gsonBuilder.registerTypeAdapter(new IncludedTypeAdapter()); 
     gsonBuilder.serializeNulls(); 
     Gson gson = gsonBuilder.create(); 

     return gson; 

私は取得しています:

期待BEGIN_ARRAYしかしBEGIN_OBJECTは$ .included行1列6292のパスで、私は私のレトロフィット応答がある<PositionResponse>あるためである疑いが[0]

だったがJsonObject

私の質問を要約すると、私のRetrofitサービスの応答タイプがPositionResponseであることを念頭に置いて、独自のカスタムタイプのアダプターでList<IncludeModel>オブジェクトを逆直列化するにはどうすればいいですか?あなたの患者と答えに感謝します。

+1

あなたが必要な理由カスタムアダプターはまったくですか?モデルがjsonと一致する場合は、一般的にモデルは必要ありません。 – nasch

+1

@nasch includeオブジェクトを見ると、型が動的に変化し、JSONAPI形式の "relationship"タグのように、サーバの戻り値が他の入れ子になっているオブジェクトなので、保持しにくいモデルクラスがたくさんあるのでカスタムモデルでそれらをマップするほうがよいでしょう。また、学習目的のために、そうすることが可能な場合。 – irobotxxx

答えて

0

JsonDeserializerを使用してJSONツリーモデルを使用しているのは簡単です。純粋なタイプのアダプタはやや高価です(おそらくRuntimeTypeAdapterFactoryはまだツリー指向だからです)、JSONドキュメントの最も単純なケースでは、このようなものを使用できます(my yesterday answerいくつかの説明がありますが、あなたの場合は少し異なります)。

abstract class Element { 

    final String id = null; 

    private Element() { 
    } 

    static final class Address 
      extends Element { 

     @SerializedName("line-1") final String line1 = null; 
     @SerializedName("line-2") final String line2 = null; 
     @SerializedName("line-3") final String line3 = null; 
     @SerializedName("locality") final String locality = null; 
     @SerializedName("region") final String region = null; 
     @SerializedName("post-code") final String postCode = null; 
     @SerializedName("country") final String country = null; 
     @SerializedName("latitude") final String latitude = null; 
     @SerializedName("longitude") final String longitude = null; 

     private Address() { 
     } 

     @Override 
     public String toString() { 
      return country + " " + region; 
     } 

    } 

    static final class Employer 
      extends Element { 

     @SerializedName("title") final String title = null; 
     @SerializedName("first-name") final String firstName = null; 
     @SerializedName("last-name") final String lastName = null; 

     private Employer() { 
     } 

     @Override 
     public String toString() { 
      return title + ' ' + firstName + ' ' + lastName; 
     } 

    } 

    static final class Position 
      extends Element { 

     @SerializedName("address-id") final String addressId = null; 
     @SerializedName("employer-id") final String employerId = null; 

     private Position() { 
     } 

     @Override 
     public String toString() { 
      return '(' + addressId + ';' + employerId + ')'; 
     } 

    } 

} 

あなたがしなければならないのは、単に次のとおりです:

私は、あなたは、このようなマッピングがしたいと仮定してい

  • が予想されるオブジェクトのタイプを決定します。
  • JSONツリーを整列させます(必要に応じて)。
  • デシリアライゼーションコンテキストを介してGeronにデシリアライズ作業を委譲するだけです(あなたの例ではうまくいきません。つまり、元の設定をもう一度失うようにGsonを再インスタンス化しています。 ; JsonTokenは、switchでチェックされた方がはるかに優れています(方法はenumがシングルトンであり、参照平等==を使用してそれらを比較することは完全に合法です)。

だから、このような何かを実装することができます。

final class ElementJsonDeserializer 
     implements JsonDeserializer<Element> { 

    private static final JsonDeserializer<Element> elementJsonDeserializer = new ElementJsonDeserializer(); 

    private ElementJsonDeserializer() { 
    } 

    static JsonDeserializer<Element> getElementJsonDeserializer() { 
     return elementJsonDeserializer; 
    } 

    @Override 
    public Element deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) 
      throws JsonParseException { 
     final JsonObject jsonObject = jsonElement.getAsJsonObject(); 
     final String typeCode = jsonObject.getAsJsonPrimitive("type").getAsString(); 
     final Class<? extends Element> clazz; 
     switch (typeCode) { 
     case "address": 
      clazz = Element.Address.class; 
      break; 
     case "employer": 
      clazz = Element.Employer.class; 
      break; 
     case "position": 
      clazz = Element.Position.class; 
      break; 
     default: 
      throw new JsonParseException("Unrecognized type: " + typeCode); 
     } 
     reattach(jsonObject, "attributes"); 
     return context.deserialize(jsonElement, clazz); 
    } 

    private static void reattach(final JsonObject parent, final String property) { 
     final JsonObject child = parent.getAsJsonObject(property); 
     parent.remove(property); // remove after we're sure it's a JSON object 
     copyTo(parent, child); 
    } 

    private static void copyTo(final JsonObject to, final JsonObject from) { 
     for (final Entry<String, JsonElement> e : from.entrySet()) { 
      to.add(e.getKey(), e.getValue()); 
     } 
    } 

} 

はもちろん、あなたはそれを再利用するための戦略のデザインパターンを実装するための戦略を抽出するために、上記をリファクタリングすることができます。すべて一緒に入れてください:

final class Response { 

    final List<Element> data = null; 
    final List<Element> included = null; 

} 

(上記は、Map<String, List<Element>>のように見えますが、あなたが決定します)。

private static final Gson gson = new GsonBuilder() 
     .registerTypeAdapter(Element.class, getElementJsonDeserializer()) 
     .create(); 

public static void main(final String... args) 
     throws IOException { 
    try (final JsonReader jsonReader = getPackageResourceJsonReader(Q43811168.class, "data.json")) { 
     final Response response = gson.fromJson(jsonReader, Response.class); 
     dump(response.data); 
     dump(response.included); 
    } 
} 

private static void dump(final Iterable<Element> elements) { 
    for (final Element e : elements) { 
     System.out.print(e.getClass().getSimpleName()); 
     System.out.print(" #"); 
     System.out.print(e.id); 
     System.out.print(": "); 
     System.out.println(e); 
    } 
} 

出力:

ポジション#43:(1; 11)
アドレス#1:英国ロンドン
雇用者#11:ミスターST

+0

ありがとうございました!あなたが送った他のリンクの情報もありがとう!私はそれを試して、あなたに知らせるでしょう。 – irobotxxx

+1

ご迷惑をおかけしました。それは動作します!..ヘルプと情報のための大いにありがとう。新しいものを学びました! – irobotxxx

関連する問題