2013-08-28 18 views
26

Mam wymagania, gdzie muszę przekonwertować obiekt java na json.Gson Serialize pole tylko jeśli nie jest puste lub nie puste

Używam Gson do tego, ale muszę konwerter tylko serializować wartości nie puste lub puste.

Na przykład:

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

teraz moje instancji Gson aby przekształcić ten obiekt do JSON wygląda

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

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

W powyższym nadrukiem, wynik jest

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

Oto ja chciałem, aby wynik był

{"test1":"test1"} 

Ponieważ test2 jest pusty, a obiekt otherObject jest pusty, nie chcę, aby były serializowane do danych json.

Btw, używam Groovy/Grails, więc jeśli istnieje jakaś wtyczka do tego, która byłaby dobra, gdyby nie sugestia, aby dostosować klasę gson do serializacji byłaby dobra.

+1

Skąd wiadomo, że "otherObject" jest puste? –

Odpowiedz

20

Stwórz własną 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 
    } 
} 

Następnie można zarejestrować go z 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)); 

produkuje

{"test1":"test1"} 

Klasa GsonBuilder ma kilka metod, aby tworzyć własne strategie serializacji/deserializacji, zarejestruj adaptery typu, i ustawić inne parametry.

Strings jest klasą guawy. Czy jesteś właścicielem, czy nie chcesz tej zależności?

+1

co jeśli mam inne obiekty na mojej klasie TestObject. na przykład: ogólnie moja klasa będzie miała wiele osadzonych obiektów innego typu: – zdesam

+0

@zdesam Wykonujesz serializację zagnieżdżoną w tej klasie. Ta klasa jest całkowicie zależna od klasy 'TestObject', więc najlepiej nadaje się do jej serializacji/deserializacji. Żaden inny komponent nie może sprawdzić pożądanych warunków niestandardowych. –

+0

Mając takie, które mają być pominięte puste struny w zgrabnie każdej klasie, Twoje rozwiązanie sprowadza się do robienia wszystkiego ręcznie. Nawet szeregowanie wszystkich pól, które nie wymagają specjalnej obsługi. Nie ma zbyt wiele tego, co pozostało Gsonowi. – maaartinus

3

Wydaje mi się, że problem nie dotyczy gson. Gson poprawnie śledzi różnicę między pustym łańcuchem a pustym łańcuchem znaków. Czy na pewno chcesz usunąć to wyróżnienie? Czy na pewno nie obchodzi Cię wszystkie klasy korzystające z TestObject?

Co możesz zrobić, jeśli nie przejmujesz się różnicą, to zmiana pustych łańcuchów na wartość null w obiekcie testowym przed serializacją. Lub lepiej, ustaw settery w TestObject tak, aby pusty łańcuch był ustawiony na null; w ten sposób definiując sztywno w klasie, pusty łańcuch jest taki sam jak zerowy. Musisz upewnić się, że wartości nie można ustawić poza ustawieniami.

+0

Dobrze, ale często nie chcesz używać zarówno '' "' jak i 'null'. Rozwiązanie saner prawdopodobnie unika 'null' i używa tylko' '" '. Inne biblioteki mogą działać lepiej z pustymi ciągami niż z zerami. * Bazy danych mogą wymuszać NOT NULL, ale nie mogą wymuszać "nie są puste". ++ +++ Normalizowanie do wartości zerowych nie jest dla mnie opcją, ponieważ moje obiekty są w tym samym czasie, w którym są dołączone do sesji Hibernate. – maaartinus

3

To, czego osobiście nie lubię w TypeAdapter za pomocą odpowiedzi, to fakt, że musisz opisać każde pole z całej twojej klasy, które mogłoby powiedzieć 50 pól (co oznacza 50 if bloków w TypeAdapter).
Moje rozwiązanie oparte jest na Reflection, a fakt, że Gson nie będzie serializować domyślnie pól wartości zerowych.
Mam specjalną klasę, która przechowuje dane dla API, aby utworzyć dokument o nazwie DocumentModel, który ma około 50 pól i nie lubię wysyłać pól "" lub pustych tablic na serwer.Stworzyłem więc specjalną metodę, która zwraca mi kopię mojego obiektu z pustymi polami pustymi. Uwaga: domyślnie wszystkie tablice w mojej instancji DocumentModel są inicjowane jako puste (zero length) tablice, a więc nigdy nie są puste, prawdopodobnie powinieneś sprawdzić tablice zerowe przed sprawdzeniem ich długości.

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

Korzystając z tej metody nie obchodzi mnie, że niektóre pola zostały dodane po napisaniu tej metody lub cokolwiek innego. Pozostaje tylko problem - sprawdzanie pól typu niestandardowego, które nie są String lub tablic, ale zależy to od konkretnej klasy i powinno być dodatkowo zakodowane, jeśli/else blokuje.

Powiązane problemy