Skip to content

Commit 1381e32

Browse files
authored
Merge pull request #192 from FasterXML/tatu/190-custom-null-filter-afterburner
Fix #190: update Afterburner to use same logic as jackson-databind for custom filters
2 parents 157c71c + cd7450a commit 1381e32

File tree

9 files changed

+352
-19
lines changed

9 files changed

+352
-19
lines changed

afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/ObjectFieldPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
4949
}
5050
// Null (etc) handling; copied from super-class impl
5151
if (value == null) {
52+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
53+
if ((_suppressableValue != null)
54+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
55+
return;
56+
}
5257
if (_nullSerializer != null) {
5358
gen.writeFieldName(_fastName);
5459
_nullSerializer.serialize(null, gen, prov);
55-
} else if (!_suppressNulls) {
56-
gen.writeFieldName(_fastName);
57-
prov.defaultSerializeNull(gen);
5860
}
5961
return;
6062
}

afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/ObjectMethodPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
4949
}
5050
// Null (etc) handling; copied from super-class impl
5151
if (value == null) {
52+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
53+
if ((_suppressableValue != null)
54+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
55+
return;
56+
}
5257
if (_nullSerializer != null) {
5358
gen.writeFieldName(_fastName);
5459
_nullSerializer.serialize(null, gen, prov);
55-
} else if (!_suppressNulls) {
56-
gen.writeFieldName(_fastName);
57-
prov.defaultSerializeNull(gen);
5860
}
5961
return;
6062
}

afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/StringFieldPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
4848
}
4949
// Null (etc) handling; copied from super-class impl
5050
if (value == null) {
51+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
52+
if ((_suppressableValue != null)
53+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
54+
return;
55+
}
5156
if (_nullSerializer != null) {
5257
gen.writeFieldName(_fastName);
5358
_nullSerializer.serialize(null, gen, prov);
54-
} else if (!_suppressNulls) {
55-
gen.writeFieldName(_fastName);
56-
prov.defaultSerializeNull(gen);
5759
}
5860
return;
5961
}

afterburner/src/main/java/com/fasterxml/jackson/module/afterburner/ser/StringMethodPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
4848
}
4949
// Null (etc) handling; copied from super-class impl
5050
if (value == null) {
51+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
52+
if ((_suppressableValue != null)
53+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
54+
return;
55+
}
5156
if (_nullSerializer != null) {
5257
gen.writeFieldName(_fastName);
5358
_nullSerializer.serialize(null, gen, prov);
54-
} else if (!_suppressNulls) {
55-
gen.writeFieldName(_fastName);
56-
prov.defaultSerializeNull(gen);
5759
}
5860
return;
5961
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package com.fasterxml.jackson.module.afterburner.ser.filter;
2+
3+
import java.util.LinkedHashMap;
4+
import java.util.Map;
5+
import java.util.concurrent.atomic.AtomicInteger;
6+
7+
import com.fasterxml.jackson.annotation.*;
8+
9+
import com.fasterxml.jackson.databind.JsonMappingException;
10+
import com.fasterxml.jackson.databind.ObjectMapper;
11+
import com.fasterxml.jackson.module.afterburner.AfterburnerTestBase;
12+
13+
// Tests for [databind#888]
14+
public class JsonIncludeCustomTest extends AfterburnerTestBase
15+
{
16+
static class FooFilter {
17+
@Override
18+
public boolean equals(Object other) {
19+
if (other == null) { // do NOT filter out nulls
20+
return false;
21+
}
22+
// in fact, only filter out exact String "foo"
23+
return "foo".equals(other);
24+
}
25+
}
26+
27+
// for testing prob with `equals(null)` which SHOULD be allowed
28+
static class BrokenFilter {
29+
@Override
30+
public boolean equals(Object other) {
31+
/*String str = */ other.toString();
32+
return false;
33+
}
34+
}
35+
36+
static class FooBean {
37+
@JsonInclude(value=JsonInclude.Include.CUSTOM,
38+
valueFilter=FooFilter.class)
39+
public String value;
40+
41+
public FooBean(String v) { value = v; }
42+
}
43+
44+
static class FooMapBean {
45+
@JsonInclude(content=JsonInclude.Include.CUSTOM,
46+
contentFilter=FooFilter.class)
47+
public Map<String,String> stuff = new LinkedHashMap<String,String>();
48+
49+
public FooMapBean add(String key, String value) {
50+
stuff.put(key, value);
51+
return this;
52+
}
53+
}
54+
55+
static class BrokenBean {
56+
@JsonInclude(value=JsonInclude.Include.CUSTOM,
57+
valueFilter=BrokenFilter.class)
58+
public String value;
59+
60+
public BrokenBean(String v) { value = v; }
61+
}
62+
63+
static class BrokenBean2 {
64+
@JsonInclude(value=JsonInclude.Include.CUSTOM,
65+
valueFilter=BrokenFilter.class)
66+
public Map<String, String> value;
67+
68+
public BrokenBean2(Map<String, String> v) { value = v; }
69+
}
70+
71+
// [databind#3481]
72+
static class CountingFooFilter {
73+
public final static AtomicInteger counter = new AtomicInteger(0);
74+
75+
@Override
76+
public boolean equals(Object other) {
77+
counter.incrementAndGet();
78+
return "foo".equals(other);
79+
}
80+
}
81+
82+
static class CountingFooBean {
83+
@JsonInclude(value=JsonInclude.Include.CUSTOM,
84+
valueFilter=CountingFooFilter.class)
85+
public String value;
86+
87+
public CountingFooBean(String v) { value = v; }
88+
}
89+
90+
/*
91+
/**********************************************************
92+
/* Test methods, success
93+
/**********************************************************
94+
*/
95+
96+
private final ObjectMapper MAPPER = newObjectMapper();
97+
98+
public void testSimpleCustomFilter() throws Exception
99+
{
100+
assertEquals(a2q("{'value':'x'}"), MAPPER.writeValueAsString(new FooBean("x")));
101+
assertEquals("{}", MAPPER.writeValueAsString(new FooBean("foo")));
102+
}
103+
104+
public void testCustomFilterWithMap() throws Exception
105+
{
106+
FooMapBean input = new FooMapBean()
107+
.add("a", "1")
108+
.add("b", "foo")
109+
.add("c", "2");
110+
111+
assertEquals(a2q("{'stuff':{'a':'1','c':'2'}}"), MAPPER.writeValueAsString(input));
112+
}
113+
114+
// [databind#3481]
115+
public void testRepeatedCalls() throws Exception
116+
{
117+
CountingFooFilter.counter.set(0);
118+
119+
assertEquals(a2q("{'value':'x'}"),
120+
MAPPER.writeValueAsString(new CountingFooBean("x")));
121+
assertEquals(1, CountingFooFilter.counter.get());
122+
123+
assertEquals("{}", MAPPER.writeValueAsString(new CountingFooBean("foo")));
124+
assertEquals(2, CountingFooFilter.counter.get());
125+
126+
// except filter will be called again for `null`s, as per [databind#3481]
127+
assertEquals(a2q("{'value':null}"), MAPPER.writeValueAsString(new CountingFooBean(null)));
128+
assertEquals(3, CountingFooFilter.counter.get());
129+
}
130+
131+
/*
132+
/**********************************************************
133+
/* Test methods, fail handling
134+
/**********************************************************
135+
*/
136+
137+
public void testBrokenFilterString() throws Exception
138+
{
139+
try {
140+
String json = MAPPER.writeValueAsString(new BrokenBean(null));
141+
fail("Should not pass, produced: "+json);
142+
} catch (JsonMappingException e) {
143+
// 20-Jun-2022, tatu: Actual message seems to vary across JDKs...
144+
verifyException(e, "Problem determining whether filter");
145+
verifyException(e, "should filter out `null` values");
146+
}
147+
}
148+
149+
public void testBrokenFilterMap() throws Exception
150+
{
151+
try {
152+
String json = MAPPER.writeValueAsString(new BrokenBean2(null));
153+
fail("Should not pass, produced: "+json);
154+
} catch (JsonMappingException e) {
155+
// 20-Jun-2022, tatu: Actual message seems to vary across JDKs...
156+
verifyException(e, "Problem determining whether filter");
157+
verifyException(e, "should filter out `null` values");
158+
}
159+
}
160+
}

blackbird/src/main/java/com/fasterxml/jackson/module/blackbird/ser/ObjectPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
5757
}
5858
// Null (etc) handling; copied from super-class impl
5959
if (value == null) {
60+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
61+
if ((_suppressableValue != null)
62+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
63+
return;
64+
}
6065
if (_nullSerializer != null) {
6166
gen.writeFieldName(_fastName);
6267
_nullSerializer.serialize(null, gen, prov);
63-
} else if (!_suppressNulls) {
64-
gen.writeFieldName(_fastName);
65-
prov.defaultSerializeNull(gen);
6668
}
6769
return;
6870
}

blackbird/src/main/java/com/fasterxml/jackson/module/blackbird/ser/StringPropertyWriter.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,14 @@ public final void serializeAsField(Object bean, JsonGenerator gen, SerializerPro
5757
}
5858
// Null (etc) handling; copied from super-class impl
5959
if (value == null) {
60+
// 20-Jun-2022, tatu: Defer checking of null, see [databind#3481]
61+
if ((_suppressableValue != null)
62+
&& prov.includeFilterSuppressNulls(_suppressableValue)) {
63+
return;
64+
}
6065
if (_nullSerializer != null) {
6166
gen.writeFieldName(_fastName);
6267
_nullSerializer.serialize(null, gen, prov);
63-
} else if (!_suppressNulls) {
64-
gen.writeFieldName(_fastName);
65-
prov.defaultSerializeNull(gen);
6668
}
6769
return;
6870
}

0 commit comments

Comments
 (0)