Skip to content

Commit bd41ee2

Browse files
committed
Fixed #3214 (I hope ;) )
1 parent 4a006dd commit bd41ee2

File tree

6 files changed

+67
-14
lines changed

6 files changed

+67
-14
lines changed

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,9 @@ Project: jackson-databind
5858
(contributed by Klaas D)
5959
#3193: Add `MapperFeature.APPLY_DEFAULT_VALUES`, initially for Scala module
6060
(suggested by Nick B)
61+
#3214: For an absent property Jackson injects `NullNode` instead of `null` to a
62+
JsonNode-typed constructor argument of a `@ConstructorProperties`-annotated constructor
63+
(repored by robvarga@github)
6164
#3217: `XMLGregorianCalendar` doesn't work with default typing
6265
(reported by Xinzhe Y)
6366
#3227: Content `null` handling not working for root values

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

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,8 +315,9 @@ public T getNullValue(DeserializationContext ctxt) throws JsonMappingException {
315315
* to be called just once (static values), or each time empty value is
316316
* needed.
317317
*<p>
318-
* Default implementation indicates that "null value" to use for input null
319-
* is simply Java `null` for all deserializers, unless overridden by sub-classes.
318+
* Default implementation indicates that the "null value" to use for input null
319+
* does not vary across uses so that {@link #getNullValue(DeserializationContext)}
320+
* need not be called more than once per deserializer instance.
320321
* This information may be used as optimization.
321322
*/
322323
@Override
@@ -327,6 +328,28 @@ public AccessPattern getNullAccessPattern() {
327328
return AccessPattern.CONSTANT;
328329
}
329330

331+
/**
332+
* Method called to determine placeholder value to be used for cases
333+
* where no value was obtained from input but we must pass a value
334+
* nonetheless: the common case is that of Creator methods requiring
335+
* passing a value for every parameter.
336+
* Usually this is same as {@link #getNullValue} (which in turn
337+
* is usually simply Java {@code null}), but it can be overridden
338+
* for specific types: most notable scalar types must use "default"
339+
* values.
340+
*<p>
341+
* This method needs to be called every time a determination is made.
342+
*<p>
343+
* Default implementation simply calls {@link #getNullValue} and
344+
* returns value.
345+
*
346+
* @since 2.13
347+
*/
348+
@Override
349+
public Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException {
350+
return getNullValue(ctxt);
351+
}
352+
330353
/*
331354
/**********************************************************
332355
/* Accessors for other replacement/placeholder values

src/main/java/com/fasterxml/jackson/databind/deser/NullValueProvider.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,24 @@ public interface NullValueProvider
3131
* access null replacement value.
3232
*/
3333
public AccessPattern getNullAccessPattern();
34+
35+
/**
36+
* Method called to determine placeholder value to be used for cases
37+
* where no value was obtained from input but we must pass a value
38+
* nonetheless: the common case is that of Creator methods requiring
39+
* passing a value for every parameter.
40+
* Usually this is same as {@link #getNullValue} (which in turn
41+
* is usually simply Java {@code null}), but it can be overridden
42+
* for specific types: most notable scalar types must use "default"
43+
* values.
44+
*<p>
45+
* This method needs to be called every time a determination is made.
46+
*<p>
47+
* Default implementation simply calls and returns {@link #getNullValue}.
48+
*
49+
* @since 2.13
50+
*/
51+
default Object getAbsentValue(DeserializationContext ctxt) throws JsonMappingException {
52+
return getNullValue(ctxt);
53+
}
3454
}

src/main/java/com/fasterxml/jackson/databind/deser/impl/PropertyValueBuffer.java

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,8 @@
44
import java.util.BitSet;
55

66
import com.fasterxml.jackson.core.JsonParser;
7-
import com.fasterxml.jackson.databind.DatabindException;
8-
import com.fasterxml.jackson.databind.DeserializationContext;
9-
import com.fasterxml.jackson.databind.DeserializationFeature;
10-
import com.fasterxml.jackson.databind.JsonDeserializer;
11-
import com.fasterxml.jackson.databind.JsonMappingException;
7+
8+
import com.fasterxml.jackson.databind.*;
129
import com.fasterxml.jackson.databind.deser.SettableAnyProperty;
1310
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
1411
import com.fasterxml.jackson.databind.introspect.AnnotatedMember;
@@ -202,14 +199,15 @@ protected Object _findMissing(SettableBeanProperty prop) throws JsonMappingExcep
202199
}
203200
try {
204201
// Third: NullValueProvider? (22-Sep-2019, [databind#2458])
205-
Object nullValue = prop.getNullValueProvider().getNullValue(_context);
206-
if (nullValue != null) {
207-
return nullValue;
202+
// 08-Aug-2021, tatu: consider [databind#3214]; not null but "absent" value...
203+
Object absentValue = prop.getNullValueProvider().getAbsentValue(_context);
204+
if (absentValue != null) {
205+
return absentValue;
208206
}
209207

210208
// Fourth: default value
211209
JsonDeserializer<Object> deser = prop.getValueDeserializer();
212-
return deser.getNullValue(_context);
210+
return deser.getAbsentValue(_context);
213211
} catch (DatabindException e) {
214212
// [databind#2101]: Include property name, if we have it
215213
AnnotatedMember member = prop.getMember();

src/main/java/com/fasterxml/jackson/databind/deser/std/JsonNodeDeserializer.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,15 @@ public JsonNode getNullValue(DeserializationContext ctxt) {
6060
return ctxt.getNodeFactory().nullNode();
6161
}
6262

63+
/**
64+
* Overridden variant to ensure that absent values are NOT coerced into
65+
* {@code NullNode}s, unlike incoming {@code null} values.
66+
*/
67+
@Override // since 2.13
68+
public Object getAbsentValue(DeserializationContext ctxt) {
69+
return null;
70+
}
71+
6372
/**
6473
* Implementation that will produce types of any JSON nodes; not just one
6574
* deserializer is registered to handle (in case of more specialized handler).

src/test/java/com/fasterxml/jackson/failing/NullJsonNodeViaCreator3214Test.java renamed to src/test/java/com/fasterxml/jackson/databind/node/AbsentNodeViaCreator3214Test.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
package com.fasterxml.jackson.failing;
1+
package com.fasterxml.jackson.databind.node;
22

33
import com.fasterxml.jackson.annotation.JsonCreator;
44
import com.fasterxml.jackson.annotation.JsonProperty;
5+
56
import com.fasterxml.jackson.databind.*;
6-
import com.fasterxml.jackson.databind.node.TextNode;
77

8-
public class NullJsonNodeViaCreator3214Test extends BaseMapTest
8+
public class AbsentNodeViaCreator3214Test extends BaseMapTest
99
{
1010
static class Pojo3214
1111
{

0 commit comments

Comments
 (0)