2011-10-05 2 views
39

I했습니다 다음 클래스GSON 핸들 객체 또는 배열

public class MyClass { 
    private List<MyOtherClass> others; 
} 

public class MyOtherClass { 
    private String name; 
} 

있어요 그리고 나는이

{ 
    others: { 
    name: "val" 
    } 
} 

또는이

{ 
    others: [ 
    { 
     name: "val" 
    }, 
    { 
     name: "val" 
    } 
    ] 
} 

내가 좋겠처럼 보일 수 있습니다 JSON을 이 두 가지 JSON 형식 모두에 동일한 MyClass을 사용할 수 있기를 바랍니다. Gson과 함께 할 수있는 방법이 있습니까?

+1

문제는이 같은 JSON을 생성 누구입니까? Json이 맞습니까? 그렇다면 Gson이 처리해야합니다. 그렇지 않다면, "진짜"해결책은 생산자를 고치는 것입니다. – Nilzor

+5

JSON을 작성하는 좋은 방법이 아니라는 것에 전적으로 동의합니다. 불행하게도 우리가 소비하는 데이터를 항상 통제 할 수있는 것은 아니기 때문에 생산자를 고치는 것이 언제나 선택 사항은 아닙니다. JSON은 스키마가 없으므로 유효한 JSON입니다. –

답변

69

나는 대답을 내놓았다.

private static class MyOtherClassTypeAdapter implements JsonDeserializer<List<MyOtherClass>> { 
    public List<MyOtherClass> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext ctx) { 
     List<MyOtherClass> vals = new ArrayList<MyOtherClass>(); 
     if (json.isJsonArray()) { 
      for (JsonElement e : json.getAsJsonArray()) { 
       vals.add((MyOtherClass) ctx.deserialize(e, MyOtherClass.class)); 
      } 
     } else if (json.isJsonObject()) { 
      vals.add((MyOtherClass) ctx.deserialize(json, MyOtherClass.class)); 
     } else { 
      throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
     } 
     return vals; 
    } 
} 

TypeTokencom.google.gson.reflect.TypeToken 있음이

Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType(); 

Gson gson = new GsonBuilder() 
     .registerTypeAdapter(myOtherClassListType, new MyOtherClassTypeAdapter()) 
     .create(); 

같은 GSON 객체를 인스턴스화한다.

현재 솔루션에 대해 읽을 수 있습니다 : https://sites.google.com/site/gson/gson-user-guide#TOC-Serializing-and-Deserializing-Gener

+0

감사합니다. 완벽하게 작동합니다. JSON이 단일 객체 또는 객체 집합을 반환하는 경우가있었습니다. – gnosio

+0

감사. 이것은 위대합니다. 두 개의 다른 TypeAdapter가 필요했기 때문에 다른 .registerTypeAdapter를 추가하여 체인을 연결해야했습니다. – tristan2468

+5

Gson이 어노테이션을 배열이나 객체의 동일한 형식을 허용하지 않는 이유는 무엇입니까? 이것은 매우 요구된다. –

8

당신에게 솔루션 세 컵 감사합니다!

가 여러 종류의 필요한 경우 제네릭 형식과 같은 일 :

public class SingleElementToListDeserializer<T> implements JsonDeserializer<List<T>> { 

private final Class<T> clazz; 

public SingleElementToListDeserializer(Class<T> clazz) { 
    this.clazz = clazz; 
} 

public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { 
    List<T> resultList = new ArrayList<>(); 
    if (json.isJsonArray()) { 
     for (JsonElement e : json.getAsJsonArray()) { 
      resultList.add(context.<T>deserialize(e, clazz)); 
     } 
    } else if (json.isJsonObject()) { 
     resultList.add(context.<T>deserialize(json, clazz)); 
    } else { 
     throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
    } 
    return resultList; 
    } 
} 

및 구성 GSON :

Type myOtherClassListType = new TypeToken<List<MyOtherClass>>() {}.getType(); 
SingleElementToListDeserializer<MyOtherClass> adapter = new SingleElementToListDeserializer<>(MyOtherClass.class); 
Gson gson = new GsonBuilder() 
    .registerTypeAdapter(myOtherClassListType, adapter) 
    .create(); 
0

세 컵 대답 오프 구축, 나는를 할 수있는 다음이 JsonArray는 배열로 직접 deserialize됩니다.

static public <T> T[] fromJsonAsArray(Gson gson, JsonElement json, Class<T> tClass, Class<T[]> tArrClass) 
     throws JsonParseException { 

    T[] arr; 

    if(json.isJsonObject()){ 
     //noinspection unchecked 
     arr = (T[]) Array.newInstance(tClass, 1); 
     arr[0] = gson.fromJson(json, tClass); 
    }else if(json.isJsonArray()){ 
     arr = gson.fromJson(json, tArrClass); 
    }else{ 
     throw new RuntimeException("Unexpected JSON type: " + json.getClass()); 
    } 

    return arr; 
} 

사용법 :

String response = "......."; 

    JsonParser p = new JsonParser(); 
    JsonElement json = p.parse(response); 
    Gson gson = new Gson(); 
    MyQuote[] quotes = GsonUtils.fromJsonAsArray(gson, json, MyQuote.class, MyQuote[].class);