Skip to content

Add support for ignoring nulls in JsonDataEncoder #1175

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jan 30, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions encoders/firebase-encoders-json/api.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 <T> com.google.firebase.encoders.json.JsonDataEncoderBuilder registerEncoder(@NonNull Class<T>, @NonNull com.google.firebase.encoders.ObjectEncoder<? super T>);
method @NonNull public <T> com.google.firebase.encoders.json.JsonDataEncoderBuilder registerEncoder(@NonNull Class<T>, @NonNull com.google.firebase.encoders.ValueEncoder<? super T>);
method @NonNull public com.google.firebase.encoders.json.JsonDataEncoderBuilder registerFallbackEncoder(@NonNull com.google.firebase.encoders.ObjectEncoder<java.lang.Object>);
Expand Down
2 changes: 1 addition & 1 deletion encoders/firebase-encoders-json/gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -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
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@

public final class JsonDataEncoderBuilder implements EncoderConfig<JsonDataEncoderBuilder> {

private final ObjectEncoder<Object> DEFAULT_FALLBACK_ENCODER =
private static final ObjectEncoder<Object> DEFAULT_FALLBACK_ENCODER =
(o, ctx) -> {
throw new EncodingException(
"Couldn't find encoder for type " + o.getClass().getCanonicalName());
Expand All @@ -44,6 +44,7 @@ public final class JsonDataEncoderBuilder implements EncoderConfig<JsonDataEncod
private final Map<Class<?>, ObjectEncoder<?>> objectEncoders = new HashMap<>();
private final Map<Class<?>, ValueEncoder<?>> valueEncoders = new HashMap<>();
private ObjectEncoder<Object> fallbackEncoder = DEFAULT_FALLBACK_ENCODER;
private boolean ignoreNullValues = false;

private static final class TimestampEncoder implements ValueEncoder<Date> {
private static final DateFormat rfc339;
Expand Down Expand Up @@ -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() {
Expand All @@ -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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,36 +37,37 @@ final class JsonValueObjectEncoderContext implements ObjectEncoderContext, Value
private final Map<Class<?>, ObjectEncoder<?>> objectEncoders;
private final Map<Class<?>, ValueEncoder<?>> valueEncoders;
private final ObjectEncoder<Object> fallbackEncoder;
private final boolean ignoreNullValues;

JsonValueObjectEncoderContext(
@NonNull Writer writer,
@NonNull Map<Class<?>, ObjectEncoder<?>> objectEncoders,
@NonNull Map<Class<?>, ValueEncoder<?>> valueEncoders,
ObjectEncoder<Object> fallbackEncoder) {
ObjectEncoder<Object> fallbackEncoder,
boolean ignoreNullValues) {
this.jsonWriter = new JsonWriter(writer);
this.objectEncoders = objectEncoders;
this.valueEncoders = valueEncoders;
this.fallbackEncoder = fallbackEncoder;
this.ignoreNullValues = ignoreNullValues;
}

private JsonValueObjectEncoderContext(JsonValueObjectEncoderContext anotherContext) {
this.jsonWriter = anotherContext.jsonWriter;
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
Expand Down Expand Up @@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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<String, Foo> fooMap = new HashMap<>();
fooMap.put("foo", new Foo());
fooMap.put("bar", null);
assertThat(encoder.encode(fooMap)).isEqualTo("{\"foo\":\"value\"}");
}
}