2013-08-28 13 views
26

Ho bisogno di dove devo convertire java object in json.Gson Serializza il campo solo se non è nullo o non vuoto

Sto utilizzando GSON per questo, ma ho bisogno del convertitore per serializzare solo valori non nulli o non vuoti.

Ad esempio:

//my java object looks like 
class TestObject{ 
    String test1; 
    String test2; 
    OtherObject otherObject = new OtherObject(); 
} 

ora il mio esempio GSON per convertire questo oggetto per JSON sembra

Gson gson = new Gson(); 
TestObject obj = new TestObject(); 
obj.test1 = "test1"; 
obj.test2 = ""; 

String jsonStr = gson.toJson(obj); 
println jsonStr; 

Nella stampa sopra, il risultato è

{"test1":"test1", "test2":"", "otherObject":{}} 

Qui i volevo solo che il risultato fosse

{"test1":"test1"} 

Poiché test2 è vuoto e otherObject è vuoto, non voglio che vengano serializzati su dati json.

Btw, sto usando Groovy/Grails, quindi se c'è qualche plugin per questo sarebbe buono, se nessun suggerimento per personalizzare la classe di serializzazione gson sarebbe buono.

+1

Come fa a sapere che 'otherObject' è vuoto? –

risposta

20

Crea il tuo TypeAdapter

public class MyTypeAdapter extends TypeAdapter<TestObject>() { 

    @Override 
    public void write(JsonWriter out, TestObject value) throws IOException { 
     out.beginObject(); 
     if (!Strings.isNullOrEmpty(value.test1)) { 
      out.name("test1"); 
      out.value(value.test1); 
     } 

     if (!Strings.isNullOrEmpty(value.test2)) { 
      out.name("test2"); 
      out.value(value.test1); 
     } 
     /* similar check for otherObject */   
     out.endObject();  
    } 

    @Override 
    public TestObject read(JsonReader in) throws IOException { 
     // do something similar, but the other way around 
    } 
} 

È possibile quindi registrarlo con Gson.

Gson gson = new GsonBuilder().registerTypeAdapter(TestObject.class, new MyTypeAdapter()).create(); 
TestObject obj = new TestObject(); 
obj.test1 = "test1"; 
obj.test2 = ""; 
System.out.println(gson.toJson(obj)); 

produce

{"test1":"test1"} 

La classe GsonBuilder ha un sacco di metodi per creare le proprie strategie di serializzazione/deserializzazione, registrare gli adattatori di tipo, e impostare altri parametri.

Strings è una classe Guava. Hai il controllo se non vuoi questa dipendenza.

+1

cosa succede se ho altri oggetti diversi nella mia classe TestObject. ad esempio: in genere la mia classe avrà più oggetti incorporati di tipo diverso – zdesam

+0

@zdesam Effettua la serializzazione nidificata in questa classe. Questa classe dipende completamente dalla classe 'TestObject', quindi è più indicata per eseguire tutte le sue serializzazioni/deserializzazioni. Nessun altro componente può verificare le condizioni personalizzate che desideri. –

+0

Con tali omettere stringhe vuote in ogni classe, la tua soluzione si riduce a fare tutto manualmente. Anche serializzare tutti i campi che non richiedono alcuna gestione speciale. Non c'è molto di ciò che Gson lascia. – maaartinus

3

Mi sembra che il problema non sia con gson. Gson tiene correttamente traccia della differenza tra null e una stringa vuota. Sei sicuro di voler cancellare questa distinzione? Sei sicuro che tutte le classi che usano TestObject non si preoccupino?

Quello che potresti fare se non ti interessa la differenza è di cambiare le stringhe vuote in null all'interno di un TestObject prima di serializzarlo. O meglio, imposta i setter in TestObject in modo tale che una stringa vuota sia impostata su null; in questo modo definisci rigidamente all'interno della classe che una stringa vuota è uguale a null. Dovrai assicurarti che i valori non possano essere impostati all'esterno dei setter.

+0

Buon punto, ma spesso non si vogliono usare entrambi "" "' e 'null'. La soluzione saner probabilmente sta evitando 'null' e usando' "" "solo. Altre librerie potrebbero funzionare meglio con stringhe vuote che con valori null. * I database possono forzare NOT NULL ma non possono forzare "non vuoto". * +++ La normalizzazione a null non è un'opzione per me poiché i miei oggetti sono al punto ancora attaccati a una sessione di Hibernate. – maaartinus

3

Quello che personalmente non mi piace in TypeAdapter utilizzando risposta è il fatto è necessario per descrivere tutti i campi della vostra intera classe che potrebbe avere permette di dire 50 campi (che significa 50 if blocchi in TypeAdapter).
La mia soluzione è basata su Reflection e un fatto Gson non serializzerà i campi di valori nulli per impostazione predefinita.
Ho una classe speciale che contiene i dati per l'API per creare un documento chiamato DocumentModel, che ha circa 50 campi e non mi piace inviare i campi String con valori "" o array vuoti al server.Così ho creato un metodo speciale che mi restituisce una copia del mio oggetto con tutti i campi vuoti annullati. Nota: per impostazione predefinita, tutti gli array nell'istanza DocumentModel vengono inizializzati come array vuoti (lunghezza zero) e quindi non sono mai nulli, è consigliabile controllare gli array per null prima di controllarne la lunghezza.

public DocumentModel getSerializableCopy() { 
    Field fields[] = new Field[]{}; 
    try { 
     // returns the array of Field objects representing the public fields 
     fields = DocumentModel.class.getDeclaredFields(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 
    DocumentModel copy = new DocumentModel(); 
    Object value; 
    for (Field field : fields) { 
     try { 
      value = field.get(this); 
      if (value instanceof String && TextUtils.isEmpty((String) value)) { 
       field.set(copy, null); 
      // note: here array is not being checked for null! 
      else if (value instanceof Object[] && ((Object[]) value).length == 0) { 
       field.set(copy, null); 
      } else 
       field.set(copy, value); 
     } catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 
    return copy; 
} 

Utilizzando questo metodo non mi interessa se alcuni campi sono stati aggiunti dopo che questo metodo è stato scritto o altro. L'unico problema rimasto è la verifica dei campi di tipo personalizzato, che non sono String o array, ma questo dipende da una particolare classe e dovrebbe essere codificato in più se/else blocchi.

Problemi correlati