2013-06-07 14 views
6

Sto tentando di deserializzare uno JSONArray con Gson, uno il tipo di valori può variare, il valore "in_wanted" può essere uno boolean o uno JSONObject.Gson deserialize json con vari tipi di valore

in_wanted come boolean:

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

in_wanted come JSONObject:

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

Ho bisogno l'oggetto quando è disponibile e ho bisogno di un deserializzatore per restituire null ogni volta che il valore di "in_wanted" è un booleano. Quale sarebbe il modo migliore per farlo con Gson?

+0

Se devi rappresentare a una classe quindi provare a lasciare che ingenuamente il lavoro deserializzatore GSON, si deve lasciare che il riferimento nullo. – Pragmateek

risposta

10

È possibile farlo con deserializzatore personalizzato. All'inizio dovremmo creare un modello di dati che possa rappresentare il tuo JSON.

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); 
    } 
} 

Ora, quando abbiamo tutte le classi necessarie dovremmo implementare nuove deserializzatore personalizzato:

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 { 

} 

prega di dare un'occhiata su JsonProfile classe. Dobbiamo crearlo per evitare il "ciclo di deserializzazione" (parte difficile).

E ora siamo in grado di testare la nostra soluzione con metodo di prova:

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: questa è l'altra possibilità di cui ho parlato nel mio commento ... – MikO

+0

Questo ha fatto il trucco, dal momento che l'analisi manuale sarebbe stata un compito importante come sospettavate @MikO. Grazie mille per l'aiuto! – Meatje

3

Si potrebbe fare un'analisi manuale, qualcosa di simile a:

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(); 
} 

Nota: vedi Gson API documentation per ulteriori informazioni sui tipi di JsonObject, JsonArray, JsonElement, e così via ...

+0

È possibile farlo solo per il valore in_wanted? Quindi non dovrei scrivere l'analisi manuale per gli altri valori dell'array (che il deserializzatore predefinito analizza bene). – Meatje

+1

@Meatje: Penso che ci sia una possibilità, scrivendo un deserializzatore personalizzato, ma prima di scriverlo, devi notare che l'altra soluzione non sarà molto più semplice di questo, e se hai quelle risposte JSON penso che sia meglio. .. o è che hai incluso solo una piccola parte delle tue effettive risposte JSON? – MikO