2013-08-28 2 views
26

У меня есть требование, где мне нужно преобразовать java-объект в json.Gson Сериализовать поле только если не пустым или не пустым

Я использую для этого Gson, но мне нужен конвертер для сериализации не нулевых или не пустых значений.

Например:

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

теперь мой экземпляр Gson, чтобы превратить этот объект в JSON выглядит

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

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

В вышеприведенном печати, результат

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

Здесь я просто хотел, чтобы результат был

{"test1":"test1"} 

Поскольку test2 пуст, а otherObject пуст, я не хочу, чтобы они были сериализованы для json-данных.

Btw, я использую Groovy/Grails, поэтому, если для этого есть какой-либо плагин, это было бы хорошо, если бы не было никаких предложений по настройке класса сериализации gson.

+1

Как узнать, что 'otherObject' пуст? –

ответ

20

Создайте свой собственный 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 
    } 
} 

Вы можете зарегистрировать его с 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)); 

производит

{"test1":"test1"} 

GsonBuilder класс имеет кучу методов, чтобы создать свои собственные стратегии сериализации/десериализации, регистрировать адаптеры типа, и задать другие параметры.

Strings - класс Гува. У вас есть чек, если вы не хотите эту зависимость.

+1

Что делать, если у меня есть другие объекты в классе TestObject. для ex: обычно мой класс будет иметь несколько встроенных объектов различного типа – zdesam

+0

@zdesam. Вы вставляете сериализацию в этом классе. Этот класс полностью зависит от вашего класса TestObject, поэтому он лучше всего подходит для всей сериализации/десериализации. Ни один другой компонент не может проверить пользовательские условия, которые вы хотите. –

+0

Если у вас есть опускаемые пустые строки в каждом классе, ваше решение сводится к тому, чтобы делать все вручную. Даже сериализация всех полей, не требующих специальной обработки. Мало того, что у Гссона осталось. – maaartinus

3

Мне кажется, проблема не в gson. Gson правильно отслеживает разницу между нулевой и пустой строкой. Вы уверены, что хотите стереть это различие? Вы уверены, что все классы, использующие TestObject, не заботятся?

Что вы можете сделать, если вам не нужна разница, это изменить пустые строки до нуля в TestObject перед его сериализацией. Или лучше, сделайте сеттеры в TestObject таким образом, чтобы пустая строка была равна нулю; таким образом вы строго определяете внутри класса, что пустая строка совпадает с нулевой. Вы должны будете убедиться, что значения не могут быть установлены за пределами сеттеров.

+0

Хорошая мысль, но часто вы не хотите использовать как '' '', так и 'null'. Решение saner, вероятно, избегает «null» и использует '' '' только. Другие библиотеки могут работать лучше с пустыми строками, чем с нулями. * Базы данных могут принудительно выполнять NOT NULL, но они не могут принудительно использовать «не пусто». * +++ Нормализация до нулей не является для меня вариантом, поскольку мои объекты находятся в точке, все еще привязанной к сеансу Hibernate. – maaartinus

3

Что мне лично не нравится в TypeAdapter, используя ответ, так это то, что вам нужно описать каждое поле вашего всего класса, которое могло бы дать 50 полей (что означает 50 if блоков в TypeAdapter).
Мое решение основано на Reflection, и факт Gson не будет сериализовать поля нулевых значений по умолчанию.
У меня есть специальный класс, который содержит данные для API для создания документа под названием DocumentModel, который имеет около 50 полей, и мне не нравится отправлять поля String с значениями «» или пустым массивом на сервер.Поэтому я создал специальный метод, который возвращает мне копию моего объекта со всеми пустыми полями. Примечание. По умолчанию все массивы в моем экземпляре DocumentModel инициализируются как пустые (нулевые длины) массивы и, следовательно, они никогда не являются нулевыми, вы должны, вероятно, проверить свои массивы на нуль, прежде чем проверять их длину.

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

Использование этого метода Мне все равно, были ли добавлены некоторые поля после того, как этот метод был написан или что-то еще. Единственная проблема - проверка полей настраиваемого типа, которые не являются String или массивом, но это зависит от конкретного класса и должно быть дополнительно закодировано в блоках if/else.

Смежные вопросы