2013-01-24 14 views
11

Desidero modificare un contenuto JSON senza convertirlo in un POJO. Sto usando GSON Library.Modificare json con GSON senza utilizzare un POJO

seguito sono il caso d'uso:

String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]"; 

JsonElement jsonElement = gson.fromJson(jsonString, JsonElement.class);  

C'è un modo in cui posso impostare il valore di key1 ad un certo valore (diciamo "Test") in ogni array, senza convertire le cose in POJO

risposta

1

Un approccio sarebbe semplicemente convertire il JSON in un java.util.Map, modificare la Mappa e andare da lì (il che potrebbe significare la serializzazione della Mappa su JSON).

Questo approccio risponde la mia preferenza a lavorare con l'API giusto per il lavoro giusto, riducendo al minimo l'uso di strumenti come GSON di gestire solo la serializzazione/deserializzazione (che è quello che ho capito è stato progettato per). Ovvero, per non utilizzare Gson API come una struttura di dati di sostituzione.

+0

Come convertiresti JSON in Mappa? – linuxeasy

0

GSON ha due API separate (che possono essere combinate): una è utilizzata per la serializzazione e la deserializzazione e l'altra per lo streaming. Se si desidera elaborare flussi di JSON, senza sovraccarico di memoria o utilizzando strutture dinamiche (piuttosto che POJO statiche) si può fare qualcosa di simile:

  • creare un JsonWriter (nel mio esempio io uso StringWriter);
  • creare un JsonReader;
  • fare un ciclo che consuma eventi dal lettore e li invia allo scrittore, eventualmente apportando modifiche, aggiunte, omissioni ecc

Il ciclo sarà composto da una singola istruzione switch che deve avere un caso tutto il possibili eventi (10 di loro). Anche l'esempio più semplice deve averli tutti, quindi il codice sotto sembra piuttosto prolisso. Ma è molto facile estenderlo e ulteriori estensioni non lo faranno molto più a lungo.

Un esempio che aggiunge "test": 1 paio di ogni oggetto sembra qualcosa di simile:

public class Whatever { 

static void streamandmodify(JsonReader reader, JsonWriter writer) throws IOException { 
    while (true) { 
     JsonToken token = reader.peek(); 
     switch (token) { 
     // most cases are just consume the event 
     // and pass an identical one to the writer 
     case BEGIN_ARRAY: 
      reader.beginArray(); 
      writer.beginArray(); 
      break; 
     case END_ARRAY: 
      reader.endArray(); 
      writer.endArray(); 
      break; 
     case BEGIN_OBJECT: 
      reader.beginObject(); 
      writer.beginObject(); 

      // this is where the change happens: 
      writer.name("test"); 
      writer.value(1); 
      break; 
     case END_OBJECT: 
      reader.endObject(); 
      writer.endObject(); 
      break; 
     case NAME: 
      String name = reader.nextName(); 
      writer.name(name); 
      break; 
     case STRING: 
      String s = reader.nextString(); 
      writer.value(s); 
      break; 
     case NUMBER: 
      String n = reader.nextString(); 
      writer.value(new BigDecimal(n)); 
      break; 
     case BOOLEAN: 
      boolean b = reader.nextBoolean(); 
      writer.value(b); 
      break; 
     case NULL: 
      reader.nextNull(); 
      writer.nullValue(); 
      break; 
     case END_DOCUMENT: 
      return; 
     } 
    } 
} 


public static void main(String[] args) throws IOException { 
    // just for test: 
    JsonReader jr = new JsonReader(new StringReader("{\"a\":1, \"b\":{\"c\":[1,2,3,{},{}]}}")); 
    StringWriter sw = new StringWriter(); 
    JsonWriter jw = new JsonWriter(sw); 
    streamandmodify(jr, jw); 
    System.out.println(sw.getBuffer().toString()); 
} 
} 
+0

Un bell'esempio di ciò che JsonWriter può fare, questo è sicuro. Ma per il compito dell'OP, non c'è alcun motivo per ricreare l'oggetto JSON tramite streaming invece di usare gson.fromJson() ben testato. Vedi la risposta di Jeff. – teejay

+0

@teejay: "nessun motivo"? come lo sapresti? perché questo commento? Posso trovare alcune buone ragioni per NON costruire un'intera rappresentazione in memoria di un documento JSON arbitrariamente grande solo per aggiungere alcune proprietà e, per esempio, serializzare l'intera cosa in un file. Nessuno dei due conosce il contesto della domanda, quindi sia l'approccio razionalizzato sia quello dominante sembrano essere migliori. – fdreger

+0

Bene, presumo che le persone che si avvicinano a questa pagina vogliono risolvere il loro problema - cioè modificare JSON da una stringa che è già completamente disponibile per loro (= nessun motivo per lo streaming). La tua risposta "funziona", ma sarebbe più appropriata in un altro contesto. Senza offesa :) – teejay

0

Il jsonString è una pianura, ordinario String Java; in modo da poter modificarlo qualunque cosa ti piace usare le funzioni standard di stringa di Java e sostituire la sottostringa key1 con Test1:

jsonString = "[{\"key1\":\"Test\",\"key2\":\"World\"},{\"key1\":\"Nice\",\"key2\":\"Town\"}]"; 

Naturalmente, String in Java sono immutabili in modo da convertirlo prima in uno StringBuilder sarà eventualmente un dare prestazioni migliori in termini di utilizzo della memoria.

+2

Questa è una strategia decente-se-hacky nel codice di test, ma attenzione nella produzione se l'originale o la stringa o la sostituzione sono forniti dall'utente. JavaScript (e JSON per estensione) è piuttosto complicato nella gestione di escape e caratteri speciali. Probabilmente vuoi lasciare che una libreria ben testata modifichi il tuo JSON in produzione. –

+0

Probabilmente hai sbagliato la domanda. Sono interessato a modificare il valore di key1 e non key1 stesso. Quindi, nel primo caso, il valore di key1 è Hello, che ho voluto modificare. – linuxeasy

+0

Oh, la risposta rimane la stessa; è solo l'esempio che deve essere cambiato. – SylvainL

1

È sempre possibile ottenere un tipo diverso da JsonElement oppure utilizzare JsonElement.getAsJsonObject per eseguire il cast su un oggetto (se possibile).

String jsonString = "[{\"key1\":\"Hello\",\"key2\":\"World\"}, ...]"; 

JsonArray jsonArray = gson.fromJson(jsonString, JsonElement.class).getAsJsonArray(); 
JsonObject firstObject = jsonArray.get(i).getAsJsonObject(); 
firstObject.addProperty("key1", "Test"); 

Mi sono sbagliato in precedenza; sembra non esserci un adattatore JsonArray; dovrai ottenere un JsonElement e usare lo strumento di lancio.

6

Ecco il più breve che ho trovato.

JsonElement je = gson.fromJson(jsonString, JsonElement.class); 
JsonObject jo = je.getAsJsonObject(); 
jo.add("key", value); 

Una volta che avete JsonObject, gson ha molti metodi per manipolarlo.

Problemi correlati