2017-02-17 38 views
0

我有從API這樣的JSON響應:如何在外部名稱變量時使用GSON/Retrofit獲取內部JSON對象?

{"asalas77": 
    {"id":23519033,"name":"Asalas77","profileIconId":22,"revisionDate":1487214366000,"summonerLevel":30} 
} 

我需要從中提取內部對象。我嘗試使用這個問題中顯示的解串器Get nested JSON object with GSON using retrofit,但它不適用於我。

public class SummonerDeserializer implements JsonDeserializer<Summoner> { 
@Override 
public Summoner deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) 
     throws JsonParseException { 
    long id = je.getAsJsonObject().get("id").getAsLong(); 
    String name = je.getAsJsonObject().get("name").getAsString(); 
    int profileIconId = je.getAsJsonObject().get("profileIconId").getAsInt(); 
    long revisionDate = je.getAsJsonObject().get("revisionDate").getAsLong(); 
    long summonerLevel = je.getAsJsonObject().get("summonerLevel").getAsLong(); 
    Summoner s = new Summoner(); 
    s.setId(id); 
    s.setName(name); 
    s.setProfileIconId(profileIconId); 
    s.setRevisionDate(revisionDate); 
    s.setSummonerLevel(summonerLevel); 

    return s; 
} 
} 

但問題是我無法從JsonElement je進入內場而得名asalas77是一個變量(這是一個搜索查詢),所以我不能直接提取內部對象。

回答

1

爲了不衝突反序列化策略,您必須有一個包裝類。假設它是如下:

final class SummonerResponse { 

    private final Summoner summoner; 

    private SummonerResponse(final Summoner summoner) { 
     this.summoner = summoner; 
    } 

    static SummonerResponse summonerResponse(final Summoner summoner) { 
     return new SummonerResponse(summoner); 
    } 

    Summoner getSummoner() { 
     return summoner; 
    } 

} 

然後你就可以創建一個自定義響應解串器:

final class SummonerWrapperDeserializer 
     implements JsonDeserializer<SummonerResponse> { 

    private static final JsonDeserializer<SummonerResponse> summonerDeserializer = new SummonerWrapperDeserializer(); 

    private SummonerWrapperDeserializer() { 
    } 

    static JsonDeserializer<SummonerResponse> getSummonerResponseDeserializer() { 
     return summonerDeserializer; 
    } 

    @Override 
    public SummonerResponse deserialize(final JsonElement jsonElement, final Type type, final JsonDeserializationContext context) 
      throws JsonParseException { 
     // Pick the root as a JSON object 
     final JsonObject outerJsonObject = jsonElement.getAsJsonObject(); 
     // And check how many properties does it have 
     final Iterable<? extends Entry<String, JsonElement>> outerJsonObjectEntries = outerJsonObject.entrySet(); 
     if (outerJsonObject.size() != 1) { 
      throw new JsonParseException("Expected one property object, the actual properties are: " + getPropertyName(outerJsonObjectEntries)); 
     } 
     // If it has only one property, just get the property and take its inner value 
     final JsonElement innerJsonElement = outerJsonObjectEntries.iterator().next().getValue(); 
     // Once it's obtained, just delegate the parsing to a downstream parser - no need to create Summoner instances by hands 
     return summonerResponse(context.deserialize(innerJsonElement, Summoner.class)); 
    } 

    private static Set<String> getPropertyName(final Iterable<? extends Entry<String, JsonElement>> entries) { 
     final Set<String> keys = new LinkedHashSet<>(); 
     for (final Entry<String, JsonElement> entry : entries) { 
      keys.add(entry.getKey()); 
     } 
     return keys; 
    } 

} 

還是節省一些內存(JSON(反)序列化需要一些內存,因爲它們使用JSON樹工作)和創建更低水平型適配器:

final class SummonerResponseTypeAdapterFactory 
     implements TypeAdapterFactory { 

    private static final TypeAdapterFactory summonerResponseTypeAdapterFactory = new SummonerResponseTypeAdapterFactory(); 

    private SummonerResponseTypeAdapterFactory() { 
    } 

    static TypeAdapterFactory getSummonerResponseTypeAdapterFactory() { 
     return summonerResponseTypeAdapterFactory; 
    } 

    @Override 
    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> typeToken) { 
     // Check if we can handle SummonerResponse. Classes can be compared with `==` 
     if (typeToken.getRawType() == SummonerResponse.class) { 
      final TypeAdapter<SummonerResponse> typeAdapter = getSummonerResponseTypeAdapter(gson); 
      @SuppressWarnings("unchecked") 
      final TypeAdapter<T> castTypeAdapter = (TypeAdapter<T>) typeAdapter; 
      return castTypeAdapter; 
     } 
     return null; 
    } 

} 
final class SummonerResponseTypeAdapter 
     extends TypeAdapter<SummonerResponse> { 

    private final Gson gson; 

    private SummonerResponseTypeAdapter(final Gson gson) { 
     this.gson = gson; 
    } 

    static TypeAdapter<SummonerResponse> getSummonerResponseTypeAdapter(final Gson gson) { 
     return new SummonerResponseTypeAdapter(gson); 
    } 

    @Override 
    @SuppressWarnings("resource") 
    public void write(final JsonWriter out, final SummonerResponse summonerResponse) 
      throws IOException { 
     // The incoming object may be null 
     if (summonerResponse == null && gson.serializeNulls()) { 
      out.nullValue(); 
      return; 
     } 
     // Generate the inner object 
     out.beginObject(); 
     out.name(summonerResponse.getSummoner().name); 
     gson.toJson(summonerResponse.getSummoner(), Summoner.class, out); 
     out.endObject(); 
    } 

    @Override 
    public SummonerResponse read(final JsonReader in) 
      throws IOException { 
     // is it a null? 
     if (in.peek() == NULL) { 
      return null; 
     } 
     // make sure that the inner read JSON contains an inner object 
     in.beginObject(); 
     // ignore the name 
     in.nextName(); 
     // delegate parsing to the backing Gson instance in order to apply downstream parsing 
     final Summoner summoner = gson.fromJson(in, Summoner.class); 
     // check if there are more properties within the inner object 
     if (in.peek() == NAME) { 
      throw new MalformedJsonException("Unexpected: " + in.nextName()); 
     } 
     // consume the "}" token 
     in.endObject(); 
     return summonerResponse(summoner); 
    } 

} 

然後任何上述選項可爲U sed的是這樣的:

final Gson gson = new GsonBuilder() 
     .registerTypeAdapter(SummonerResponse.class, getSummonerResponseDeserializer()) 
     .create(); 
final SummonerResponse summonerResponse = gson.fromJson(JSON, SummonerResponse.class); 
final Summoner summoner = summonerResponse.getSummoner(); 
out.println(summoner.id + " => " + summoner.name); 

final Gson gson = new GsonBuilder() 
     .registerTypeAdapterFactory(getSummonerResponseTypeAdapterFactory()) 
     .create(); 
final SummonerResponse summonerResponse = gson.fromJson(JSON, SummonerResponse.class); 
final Summoner summoner = summonerResponse.getSummoner(); 
out.println(summoner.id + " => " + summoner.name); 
out.println(gson.toJson(summonerResponse)); 

輸出是

23519033 => Asalas77

23519033 => Asalas77
{ 「Asalas77」:{ 「ID」:23519033, 「姓名」: 「Asalas77」, 「profileIconId」:22, 「revisionDate」:1487214366000 「summonerLevel」:30}}

相關問題