2013-06-07 28 views
6

Ich versuche, eine JSONArray mit Gson zu deserialisieren, man kann den Typ der Werte variieren, der Wert "in_wanted" kann entweder boolean oder JSONObject sein.Gson deserialize JSON mit unterschiedlichen Werttypen

in_wanted als boolean:

{ 
"movies": [ 
     { 
      "title": "example boolean", 
      "in_wanted": false 
     } 
    ]   
} 

in_wanted als JSONObject:

{ 
"movies": [ 
     { 
      "title": "example object", 
      "in_wanted": { 
       "profile": { 
        "value": false 
       } 
      } 
     } 
    ]   
} 

Ich brauche das Objekt, wenn es verfügbar ist, und ich brauche einen Deserializer null zurück, wenn der Wert von "in_wanted" ist ein boolesch. Was wäre der beste Weg, dies mit Gson zu tun?

+0

Wenn Sie zu einer Klasse zuordnen sind dann versuchen, ganz naiv die Gson Deserializer arbeiten zu lassen, sollte es die Referenz als null lassen. – Pragmateek

Antwort

10

Sie können dies tun mit benutzerdefiniertem Deserializer. Zu Beginn sollten wir ein Datenmodell erstellen, das Ihren JSON darstellen kann. Jetzt

class JsonEntity { 

    private List<Movie> movies; 

    public List<Movie> getMovies() { 
     return movies; 
    } 

    public void setMovies(List<Movie> movies) { 
     this.movies = movies; 
    } 

    @Override 
    public String toString() { 
     return "JsonEntity [movies=" + movies + "]"; 
    } 
} 

class Movie { 

    private String title; 
    private Profile in_wanted; 

    public String getTitle() { 
     return title; 
    } 

    public void setTitle(String title) { 
     this.title = title; 
    } 

    public Profile getIn_wanted() { 
     return in_wanted; 
    } 

    public void setIn_wanted(Profile in_wanted) { 
     this.in_wanted = in_wanted; 
    } 

    @Override 
    public String toString() { 
     return "Movie [title=" + title + ", in_wanted=" + in_wanted + "]"; 
    } 
} 

class Profile { 

    private boolean value; 

    public boolean isValue() { 
     return value; 
    } 

    public void setValue(boolean value) { 
     this.value = value; 
    } 

    @Override 
    public String toString() { 
     return String.valueOf(value); 
    } 
} 

, wenn wir alle benötigten Klassen sollten wir neuen benutzerdefinierten Deserializer implementieren:

class ProfileJsonDeserializer implements JsonDeserializer<Profile> { 
    @Override 
    public Profile deserialize(JsonElement jsonElement, Type type, 
      JsonDeserializationContext context) throws JsonParseException { 
     if (jsonElement.isJsonPrimitive()) { 
      return null; 
     } 

     return context.deserialize(jsonElement, JsonProfile.class); 
    } 
} 

class JsonProfile extends Profile { 

} 

Bitte haben Sie einen Blick auf JsonProfile Klasse. Wir müssen es erstellen, um "Deserialisierungsschleife" (tricky part) zu vermeiden.

Und jetzt können wir unsere Lösung mit Testmethode testen:

GsonBuilder builder = new GsonBuilder(); 
builder.registerTypeAdapter(Profile.class, new ProfileJsonDeserializer()); 
Gson gson = builder.create(); 

JsonEntity jsonEntity = gson.fromJson(new FileReader("/tmp/json.txt"), 
     JsonEntity.class); 
System.out.println(jsonEntity); 
+2

@Meatje: das ist die andere Möglichkeit, über die ich in meinem Kommentar gesprochen habe ... – MikO

+0

Das hat den Trick gemacht, da das manuelle Parsing eine große Aufgabe gewesen wäre, als du @MikO verdächtigst. Danke euch beiden sehr für die Hilfe! – Meatje

3

Sie könnten eine manuelle Parsen tun, so etwas wie:

JsonParser parser = new JsonParser(); 
JsonObject rootObject = parser.parse(yourJsonString).getAsJsonObject(); 
JsonObject movieObject = rootObject 
          .getAsJsonArray("movies") 
          .get(0).getAsJsonObject(); 
JsonElement inWantedElement = movieObject.get("in_wanted"); 

//Check if "in_wanted" element is a boolean or an object 
if (inWantedElement.isJsonObject()) { 
    //Process the element as an object... 
    //for example get the element "value"... 
    boolean value = inWantedElement 
         .getAsJsonObject() 
         .getAsJsonObject("profile") 
         .getAsJsonPrimitive("value") 
         .getAsBoolean(); 
} 
else if (inWantedElement.isJsonPrimitive()) { 
    //Process the element as a boolean... 
    boolean inWanted = inWantedElement.getAsBoolean(); 
} 

Hinweis: siehe Gson API documentation für weitere Informationen über Typen JsonObject, JsonArray, JsonElement, und so weiter ...

+0

Ist dies nur für den Wert in_wanted möglich? Ich müsste also nicht für die anderen Werte im Array manuell schreiben (was der Standard-Deserializer gut parst). – Meatje

+1

@Meatje: Ich denke, es gibt eine Möglichkeit, einen benutzerdefinierten Deserializer schreiben, aber bevor Sie das schreiben, müssen Sie beachten, dass die andere Lösung wird nicht viel einfacher, dass dies, und wenn Sie diese JSON-Antworten habe ich denke, das ist besser. .. oder haben Sie nur einen kleinen Teil Ihrer tatsächlichen JSON-Antworten angegeben? – MikO