Skip to content

Commit 8d3d3b7

Browse files
committed
Fix #1889
1 parent c52b0d1 commit 8d3d3b7

File tree

56 files changed

+132
-277
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+132
-277
lines changed

release-notes/VERSION

+2
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,6 @@ Versions: 3.x (for earlier see VERSION-2.x)
2020
#1790: Add `createParser` methods in `ObjectMapper`, `ObjectReader`
2121
#1888: Merge `ResolvableSerializer` into `JsonSerializer`, `ResolvableDeserializer`
2222
into `JsonDeserializer`
23+
#1889: Merge `ContextualSerializer` into `JsonSerializer`, `ContextualDeserializer`
24+
into `JsonDeserializer`
2325
- Remove `MappingJsonFactory`

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,9 @@
2525
*<p>
2626
* Instances are not typically passed when constructing serializers
2727
* and deserializers, but rather only passed when context
28-
* is known when
29-
* {@link com.fasterxml.jackson.databind.ser.ContextualSerializer} and
30-
* {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer}
31-
* resolution occurs (<code>createContextual(...)</code> method is called).
28+
* is known and
29+
* {@link JsonSerializer#createContextual} and
30+
* {@link JsonDeserializer#createContextual} are called.
3231
* References may (need to) be retained by serializers and deserializers,
3332
* especially when further resolving dependent handlers like value
3433
* serializers/deserializers or structured types.

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

+12-17
Original file line numberDiff line numberDiff line change
@@ -151,12 +151,11 @@ public abstract class DeserializationContext
151151
protected transient ContextAttributes _attributes;
152152

153153
/**
154-
* Type of {@link JsonDeserializer} (or, more specifically,
155-
* {@link ContextualDeserializer}) that is being
156-
* contextualized currently.
154+
* Type of {@link JsonDeserializer} on which {@link JsonDeserializer#createContextual}
155+
* is being called currently.
157156
*/
158157
protected LinkedNode<JavaType> _currentType;
159-
158+
160159
/*
161160
/**********************************************************
162161
/* Life-cycle
@@ -316,13 +315,13 @@ public DeserializationContext setAttribute(Object key, Object value)
316315

317316
/**
318317
* Accessor to {@link JavaType} of currently contextualized
319-
* {@link ContextualDeserializer}, if any.
318+
* {@link JsonDeserializer}, if any.
320319
* This is sometimes useful for generic {@link JsonDeserializer}s that
321320
* do not get passed (or do not retain) type information when being
322321
* constructed: happens for example for deserializers constructed
323322
* from annotations.
324323
*
325-
* @return Type of {@link ContextualDeserializer} being contextualized,
324+
* @return Type of {@link JsonDeserializer} being contextualized,
326325
* if process is on-going; null if not.
327326
*/
328327
public JavaType getContextualType() {
@@ -755,21 +754,19 @@ public abstract KeyDeserializer keyDeserializerInstance(Annotated annotated,
755754
/**
756755
* Method called for primary property deserializers (ones
757756
* directly created to deserialize values of a POJO property),
758-
* to handle details of resolving
759-
* {@link ContextualDeserializer} with given property context.
757+
* to handle details of calling
758+
* {@link JsonDeserializer#createContextual} with given property context.
760759
*
761760
* @param prop Property for which the given primary deserializer is used; never null.
762-
*
763-
* @since 2.5
764761
*/
765762
public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> deser,
766763
BeanProperty prop, JavaType type)
767764
throws JsonMappingException
768765
{
769-
if (deser instanceof ContextualDeserializer) {
766+
if (deser != null) {
770767
_currentType = new LinkedNode<JavaType>(type, _currentType);
771768
try {
772-
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
769+
deser = deser.createContextual(this, prop);
773770
} finally {
774771
_currentType = _currentType.next();
775772
}
@@ -783,24 +780,22 @@ public JsonDeserializer<?> handlePrimaryContextualization(JsonDeserializer<?> de
783780
* but instead created as a component -- such as value deserializers
784781
* for structured types, or deserializers for root values)
785782
* to handle details of resolving
786-
* {@link ContextualDeserializer} with given property context.
783+
* {@link JsonDeserializer#createContextual} with given property context.
787784
* Given that these deserializers are not directly related to given property
788785
* (or, in case of root value property, to any property), annotations
789786
* accessible may or may not be relevant.
790787
*
791788
* @param prop Property for which deserializer is used, if any; null
792789
* when deserializing root values
793-
*
794-
* @since 2.5
795790
*/
796791
public JsonDeserializer<?> handleSecondaryContextualization(JsonDeserializer<?> deser,
797792
BeanProperty prop, JavaType type)
798793
throws JsonMappingException
799794
{
800-
if (deser instanceof ContextualDeserializer) {
795+
if (deser != null) {
801796
_currentType = new LinkedNode<JavaType>(type, _currentType);
802797
try {
803-
deser = ((ContextualDeserializer) deser).createContextual(this, prop);
798+
deser =deser.createContextual(this, prop);
804799
} finally {
805800
_currentType = _currentType.next();
806801
}

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

+31-6
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,9 @@
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
34-
* {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer},
35-
* which allows specialization of deserializers: call to
36-
* {@link com.fasterxml.jackson.databind.deser.ContextualDeserializer#createContextual}
37-
* is passed information on property, and can create a newly configured
33+
* to override
34+
* {@link #createContextual} which allows specialization of deserializers:
35+
* it is passed information on property, and can create a newly configured
3836
* deserializer for handling that particular property.
3937
*<br />
4038
* Resolution of deserializers occurs before contextualization.
@@ -44,7 +42,8 @@ public abstract class JsonDeserializer<T>
4442
{
4543
/*
4644
/**********************************************************
47-
/* Initialization, with former `ResolvableDeserializer`
45+
/* Initialization, with former `ResolvableDeserializer`,
46+
/* `ContextualDeserializer`
4847
/**********************************************************
4948
*/
5049

@@ -62,6 +61,32 @@ public void resolve(DeserializationContext ctxt) throws JsonMappingException {
6261
// Default implementation does nothing
6362
}
6463

64+
/**
65+
* Method called to see if a different (or differently configured) deserializer
66+
* is needed to deserialize values of specified property.
67+
* Note that instance that this method is called on is typically shared one and
68+
* as a result method should <b>NOT</b> modify this instance but rather construct
69+
* and return a new instance. This instance should only be returned as-is, in case
70+
* it is already suitable for use.
71+
*
72+
* @param ctxt Deserialization context to access configuration, additional
73+
* deserializers that may be needed by this deserializer
74+
* @param property Method, field or constructor parameter that represents the property
75+
* (and is used to assign deserialized value).
76+
* Should be available; but there may be cases where caller cannot provide it and
77+
* null is passed instead (in which case impls usually pass 'this' deserializer as is)
78+
*
79+
* @return Deserializer to use for deserializing values of specified property;
80+
* may be this instance or a new instance.
81+
*
82+
* @throws JsonMappingException
83+
*/
84+
public JsonDeserializer<?> createContextual(DeserializationContext ctxt,
85+
BeanProperty property) throws JsonMappingException {
86+
// default implementation returns instance unmodified
87+
return this;
88+
}
89+
6590
/*
6691
/**********************************************************
6792
/* Main deserialization methods

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

+53-20
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,9 @@
1616
* Abstract class that defines API used by {@link ObjectMapper} (and
1717
* other chained {@link JsonSerializer}s too) to serialize Objects of
1818
* arbitrary types into JSON, using provided {@link JsonGenerator}.
19-
* {@link com.fasterxml.jackson.databind.ser.std.StdSerializer} instead
20-
* of this class, since it will implement many of optional
21-
* methods of this class.
22-
*<p>
23-
* NOTE: various <code>serialize</code> methods are never (to be) called
24-
* with null values -- caller <b>must</b> handle null values, usually
25-
* by calling {@link SerializerProvider#findNullValueSerializer} to obtain
26-
* serializer to use.
27-
* This also means that custom serializers cannot be directly used to change
28-
* the output to produce when serializing null values.
19+
* Note that although API is defined here, custom serializer implementations
20+
* should almost always be based on {@link com.fasterxml.jackson.databind.ser.std.StdSerializer}
21+
* since it will implement many of optional methods of this class.
2922
*<p>
3023
* If serializer is an aggregate one -- meaning it delegates handling of some
3124
* of its contents by using other serializer(s) -- it typically also needs
@@ -35,23 +28,34 @@
3528
* resolution of secondary serializers (which may have cyclic link back
3629
* to serializer itself, directly or indirectly).
3730
*<p>
38-
* In addition, to support per-property annotations (to configure aspects
39-
* of serialization on per-property basis), serializers may want
40-
* to implement
41-
* {@link com.fasterxml.jackson.databind.ser.ContextualSerializer},
42-
* which allows specialization of serializers: call to
43-
* {@link com.fasterxml.jackson.databind.ser.ContextualSerializer#createContextual}
44-
* is passed information on property, and can create a newly configured
45-
* serializer for handling that particular property.
31+
* Initialization of serializers is handled by two main methods:
32+
*<ol>
33+
* <li>{@link #resolve}: called after instance is configured to be used for specific type,
34+
* but without yet knowing property it will be used for (or, in case of root values, without property).
35+
* Method needs to be implemented for serializers that may work on cyclic types, and specifically
36+
* is implemented by standard POJO serializer ({@code BeanSerializer}). It is usually not needed for
37+
* container types as their type definitions are not cyclic, unlike some POJO types.
38+
* <li>{@link #createContextual}: called on resolved instance (whether newly created, or found via cache),
39+
* when serializer is to be used for specific property, or as root value serializer (no referring property).
40+
* It is used to apply annotations from property accessors (getter, field), and may also be used for resolving
41+
* nested types for container serializers (such as ones for {@link java.util.Collection}s).
42+
* </ol>
43+
* Caching of serializers occurs after {@link #resolve} is called: cached instances are not contextual.
4644
*<p>
47-
* Resolution of serializers occurs before contextualization.
45+
* NOTE: various <code>serialize</code> methods are never (to be) called
46+
* with null values -- caller <b>must</b> handle null values, usually
47+
* by calling {@link SerializerProvider#findNullValueSerializer} to obtain
48+
* serializer to use.
49+
* This also means that custom serializers cannot be directly used to change
50+
* the output to produce when serializing null values.
4851
*/
4952
public abstract class JsonSerializer<T>
5053
implements JsonFormatVisitable
5154
{
5255
/*
5356
/**********************************************************
54-
/* Initialization, with former `ResolvableSerializer`
57+
/* Initialization, with former `ResolvableSerializer`,
58+
/* `ContextualSerializer`.
5559
/**********************************************************
5660
*/
5761

@@ -71,6 +75,35 @@ public void resolve(SerializerProvider provider) throws JsonMappingException {
7175
// Default implementation does nothing
7276
}
7377

78+
/**
79+
* Method called to see if a different (or differently configured) serializer
80+
* is needed to serialize values of specified property (or, for root values, in which
81+
* case `null` is passed).
82+
* Note that instance that this method is called on is typically shared one and
83+
* as a result method should <b>NOT</b> modify this instance but rather construct
84+
* and return a new instance. This instance should only be returned as-is, in case
85+
* it is already suitable for use.
86+
*<p>
87+
* Note that method is only called once per POJO property, and for the first usage as root
88+
* value serializer; it is not called for every serialization, as doing that would have
89+
* significant performance impact; most serializers cache contextual instances for future
90+
* use.
91+
*
92+
* @param prov Serializer provider to use for accessing config, other serializers
93+
* @param property Property (defined by one or more accessors - field or method - used
94+
* for accessing logical property value) for which serializer is used to be used;
95+
* or, `null` for root value (or in cases where caller does not have this information,
96+
* which is handled as root value case).
97+
*
98+
* @return Serializer to use for serializing values of specified property;
99+
* may be this instance or a new instance.
100+
*/
101+
public JsonSerializer<?> createContextual(SerializerProvider prov,
102+
BeanProperty property) throws JsonMappingException {
103+
// default implementation returns instance unmodified
104+
return this;
105+
}
106+
74107
/*
75108
/**********************************************************
76109
/* Fluent factory methods for constructing decorated versions

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

+9-21
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import com.fasterxml.jackson.databind.cfg.ContextAttributes;
2525
import com.fasterxml.jackson.databind.cfg.GeneratorSettings;
26-
import com.fasterxml.jackson.databind.deser.ContextualDeserializer;
2726
import com.fasterxml.jackson.databind.exc.InvalidDefinitionException;
2827
import com.fasterxml.jackson.databind.exc.InvalidTypeIdException;
2928
import com.fasterxml.jackson.databind.introspect.Annotated;
@@ -1021,9 +1020,8 @@ public boolean isUnknownTypeSerializer(JsonSerializer<?> ser) {
10211020
* Method that can be called to construct and configure serializer instance,
10221021
* either given a {@link Class} to instantiate (with default constructor),
10231022
* or an uninitialized serializer instance.
1024-
* Either way, serialize will be properly resolved
1025-
* (via {@link com.fasterxml.jackson.databind.JsonSerializer#resolve}) and/or contextualized
1026-
* (via {@link com.fasterxml.jackson.databind.ser.ContextualSerializer}) as necessary.
1023+
* Either way, serializer will be properly resolved
1024+
* (via {@link com.fasterxml.jackson.databind.JsonSerializer#resolve}).
10271025
*
10281026
* @param annotated Annotated entity that contained definition
10291027
* @param serDef Serializer definition: either an instance or class
@@ -1039,8 +1037,6 @@ public abstract JsonSerializer<Object> serializerInstance(Annotated annotated,
10391037
*
10401038
* @param forProperty (optional) If filter is created for a property, that property;
10411039
* `null` if filter created via defaulting, global or per-type.
1042-
*
1043-
* @since 2.9
10441040
*/
10451041
public abstract Object includeFilterInstance(BeanPropertyDefinition forProperty,
10461042
Class<?> filterClass)
@@ -1049,8 +1045,6 @@ public abstract Object includeFilterInstance(BeanPropertyDefinition forProperty,
10491045
/**
10501046
* Follow-up method that may be called after calling {@link #includeFilterInstance},
10511047
* to check handling of `null` values by the filter.
1052-
*
1053-
* @since 2.9
10541048
*/
10551049
public abstract boolean includeFilterSuppressNulls(Object filter)
10561050
throws JsonMappingException;
@@ -1064,8 +1058,8 @@ public abstract boolean includeFilterSuppressNulls(Object filter)
10641058
/**
10651059
* Method called for primary property serializers (ones
10661060
* directly created to serialize values of a POJO property),
1067-
* to handle details of resolving
1068-
* {@link ContextualSerializer} with given property context.
1061+
* to handle details of contextualization, calling
1062+
* {@link JsonSerializer#createContextual(SerializerProvider, BeanProperty)} with given property context.
10691063
*
10701064
* @param property Property for which the given primary serializer is used; never null.
10711065
*/
@@ -1074,9 +1068,7 @@ public JsonSerializer<?> handlePrimaryContextualization(JsonSerializer<?> ser,
10741068
throws JsonMappingException
10751069
{
10761070
if (ser != null) {
1077-
if (ser instanceof ContextualSerializer) {
1078-
ser = ((ContextualSerializer) ser).createContextual(this, property);
1079-
}
1071+
ser = ser.createContextual(this, property);
10801072
}
10811073
return ser;
10821074
}
@@ -1086,29 +1078,25 @@ public JsonSerializer<?> handlePrimaryContextualization(JsonSerializer<?> ser,
10861078
* NOT directly created to serialize values of a POJO property
10871079
* but instead created as a dependant serializer -- such as value serializers
10881080
* for structured types, or serializers for root values)
1089-
* to handle details of resolving
1090-
* {@link ContextualDeserializer} with given property context.
1081+
* to handle details of contextualization, calling
1082+
* {@link JsonSerializer#createContextual(SerializerProvider, BeanProperty)} with given property context.
10911083
* Given that these serializers are not directly related to given property
10921084
* (or, in case of root value property, to any property), annotations
10931085
* accessible may or may not be relevant.
10941086
*
10951087
* @param property Property for which serializer is used, if any; null
10961088
* when deserializing root values
1097-
*
1098-
* @since 2.3
10991089
*/
11001090
public JsonSerializer<?> handleSecondaryContextualization(JsonSerializer<?> ser,
11011091
BeanProperty property)
11021092
throws JsonMappingException
11031093
{
11041094
if (ser != null) {
1105-
if (ser instanceof ContextualSerializer) {
1106-
ser = ((ContextualSerializer) ser).createContextual(this, property);
1107-
}
1095+
ser = ser.createContextual(this, property);
11081096
}
11091097
return ser;
11101098
}
1111-
1099+
11121100
/*
11131101
/********************************************************
11141102
/* Convenience methods for serializing using default methods

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
*/
2626
public class AbstractDeserializer
2727
extends JsonDeserializer<Object>
28-
implements ContextualDeserializer, // since 2.9
29-
java.io.Serializable
28+
implements java.io.Serializable
3029
{
3130
private static final long serialVersionUID = 1L;
3231

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

+1-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,7 @@
2525
*/
2626
public abstract class BeanDeserializerBase
2727
extends StdDeserializer<Object>
28-
implements ContextualDeserializer,
29-
ValueInstantiator.Gettable,
28+
implements ValueInstantiator.Gettable,
3029
java.io.Serializable
3130
{
3231
private static final long serialVersionUID = 1;

0 commit comments

Comments
 (0)