Skip to content

Commit 2339988

Browse files
committed
intermediate commit, apologies for breakage; refactoring empty/null handling
1 parent 3fc3177 commit 2339988

26 files changed

+352
-101
lines changed

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

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

66
import com.fasterxml.jackson.core.*;
7-
import com.fasterxml.jackson.databind.deser.BeanDeserializerFactory;
8-
import com.fasterxml.jackson.databind.deser.NullValueProvider;
9-
import com.fasterxml.jackson.databind.deser.SettableBeanProperty;
7+
8+
import com.fasterxml.jackson.databind.deser.*;
109
import com.fasterxml.jackson.databind.deser.impl.ObjectIdReader;
1110
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
11+
import com.fasterxml.jackson.databind.util.AccessPattern;
1212
import com.fasterxml.jackson.databind.util.NameTransformer;
1313

1414
/**
@@ -30,7 +30,7 @@
3030
*<p>
3131
* In addition, to support per-property annotations (to configure aspects
3232
* of deserialization on per-property basis), deserializers may want
33-
* to implement
33+
* to implement
3434
* {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer},
3535
* which allows specialization of deserializers: call to
3636
* {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer#createContextual}
@@ -82,8 +82,8 @@ public abstract class JsonDeserializer<T>
8282
* after the @class. Thus, if you want your method to work correctly
8383
* both with and without polymorphism, you must begin your method with:
8484
* <pre>
85-
* if (jp.getCurrentToken() == JsonToken.START_OBJECT) {
86-
* jp.nextToken();
85+
* if (p.getCurrentToken() == JsonToken.START_OBJECT) {
86+
* p.nextToken();
8787
* }
8888
* </pre>
8989
* This results in the stream pointing to the field name, so that
@@ -256,7 +256,7 @@ public Collection<Object> getKnownPropertyNames() {
256256

257257
/*
258258
/**********************************************************
259-
/* Other accessors
259+
/* Default NullValueProvider implementation
260260
/**********************************************************
261261
*/
262262

@@ -275,12 +275,43 @@ public Collection<Object> getKnownPropertyNames() {
275275
*
276276
* @since 2.6 Added to replace earlier no-arguments variant
277277
*/
278-
@Override
279278
public T getNullValue(DeserializationContext ctxt) throws JsonMappingException {
280279
// Change the direction in 2.7
281280
return getNullValue();
282281
}
283282

283+
/**
284+
* Default implementation indicates that "null value" to use for input null
285+
* is simply Java `null` for all deserializers, unless overridden by sub-classes.
286+
* This information may be used as optimization.
287+
*/
288+
@Override
289+
public AccessPattern getNullAccessPattern() {
290+
// Default implementation assumes that the null value does not vary, which
291+
// is usually the case for most implementations. But it is not necessarily
292+
// `null`; so sub-classes may want to refine further.
293+
return AccessPattern.CONSTANT;
294+
}
295+
296+
/**
297+
* This method may be called in conjunction with calls to
298+
* {@link #getEmptyValue(DeserializationContext)}, to check whether it needs
299+
* to be called just once (static values), or each time empty value is
300+
* needed.
301+
*
302+
* @since 2.9
303+
*/
304+
// public abstract AccessPattern getEmptyAccessPattern();
305+
public AccessPattern getEmptyAccessPattern() {
306+
return AccessPattern.DYNAMIC;
307+
}
308+
309+
/*
310+
/**********************************************************
311+
/* Other accessors
312+
/**********************************************************
313+
*/
314+
284315
/**
285316
* Method called to determine value to be used for "empty" values
286317
* (most commonly when deserializing from empty JSON Strings).

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1132,7 +1132,7 @@ public JsonDeserializer<?> createMapDeserializer(DeserializationContext ctxt,
11321132
if (kt == null || !kt.isEnum()) {
11331133
throw new IllegalArgumentException("Can not construct EnumMap; generic (key) type not available");
11341134
}
1135-
deser = new EnumMapDeserializer(type, null, contentDeser, contentTypeDeser);
1135+
deser = new EnumMapDeserializer(type, null, contentDeser, contentTypeDeser, null);
11361136
}
11371137

11381138
// Otherwise, generic handler works ok.

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

Lines changed: 30 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,35 @@ protected SettableBeanProperty _resolveMergeAndNullSettings(DeserializationConte
929929

930930
/*
931931
/**********************************************************
932-
/* Public accessors
932+
/* Public accessors; null/empty value providers
933+
/**********************************************************
934+
*/
935+
936+
@Override
937+
public AccessPattern getNullAccessPattern() {
938+
// POJO types do not have custom `null` values
939+
return AccessPattern.ALWAYS_NULL;
940+
}
941+
942+
@Override
943+
public AccessPattern getEmptyAccessPattern() {
944+
// Empty values can not be shared
945+
return AccessPattern.DYNAMIC;
946+
}
947+
948+
@Override // since 2.9
949+
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
950+
// alas, need to promote exception, if any:
951+
try {
952+
return _valueInstantiator.createUsingDefault(ctxt);
953+
} catch (IOException e) {
954+
return ClassUtil.throwAsMappingException(ctxt, e);
955+
}
956+
}
957+
958+
/*
959+
/**********************************************************
960+
/* Public accessors; other
933961
/**********************************************************
934962
*/
935963

@@ -948,7 +976,7 @@ public Boolean supportsUpdate(DeserializationConfig config) {
948976
public Class<?> handledType() {
949977
return _beanType.getRawClass();
950978
}
951-
979+
952980
/**
953981
* Overridden to return true for those instances that are
954982
* handling value for which Object Identity handling is enabled
@@ -1083,16 +1111,6 @@ public ValueInstantiator getValueInstantiator() {
10831111
return _valueInstantiator;
10841112
}
10851113

1086-
@Override // since 2.9
1087-
public Object getEmptyValue(DeserializationContext ctxt) throws JsonMappingException {
1088-
// alas, need to promote exception, if any:
1089-
try {
1090-
return _valueInstantiator.createUsingDefault(ctxt);
1091-
} catch (IOException e) {
1092-
return ClassUtil.throwAsMappingException(ctxt, e);
1093-
}
1094-
}
1095-
10961114
/*
10971115
/**********************************************************
10981116
/* Mutators

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.fasterxml.jackson.databind.DeserializationContext;
44
import com.fasterxml.jackson.databind.JsonMappingException;
5+
import com.fasterxml.jackson.databind.util.AccessPattern;
56

67
/**
78
* Helper interface implemented by classes that are to be used as
@@ -24,6 +25,16 @@ public interface NullValueProvider
2425
* Method called to possibly convert incoming `null` token (read via
2526
* underlying streaming input source) into other value of type accessor
2627
* supports. May return `null`, or value compatible with type binding.
28+
*<p>
29+
* NOTE: if {@link #getNullAccessPattern()} returns `ALWAYS_NULL` or
30+
* `CONSTANT`, this method WILL NOT use provided `ctxt` and it may thus
31+
* be passed as `null`.
2732
*/
2833
public Object getNullValue(DeserializationContext ctxt) throws JsonMappingException;
34+
35+
/**
36+
* Accessor that may be used to determine if and when provider must be called to
37+
* access null replacement value.
38+
*/
39+
public AccessPattern getNullAccessPattern();
2940
}

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

Lines changed: 10 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import com.fasterxml.jackson.databind.*;
99
import com.fasterxml.jackson.databind.deser.impl.FailingDeserializer;
10+
import com.fasterxml.jackson.databind.deser.impl.NullsConstantProvider;
1011
import com.fasterxml.jackson.databind.introspect.*;
1112
import com.fasterxml.jackson.databind.jsonFormatVisitors.JsonObjectFormatVisitor;
1213
import com.fasterxml.jackson.databind.jsontype.TypeDeserializer;
@@ -35,6 +36,11 @@ public abstract class SettableBeanProperty
3536
protected static final JsonDeserializer<Object> MISSING_VALUE_DESERIALIZER = new FailingDeserializer(
3637
"No _valueDeserializer assigned");
3738

39+
/**
40+
* @since 2.9
41+
*/
42+
protected static final NullValueProvider MISSING_NULL_PROVIDER = NullsConstantProvider.nuller();
43+
3844
/**
3945
* Logical name of the property (often but not always derived
4046
* from the setter method name)
@@ -163,7 +169,7 @@ protected SettableBeanProperty(PropertyName propName, JavaType type, PropertyNam
163169
}
164170
_valueTypeDeserializer = typeDeser;
165171
_valueDeserializer = MISSING_VALUE_DESERIALIZER;
166-
_nullProvider = MISSING_VALUE_DESERIALIZER;
172+
_nullProvider = MISSING_NULL_PROVIDER;
167173
}
168174

169175
/**
@@ -188,9 +194,9 @@ protected SettableBeanProperty(PropertyName propName, JavaType type,
188194
_valueTypeDeserializer = null;
189195
_valueDeserializer = valueDeser;
190196
// 29-Jan-2017, tatu: Presumed to be irrelevant for ObjectId values...
191-
_nullProvider = valueDeser;
197+
_nullProvider = MISSING_NULL_PROVIDER;
192198
}
193-
199+
194200
/**
195201
* Basic copy-constructor for sub-classes to use.
196202
*/
@@ -209,17 +215,6 @@ protected SettableBeanProperty(SettableBeanProperty src)
209215
_nullProvider = src._nullProvider;
210216
}
211217

212-
/**
213-
* @deprecated Since 2.9 use {@link #SettableBeanProperty(SettableBeanProperty, JsonDeserializer, NullValueProvider)}
214-
* instead
215-
*/
216-
@Deprecated // since 2.9
217-
protected SettableBeanProperty(SettableBeanProperty src,
218-
JsonDeserializer<?> deser)
219-
{
220-
this(src, deser, deser);
221-
}
222-
223218
/**
224219
* Copy-with-deserializer-change constructor for sub-classes to use.
225220
*/
@@ -244,7 +239,7 @@ protected SettableBeanProperty(SettableBeanProperty src,
244239
_viewMatcher = src._viewMatcher;
245240
// 29-Jan-2017, tatu: Bit messy, but for now has to do...
246241
if (nullAccessor == MISSING_VALUE_DESERIALIZER) {
247-
nullAccessor = deser;
242+
nullAccessor = MISSING_NULL_PROVIDER;
248243
}
249244
_nullProvider = nullAccessor;
250245
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.databind.*;
44
import com.fasterxml.jackson.databind.deser.NullValueProvider;
55
import com.fasterxml.jackson.databind.exc.InvalidNullException;
6+
import com.fasterxml.jackson.databind.util.AccessPattern;
67

78
/**
89
* Simple {@link NullValueProvider} that will always throw a
@@ -16,6 +17,11 @@ public NullsAsEmptyProvider(JsonDeserializer<?> deser) {
1617
_deserializer = deser;
1718
}
1819

20+
@Override
21+
public AccessPattern getNullAccessPattern() {
22+
return AccessPattern.DYNAMIC;
23+
}
24+
1925
@Override
2026
public Object getNullValue(DeserializationContext ctxt)
2127
throws JsonMappingException {

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.databind.*;
44
import com.fasterxml.jackson.databind.deser.NullValueProvider;
55
import com.fasterxml.jackson.databind.exc.InvalidNullException;
6+
import com.fasterxml.jackson.databind.util.AccessPattern;
67

78
/**
89
* Simple {@link NullValueProvider} that will always throw a
@@ -12,10 +13,16 @@ public class NullsConstantProvider implements NullValueProvider
1213
{
1314
private final static NullsConstantProvider SKIPPER = new NullsConstantProvider(NullValueProvider.SKIP_MARKER);
1415

16+
private final static NullsConstantProvider NULLER = new NullsConstantProvider(null);
17+
1518
protected final Object _nullValue;
1619

20+
protected final AccessPattern _access;
21+
1722
public NullsConstantProvider(Object nvl) {
1823
_nullValue = nvl;
24+
_access = (_nullValue == null) ? AccessPattern.ALWAYS_NULL
25+
: AccessPattern.CONSTANT;
1926
}
2027

2128
/**
@@ -27,6 +34,15 @@ public static NullsConstantProvider skipper() {
2734
return SKIPPER;
2835
}
2936

37+
public static NullsConstantProvider nuller() {
38+
return NULLER;
39+
}
40+
41+
@Override
42+
public AccessPattern getNullAccessPattern() {
43+
return _access;
44+
}
45+
3046
@Override
3147
public Object getNullValue(DeserializationContext ctxt) {
3248
return _nullValue;

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.fasterxml.jackson.databind.*;
44
import com.fasterxml.jackson.databind.deser.NullValueProvider;
55
import com.fasterxml.jackson.databind.exc.InvalidNullException;
6+
import com.fasterxml.jackson.databind.util.AccessPattern;
67

78
/**
89
* Simple {@link NullValueProvider} that will always throw a
@@ -18,6 +19,12 @@ public NullsFailProvider(PropertyName name, JavaType type) {
1819
_type = type;
1920
}
2021

22+
@Override
23+
public AccessPattern getNullAccessPattern() {
24+
// Must be called every time to effect the exception...
25+
return AccessPattern.DYNAMIC;
26+
}
27+
2128
@Override
2229
public Object getNullValue(DeserializationContext ctxt)
2330
throws JsonMappingException {

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ public AtomicReferenceDeserializer(JavaType fullType, ValueInstantiator inst,
2525
{
2626
super(fullType, inst, typeDeser, deser);
2727
}
28-
28+
2929
/*
3030
/**********************************************************
3131
/* Abstract method implementations
@@ -37,7 +37,6 @@ public AtomicReferenceDeserializer withResolved(TypeDeserializer typeDeser, Json
3737
return new AtomicReferenceDeserializer(_fullType, _valueInstantiator,
3838
typeDeser, valueDeser);
3939
}
40-
4140
@Override
4241
public AtomicReference<Object> getNullValue(DeserializationContext ctxt) {
4342
return new AtomicReference<Object>();

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

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -119,16 +119,6 @@ protected CollectionDeserializer withResolved(JsonDeserializer<?> dd,
119119
nuller, unwrapSingle);
120120
}
121121

122-
/**
123-
* @deprecated Since 2.7 as it does not pass `unwrapSingle`
124-
*/
125-
@Deprecated // since 2.7 -- will not retain "unwrapSingle" setting
126-
protected CollectionDeserializer withResolved(JsonDeserializer<?> dd,
127-
JsonDeserializer<?> vd, TypeDeserializer vtd)
128-
{
129-
return withResolved(dd, vd, vtd, vd, _unwrapSingle);
130-
}
131-
132122
// Important: do NOT cache if polymorphic values
133123
@Override // since 2.5
134124
public boolean isCachable() {

0 commit comments

Comments
 (0)