diff --git a/encoders/firebase-encoders-json/api.txt b/encoders/firebase-encoders-json/api.txt index 947497afe02..ebf7a8685f0 100644 --- a/encoders/firebase-encoders-json/api.txt +++ b/encoders/firebase-encoders-json/api.txt @@ -72,6 +72,7 @@ package com.google.firebase.encoders.json { ctor public JsonDataEncoderBuilder(); method @NonNull public com.google.firebase.encoders.DataEncoder build(); method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder configureWith(@NonNull com.google.firebase.encoders.config.Configurator); + method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder ignoreNullValues(boolean); method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder registerEncoder(@NonNull Class, @NonNull com.google.firebase.encoders.ObjectEncoder); method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder registerEncoder(@NonNull Class, @NonNull com.google.firebase.encoders.ValueEncoder); method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder registerFallbackEncoder(@NonNull com.google.firebase.encoders.ObjectEncoder); diff --git a/encoders/firebase-encoders-json/gradle.properties b/encoders/firebase-encoders-json/gradle.properties index 1c68d126d26..94dcffed351 100644 --- a/encoders/firebase-encoders-json/gradle.properties +++ b/encoders/firebase-encoders-json/gradle.properties @@ -12,4 +12,4 @@ # See the License for the specific language governing permissions and # limitations under the License. -version=16.0.1 +version=16.1.0 diff --git a/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonDataEncoderBuilder.java b/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonDataEncoderBuilder.java index 847660431a4..0ea6307130c 100644 --- a/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonDataEncoderBuilder.java +++ b/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonDataEncoderBuilder.java @@ -35,7 +35,7 @@ public final class JsonDataEncoderBuilder implements EncoderConfig { - private final ObjectEncoder DEFAULT_FALLBACK_ENCODER = + private static final ObjectEncoder DEFAULT_FALLBACK_ENCODER = (o, ctx) -> { throw new EncodingException( "Couldn't find encoder for type " + o.getClass().getCanonicalName()); @@ -44,6 +44,7 @@ public final class JsonDataEncoderBuilder implements EncoderConfig, ObjectEncoder> objectEncoders = new HashMap<>(); private final Map, ValueEncoder> valueEncoders = new HashMap<>(); private ObjectEncoder fallbackEncoder = DEFAULT_FALLBACK_ENCODER; + private boolean ignoreNullValues = false; private static final class TimestampEncoder implements ValueEncoder { private static final DateFormat rfc339; @@ -104,6 +105,12 @@ public JsonDataEncoderBuilder configureWith(@NonNull Configurator config) { return this; } + @NonNull + public JsonDataEncoderBuilder ignoreNullValues(boolean ignore) { + this.ignoreNullValues = ignore; + return this; + } + @NonNull public DataEncoder build() { return new DataEncoder() { @@ -112,7 +119,7 @@ public void encode(@NonNull Object o, @NonNull Writer writer) throws IOException, EncodingException { JsonValueObjectEncoderContext encoderContext = new JsonValueObjectEncoderContext( - writer, objectEncoders, valueEncoders, fallbackEncoder); + writer, objectEncoders, valueEncoders, fallbackEncoder, ignoreNullValues); encoderContext.add(o, false); encoderContext.close(); } diff --git a/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonValueObjectEncoderContext.java b/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonValueObjectEncoderContext.java index 2a8a94e1cfc..9f37311d4ba 100644 --- a/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonValueObjectEncoderContext.java +++ b/encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonValueObjectEncoderContext.java @@ -37,16 +37,19 @@ final class JsonValueObjectEncoderContext implements ObjectEncoderContext, Value private final Map, ObjectEncoder> objectEncoders; private final Map, ValueEncoder> valueEncoders; private final ObjectEncoder fallbackEncoder; + private final boolean ignoreNullValues; JsonValueObjectEncoderContext( @NonNull Writer writer, @NonNull Map, ObjectEncoder> objectEncoders, @NonNull Map, ValueEncoder> valueEncoders, - ObjectEncoder fallbackEncoder) { + ObjectEncoder fallbackEncoder, + boolean ignoreNullValues) { this.jsonWriter = new JsonWriter(writer); this.objectEncoders = objectEncoders; this.valueEncoders = valueEncoders; this.fallbackEncoder = fallbackEncoder; + this.ignoreNullValues = ignoreNullValues; } private JsonValueObjectEncoderContext(JsonValueObjectEncoderContext anotherContext) { @@ -54,19 +57,17 @@ private JsonValueObjectEncoderContext(JsonValueObjectEncoderContext anotherConte this.objectEncoders = anotherContext.objectEncoders; this.valueEncoders = anotherContext.valueEncoders; this.fallbackEncoder = anotherContext.fallbackEncoder; + this.ignoreNullValues = anotherContext.ignoreNullValues; } @NonNull @Override public JsonValueObjectEncoderContext add(@NonNull String name, @Nullable Object o) throws IOException, EncodingException { - maybeUnNest(); - jsonWriter.name(name); - if (o == null) { - jsonWriter.nullValue(); - return this; + if (ignoreNullValues) { + return internalAddIgnoreNullValues(name, o); } - return add(o, false); + return internalAdd(name, o); } @NonNull @@ -311,4 +312,25 @@ private void maybeUnNest() throws IOException { jsonWriter.endObject(); } } + + private JsonValueObjectEncoderContext internalAdd(@NonNull String name, @Nullable Object o) + throws IOException, EncodingException { + maybeUnNest(); + jsonWriter.name(name); + if (o == null) { + jsonWriter.nullValue(); + return this; + } + return add(o, false); + } + + private JsonValueObjectEncoderContext internalAddIgnoreNullValues( + @NonNull String name, @Nullable Object o) throws IOException, EncodingException { + if (o == null) { + return this; + } + maybeUnNest(); + jsonWriter.name(name); + return add(o, false); + } } diff --git a/encoders/firebase-encoders-json/src/test/java/com/google/firebase/encoders/json/JsonDataEncoderBuilderTests.java b/encoders/firebase-encoders-json/src/test/java/com/google/firebase/encoders/json/JsonDataEncoderBuilderTests.java index fe7275f7ade..4f2ded9e70f 100644 --- a/encoders/firebase-encoders-json/src/test/java/com/google/firebase/encoders/json/JsonDataEncoderBuilderTests.java +++ b/encoders/firebase-encoders-json/src/test/java/com/google/firebase/encoders/json/JsonDataEncoderBuilderTests.java @@ -22,6 +22,7 @@ import com.google.firebase.encoders.ObjectEncoderContext; import com.google.firebase.encoders.ValueEncoderContext; import java.util.Collections; +import java.util.HashMap; import org.junit.Test; import org.junit.runner.RunWith; @@ -61,4 +62,44 @@ public void configureWith_shouldCorrectlyRegisterValueEncoder() throws EncodingE assertThat(encoder.encode(Collections.singletonMap("foo", new Foo()))) .isEqualTo("{\"foo\":\"value\"}"); } + + @Test + public void ignoreNullValues_shouldCorrectlyEncodeObjectIgnoringNullObjects() + throws EncodingException { + DataEncoder encoder = + new JsonDataEncoderBuilder() + .configureWith( + cfg -> + cfg.registerEncoder( + Foo.class, + (Foo s, ObjectEncoderContext ctx) -> { + ctx.add("foo", "value"); + ctx.add("bar", null); + })) + .ignoreNullValues(true) + .build(); + + assertThat(encoder.encode(new Foo())).isEqualTo("{\"foo\":\"value\"}"); + } + + @Test + public void ignoreNullValues_shouldCorrectlyEncodeValueIgnoringNullObjects() + throws EncodingException { + DataEncoder encoder = + new JsonDataEncoderBuilder() + .configureWith( + cfg -> + cfg.registerEncoder( + Foo.class, + (Foo s, ValueEncoderContext ctx) -> { + ctx.add("value"); + })) + .ignoreNullValues(true) + .build(); + + HashMap fooMap = new HashMap<>(); + fooMap.put("foo", new Foo()); + fooMap.put("bar", null); + assertThat(encoder.encode(fooMap)).isEqualTo("{\"foo\":\"value\"}"); + } }