Skip to content

Commit c21ccae

Browse files
committed
Add support for ignoring nulls in JsonDataEncoder
1 parent 30f71bb commit c21ccae

File tree

3 files changed

+81
-10
lines changed

3 files changed

+81
-10
lines changed

encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonDataEncoderBuilder.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535

3636
public final class JsonDataEncoderBuilder implements EncoderConfig<JsonDataEncoderBuilder> {
3737

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

4849
private static final class TimestampEncoder implements ValueEncoder<Date> {
4950
private static final DateFormat rfc339;
@@ -104,6 +105,12 @@ public JsonDataEncoderBuilder configureWith(@NonNull Configurator config) {
104105
return this;
105106
}
106107

108+
@NonNull
109+
public JsonDataEncoderBuilder ignoreNulls(boolean ignore) {
110+
this.ignoreNulls = ignore;
111+
return this;
112+
}
113+
107114
@NonNull
108115
public DataEncoder build() {
109116
return new DataEncoder() {
@@ -112,7 +119,7 @@ public void encode(@NonNull Object o, @NonNull Writer writer)
112119
throws IOException, EncodingException {
113120
JsonValueObjectEncoderContext encoderContext =
114121
new JsonValueObjectEncoderContext(
115-
writer, objectEncoders, valueEncoders, fallbackEncoder);
122+
writer, objectEncoders, valueEncoders, fallbackEncoder, ignoreNulls);
116123
encoderContext.add(o, false);
117124
encoderContext.close();
118125
}

encoders/firebase-encoders-json/src/json/java/com/google/firebase/encoders/json/JsonValueObjectEncoderContext.java

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -31,42 +31,45 @@
3131

3232
final class JsonValueObjectEncoderContext implements ObjectEncoderContext, ValueEncoderContext {
3333

34+
private interface AddMethod {
35+
JsonValueObjectEncoderContext invoke(@NonNull String name, @Nullable Object o)
36+
throws IOException, EncodingException;
37+
}
38+
3439
private JsonValueObjectEncoderContext childContext = null;
3540
private boolean active = true;
3641
private final JsonWriter jsonWriter;
3742
private final Map<Class<?>, ObjectEncoder<?>> objectEncoders;
3843
private final Map<Class<?>, ValueEncoder<?>> valueEncoders;
3944
private final ObjectEncoder<Object> fallbackEncoder;
45+
private final AddMethod addMethod;
4046

4147
JsonValueObjectEncoderContext(
4248
@NonNull Writer writer,
4349
@NonNull Map<Class<?>, ObjectEncoder<?>> objectEncoders,
4450
@NonNull Map<Class<?>, ValueEncoder<?>> valueEncoders,
45-
ObjectEncoder<Object> fallbackEncoder) {
51+
ObjectEncoder<Object> fallbackEncoder,
52+
boolean ignoreNulls) {
4653
this.jsonWriter = new JsonWriter(writer);
4754
this.objectEncoders = objectEncoders;
4855
this.valueEncoders = valueEncoders;
4956
this.fallbackEncoder = fallbackEncoder;
57+
this.addMethod = ignoreNulls ? this::internalAddIgnoreNulls : this::internalAdd;
5058
}
5159

5260
private JsonValueObjectEncoderContext(JsonValueObjectEncoderContext anotherContext) {
5361
this.jsonWriter = anotherContext.jsonWriter;
5462
this.objectEncoders = anotherContext.objectEncoders;
5563
this.valueEncoders = anotherContext.valueEncoders;
5664
this.fallbackEncoder = anotherContext.fallbackEncoder;
65+
this.addMethod = anotherContext.addMethod;
5766
}
5867

5968
@NonNull
6069
@Override
6170
public JsonValueObjectEncoderContext add(@NonNull String name, @Nullable Object o)
6271
throws IOException, EncodingException {
63-
maybeUnNest();
64-
jsonWriter.name(name);
65-
if (o == null) {
66-
jsonWriter.nullValue();
67-
return this;
68-
}
69-
return add(o, false);
72+
return addMethod.invoke(name, o);
7073
}
7174

7275
@NonNull
@@ -311,4 +314,25 @@ private void maybeUnNest() throws IOException {
311314
jsonWriter.endObject();
312315
}
313316
}
317+
318+
private JsonValueObjectEncoderContext internalAdd(@NonNull String name, @Nullable Object o)
319+
throws IOException, EncodingException {
320+
maybeUnNest();
321+
jsonWriter.name(name);
322+
if (o == null) {
323+
jsonWriter.nullValue();
324+
return this;
325+
}
326+
return add(o, false);
327+
}
328+
329+
private JsonValueObjectEncoderContext internalAddIgnoreNulls(
330+
@NonNull String name, @Nullable Object o) throws IOException, EncodingException {
331+
if (o == null) {
332+
return this;
333+
}
334+
maybeUnNest();
335+
jsonWriter.name(name);
336+
return add(o, false);
337+
}
314338
}

encoders/firebase-encoders-json/src/test/java/com/google/firebase/encoders/json/JsonDataEncoderBuilderTests.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.google.firebase.encoders.ObjectEncoderContext;
2323
import com.google.firebase.encoders.ValueEncoderContext;
2424
import java.util.Collections;
25+
import java.util.HashMap;
2526
import org.junit.Test;
2627
import org.junit.runner.RunWith;
2728

@@ -61,4 +62,43 @@ public void configureWith_shouldCorrectlyRegisterValueEncoder() throws EncodingE
6162
assertThat(encoder.encode(Collections.singletonMap("foo", new Foo())))
6263
.isEqualTo("{\"foo\":\"value\"}");
6364
}
65+
66+
@Test
67+
public void ignoreNulls_shouldCorrectlyEncodeObjectIgnoringNullObjects()
68+
throws EncodingException {
69+
DataEncoder encoder =
70+
new JsonDataEncoderBuilder()
71+
.configureWith(
72+
cfg ->
73+
cfg.registerEncoder(
74+
Foo.class,
75+
(Foo s, ObjectEncoderContext ctx) -> {
76+
ctx.add("foo", "value");
77+
ctx.add("bar", null);
78+
}))
79+
.ignoreNulls(true)
80+
.build();
81+
82+
assertThat(encoder.encode(new Foo())).isEqualTo("{\"foo\":\"value\"}");
83+
}
84+
85+
@Test
86+
public void ignoreNulls_shouldCorrectlyEncodeValueIgnoringNullObjects() throws EncodingException {
87+
DataEncoder encoder =
88+
new JsonDataEncoderBuilder()
89+
.configureWith(
90+
cfg ->
91+
cfg.registerEncoder(
92+
Foo.class,
93+
(Foo s, ValueEncoderContext ctx) -> {
94+
ctx.add("value");
95+
}))
96+
.ignoreNulls(true)
97+
.build();
98+
99+
HashMap<String, Foo> fooMap = new HashMap<>();
100+
fooMap.put("foo", new Foo());
101+
fooMap.put("bar", null);
102+
assertThat(encoder.encode(fooMap)).isEqualTo("{\"foo\":\"value\"}");
103+
}
64104
}

0 commit comments

Comments
 (0)