Skip to content

Commit f8c1363

Browse files
authored
Add JavaDoc and test wrt custom JsonDeserializers null handling (#4594)
1 parent 8d96e83 commit f8c1363

File tree

2 files changed

+80
-3
lines changed

2 files changed

+80
-3
lines changed

src/main/java/com/fasterxml/jackson/databind/JsonDeserializer.java

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,17 @@ public abstract class JsonDeserializer<T>
9595
* fails, event that was not recognized or usable, which may be
9696
* the same event as the one it pointed to upon call).
9797
*<p>
98-
* Note that this method is never called for JSON null literal,
99-
* and thus deserializers need (and should) not check for it.
98+
* <strong>Handling null values (JsonToken.VALUE_NULL)</strong>
99+
* <br>
100+
* : Note that this method is never called for the JSON {@code null} literal to avoid
101+
* every deserializer from having to handle null values. Instead, the
102+
* {@link JsonDeserializer#getNullValue(DeserializationContext)} method
103+
* is called to produce a null value. To influence null handling,
104+
* custom deserializers should override
105+
* {@link JsonDeserializer#getNullValue(DeserializationContext)}
106+
* and usually also {@link JsonDeserializer#getNullAccessPattern()}.
100107
*
101-
* @param p Parsed used for reading JSON content
108+
* @param p Parser used for reading JSON content
102109
* @param ctxt Context that can be used to access information about
103110
* this deserialization activity.
104111
*
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.fasterxml.jackson.databind.deser;
2+
3+
import java.io.IOException;
4+
import java.util.ArrayList;
5+
import java.util.List;
6+
7+
import org.junit.jupiter.api.Test;
8+
9+
import com.fasterxml.jackson.core.JacksonException;
10+
import com.fasterxml.jackson.core.JsonParser;
11+
import com.fasterxml.jackson.databind.*;
12+
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
13+
import com.fasterxml.jackson.databind.testutil.DatabindTestUtil;
14+
15+
import static org.assertj.core.api.Assertions.assertThat;
16+
17+
/**
18+
* Test to check that getNullValue for deserializer is not cached, by default.
19+
*/
20+
public class CustomDeserializers4225NullCacheTest extends DatabindTestUtil
21+
{
22+
static class CustomListDeserializer extends JsonDeserializer<List<String>> {
23+
24+
private static int getNullValueInvocationCount = 0;
25+
26+
@Override
27+
public List<String> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
28+
return makeList("regular");
29+
}
30+
31+
@Override
32+
public List<String> getNullValue(DeserializationContext ctxt) throws JsonMappingException {
33+
// Increment invocation count
34+
getNullValueInvocationCount++;
35+
return makeList("nullVal_" + getNullValueInvocationCount);
36+
}
37+
38+
public List<String> makeList(String content) {
39+
List<String> randomList = new ArrayList<>();
40+
randomList.add(content);
41+
return randomList;
42+
}
43+
}
44+
45+
static class Bean4225 {
46+
@JsonDeserialize(using = CustomListDeserializer.class)
47+
public List<String> myList;
48+
}
49+
50+
@Test
51+
public void testGetNullValueIsCached() throws Exception
52+
{
53+
ObjectMapper mapper = newJsonMapper();
54+
55+
// First time deserializing null
56+
verifyGetNullValueInvokedTimes(mapper, 1);
57+
// Second time deserializing null, should be invoked twice
58+
verifyGetNullValueInvokedTimes(mapper, 2);
59+
}
60+
61+
private void verifyGetNullValueInvokedTimes(ObjectMapper mapper, int times)
62+
throws Exception
63+
{
64+
Bean4225 someBean = mapper.readValue(a2q("{'myList': null}"), Bean4225.class);
65+
66+
assertThat(someBean.myList).hasSize(1);
67+
assertThat(someBean.myList.get(0)).isEqualTo("nullVal_" + times);
68+
assertThat(CustomListDeserializer.getNullValueInvocationCount).isEqualTo(times);
69+
}
70+
}

0 commit comments

Comments
 (0)