Gson serialization: exclude SOME fields if null, but not all of them

Given POJO:

class Person {
    @Expose
    String name;
    @Expose
    String phone;
    @Expose
    String fax;
}

I want the "phone" to be always serialized, but the "fax" only if it is not zero. So what was given to the John man without a telephone or fax:

Current:

{ "name": "John", "phone": null, "fax": null }

What I need:

{ "name": "John", "phone": null }

Is there something like:

@Expose (serialize_if_null = false)

the transient is not working because I still want to serialize it if it matters.

Using ExclusionStrategy, I can define the field, but I cannot find a way to get the value.

thank

+4
source share
1 answer

Using ExclusionStrategy, I can define the field, but I cannot find a way to get the value.

Yes, this does not provide a way to determine the current value of the field. This is because Gson ReflectiveTypeAdapterFactoryworks internally ( BoundField.serialized- finaland is only allowed once):

@Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
  if (!serialized) return false;
  Object fieldValue = field.get(value);
  return fieldValue != value; // avoid recursion for example for Throwable.cause
}
for (BoundField boundField : boundFields.values()) {
  if (boundField.writeField(value)) {
    out.name(boundField.name);
    boundField.write(out, value);
  }
}

, (. ) , , ( Gson - DTO).

DTO , DTO : phone fax fax.

class PersonDto {
    @Expose String name;
    @Expose String phone;
    PersonDto(final Person person) {
        name = person.name;
        phone = person.phone;
    }
}
class PersonDtoWithFax extends PersonDto {
    @Expose String fax;
    PersonDtoWithFax(final Person person) {
        super(person);
        fax = person.fax;
    }
}

:

final Gson gson = new GsonBuilder()
        .serializeNulls()
        .create();
final Person person = new Person();
person.name = "John";
final PersonDto personDto = person.fax == null
        ? new PersonDto(person)
        : new PersonDtoWithFax(person);
System.out.println(gson.toJson(personDto));

DTO , , , , , - ( , java.lang.reflect.Field).

final class SpecialJsonSerializer<T>
        implements JsonSerializer<T> {

    private final Gson gson; // Unfortunately, Gson does not provide much from JsonSerialiationContext, so we have to get it ourselves
    private final Iterable<String> excludeIfNull;

    private SpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) {
        this.gson = gson;
        this.excludeIfNull = excludeIfNull;
    }

    static <T> JsonSerializer<T> getSpecialJsonSerializer(final Gson gson, final Iterable<String> excludeIfNull) {
        return new SpecialJsonSerializer<>(gson, excludeIfNull);
    }

    @Override
    public JsonElement serialize(final T object, final Type type, final JsonSerializationContext context) {
        // context.serialize(person, type) cannot work due to infinite recursive serialization
        // therefore the backing Gson instance is used
        final JsonObject jsonObject = gson.toJsonTree(object, type).getAsJsonObject();
        for ( final String propertyName : excludeIfNull ) {
            final JsonElement property = jsonObject.get(propertyName);
            if ( property != null && property.isJsonNull() ) {
                jsonObject.remove(propertyName);
            }
        }
        return jsonObject;
    }

}

, , JSON , DTO, ( - JsonElement).

// Both Gson instances must have serializeNulls()
final Gson gson = new GsonBuilder()
        .serializeNulls()
        .create();
final Gson gsonWrapper = new GsonBuilder()
        .serializeNulls()
        .registerTypeAdapter(Person.class, getSpecialJsonSerializer(gson, singletonList("fax")))
        .create();
final Person person = new Person();
person.name = "John";
System.out.println(gsonWrapper.toJson(person));

:

{ "": "", "": }

+1

Source: https://habr.com/ru/post/1671099/


All Articles