Подтвердить что ты не робот

Поле Gson Serialize, если оно не пустое или не пустое

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

Я использую 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.

4b9b3361

Ответ 1

Создайте свой собственный 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 - это класс Guava. У вас есть чек, если вы не хотите эту зависимость.

Ответ 2

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

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

Ответ 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.