7
7
import java .util .Set ;
8
8
9
9
import com .fasterxml .jackson .annotation .JsonTypeInfo .As ;
10
+
10
11
import com .fasterxml .jackson .core .*;
11
12
import com .fasterxml .jackson .core .type .WritableTypeId ;
13
+
12
14
import com .fasterxml .jackson .databind .*;
13
15
import com .fasterxml .jackson .databind .annotation .JacksonStdImpl ;
14
16
import com .fasterxml .jackson .databind .introspect .AnnotatedMember ;
20
22
import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
21
23
import com .fasterxml .jackson .databind .ser .BeanSerializer ;
22
24
import com .fasterxml .jackson .databind .ser .ContextualSerializer ;
25
+ import com .fasterxml .jackson .databind .ser .impl .PropertySerializerMap ;
23
26
import com .fasterxml .jackson .databind .util .ClassUtil ;
24
27
25
28
/**
@@ -49,14 +52,29 @@ public class JsonValueSerializer
49
52
50
53
protected final BeanProperty _property ;
51
54
55
+ /**
56
+ * Declared type of the value accessed, as declared by accessor.
57
+ *
58
+ * @since 2.12
59
+ */
60
+ protected final JavaType _valueType ;
61
+
52
62
/**
53
63
* This is a flag that is set in rare (?) cases where this serializer
54
64
* is used for "natural" types (boolean, int, String, double); and where
55
65
* we actually must force type information wrapping, even though
56
66
* one would not normally be added.
57
67
*/
58
68
protected final boolean _forceTypeInformation ;
59
-
69
+
70
+ /**
71
+ * If value type cannot be statically determined, mapping from
72
+ * runtime value types to serializers are cached in this object.
73
+ *
74
+ * @since 2.12
75
+ */
76
+ protected transient PropertySerializerMap _dynamicSerializers ;
77
+
60
78
/*
61
79
/**********************************************************
62
80
/* Life-cycle
@@ -77,9 +95,11 @@ public JsonValueSerializer(AnnotatedMember accessor, JsonSerializer<?> ser)
77
95
{
78
96
super (accessor .getType ());
79
97
_accessor = accessor ;
98
+ _valueType = accessor .getType ();
80
99
_valueSerializer = (JsonSerializer <Object >) ser ;
81
100
_property = null ;
82
101
_forceTypeInformation = true ; // gets reconsidered when we are contextualized
102
+ _dynamicSerializers = PropertySerializerMap .emptyForProperties ();
83
103
}
84
104
85
105
@ SuppressWarnings ("unchecked" )
@@ -88,9 +108,11 @@ public JsonValueSerializer(JsonValueSerializer src, BeanProperty property,
88
108
{
89
109
super (_notNullClass (src .handledType ()));
90
110
_accessor = src ._accessor ;
111
+ _valueType = src ._valueType ;
91
112
_valueSerializer = (JsonSerializer <Object >) ser ;
92
113
_property = property ;
93
114
_forceTypeInformation = forceTypeInfo ;
115
+ _dynamicSerializers = PropertySerializerMap .emptyForProperties ();
94
116
}
95
117
96
118
@ SuppressWarnings ("unchecked" )
@@ -107,7 +129,41 @@ public JsonValueSerializer withResolved(BeanProperty property,
107
129
}
108
130
return new JsonValueSerializer (this , property , ser , forceTypeInfo );
109
131
}
110
-
132
+
133
+ /*
134
+ /**********************************************************
135
+ /* Overrides
136
+ /**********************************************************
137
+ */
138
+
139
+ @ Override // since 2.12
140
+ public boolean isEmpty (SerializerProvider ctxt , Object value0 )
141
+ {
142
+ Object referenced = _accessor .getValue (value0 );
143
+
144
+ if (referenced == null ) {
145
+ return true ;
146
+ }
147
+ JsonSerializer <Object > ser = _valueSerializer ;
148
+ if (ser == null ) {
149
+ try {
150
+ Class <?> cc = referenced .getClass ();
151
+ ser = _dynamicSerializers .serializerFor (cc );
152
+ if (ser == null ) {
153
+ if (_valueType .hasGenericTypes ()) {
154
+ ser = _findAndAddDynamic (_dynamicSerializers ,
155
+ ctxt .constructSpecializedType (_valueType , cc ), ctxt );
156
+ } else {
157
+ ser = _findAndAddDynamic (_dynamicSerializers , cc , ctxt );
158
+ }
159
+ }
160
+ } catch (JsonMappingException e ) {
161
+ throw new RuntimeJsonMappingException (e );
162
+ }
163
+ }
164
+ return ser .isEmpty (ctxt , referenced );
165
+ }
166
+
111
167
/*
112
168
/**********************************************************
113
169
/* Post-processing
@@ -129,20 +185,19 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
129
185
// if not, we don't really know the actual type until we get the instance.
130
186
131
187
// 10-Mar-2010, tatu: Except if static typing is to be used
132
- JavaType t = _accessor .getType ();
133
- if (provider .isEnabled (MapperFeature .USE_STATIC_TYPING ) || t .isFinal ()) {
188
+ if (provider .isEnabled (MapperFeature .USE_STATIC_TYPING ) || _valueType .isFinal ()) {
134
189
// false -> no need to cache
135
190
/* 10-Mar-2010, tatu: Ideally we would actually separate out type
136
191
* serializer from value serializer; but, alas, there's no access
137
192
* to serializer factory at this point...
138
193
*/
139
194
// 05-Sep-2013, tatu: I _think_ this can be considered a primary property...
140
- ser = provider .findPrimaryPropertySerializer (t , property );
195
+ ser = provider .findPrimaryPropertySerializer (_valueType , property );
141
196
/* 09-Dec-2010, tatu: Turns out we must add special handling for
142
197
* cases where "native" (aka "natural") type is being serialized,
143
198
* using standard serializer
144
199
*/
145
- boolean forceTypeInformation = isNaturalTypeWithStdHandling (t .getRawClass (), ser );
200
+ boolean forceTypeInformation = isNaturalTypeWithStdHandling (_valueType .getRawClass (), ser );
146
201
return withResolved (property , ser , forceTypeInformation );
147
202
}
148
203
// [databind#2822]: better hold on to "property", regardless
@@ -164,27 +219,30 @@ public JsonSerializer<?> createContextual(SerializerProvider provider,
164
219
*/
165
220
166
221
@ Override
167
- public void serialize (Object bean , JsonGenerator gen , SerializerProvider prov ) throws IOException
222
+ public void serialize (Object bean , JsonGenerator gen , SerializerProvider provider ) throws IOException
168
223
{
169
224
try {
170
225
Object value = _accessor .getValue (bean );
171
226
if (value == null ) {
172
- prov .defaultSerializeNull (gen );
227
+ provider .defaultSerializeNull (gen );
173
228
return ;
174
229
}
175
230
JsonSerializer <Object > ser = _valueSerializer ;
176
231
if (ser == null ) {
177
- Class <?> c = value .getClass ();
178
- // 10-Mar-2010, tatu: Ideally we would actually separate out type
179
- // serializer from value serializer; but, alas, there's no access
180
- // to serializer factory at this point...
181
-
182
- // let's cache it, may be needed soon again
183
- ser = prov .findTypedValueSerializer (c , true , _property );
232
+ Class <?> cc = value .getClass ();
233
+ ser = _dynamicSerializers .serializerFor (cc );
234
+ if (ser == null ) {
235
+ if (_valueType .hasGenericTypes ()) {
236
+ ser = _findAndAddDynamic (_dynamicSerializers ,
237
+ provider .constructSpecializedType (_valueType , cc ), provider );
238
+ } else {
239
+ ser = _findAndAddDynamic (_dynamicSerializers , cc , provider );
240
+ }
241
+ }
184
242
}
185
- ser .serialize (value , gen , prov );
243
+ ser .serialize (value , gen , provider );
186
244
} catch (Exception e ) {
187
- wrapAndThrow (prov , e , bean , _accessor .getName () + "()" );
245
+ wrapAndThrow (provider , e , bean , _accessor .getName () + "()" );
188
246
}
189
247
}
190
248
@@ -203,7 +261,16 @@ public void serializeWithType(Object bean, JsonGenerator gen, SerializerProvider
203
261
}
204
262
JsonSerializer <Object > ser = _valueSerializer ;
205
263
if (ser == null ) { // no serializer yet? Need to fetch
206
- ser = provider .findValueSerializer (value .getClass (), _property );
264
+ Class <?> cc = value .getClass ();
265
+ ser = _dynamicSerializers .serializerFor (cc );
266
+ if (ser == null ) {
267
+ if (_valueType .hasGenericTypes ()) {
268
+ ser = _findAndAddDynamic (_dynamicSerializers ,
269
+ provider .constructSpecializedType (_valueType , cc ), provider );
270
+ } else {
271
+ ser = _findAndAddDynamic (_dynamicSerializers , cc , provider );
272
+ }
273
+ }
207
274
} else {
208
275
// 09-Dec-2010, tatu: To work around natural type's refusal to add type info, we do
209
276
// this (note: type is for the wrapper type, not enclosed value!)
@@ -219,7 +286,7 @@ public void serializeWithType(Object bean, JsonGenerator gen, SerializerProvider
219
286
}
220
287
// 28-Sep-2016, tatu: As per [databind#1385], we do need to do some juggling
221
288
// to use different Object for type id (logical type) and actual serialization
222
- // (delegat type).
289
+ // (delegate type).
223
290
TypeSerializerRerouter rr = new TypeSerializerRerouter (typeSer0 , bean );
224
291
ser .serializeWithType (value , gen , provider , rr );
225
292
} catch (Exception e ) {
@@ -251,7 +318,6 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t
251
318
*
252
319
* Note that meaning of JsonValue, then, is very different for Enums. Sigh.
253
320
*/
254
- final JavaType type = _accessor .getType ();
255
321
Class <?> declaring = _accessor .getDeclaringClass ();
256
322
if ((declaring != null ) && ClassUtil .isEnumType (declaring )) {
257
323
if (_acceptJsonFormatVisitorForEnum (visitor , typeHint , declaring )) {
@@ -260,13 +326,13 @@ public void acceptJsonFormatVisitor(JsonFormatVisitorWrapper visitor, JavaType t
260
326
}
261
327
JsonSerializer <Object > ser = _valueSerializer ;
262
328
if (ser == null ) {
263
- ser = visitor .getProvider ().findTypedValueSerializer (type , false , _property );
329
+ ser = visitor .getProvider ().findTypedValueSerializer (_valueType , false , _property );
264
330
if (ser == null ) { // can this ever occur?
265
331
visitor .expectAnyFormat (typeHint );
266
332
return ;
267
333
}
268
334
}
269
- ser .acceptJsonFormatVisitor (visitor , type );
335
+ ser .acceptJsonFormatVisitor (visitor , _valueType );
270
336
}
271
337
272
338
/**
@@ -322,6 +388,34 @@ protected boolean isNaturalTypeWithStdHandling(Class<?> rawType, JsonSerializer<
322
388
return isDefaultSerializer (ser );
323
389
}
324
390
391
+ // @since 2.12
392
+ protected final JsonSerializer <Object > _findAndAddDynamic (PropertySerializerMap map ,
393
+ Class <?> type , SerializerProvider provider ) throws JsonMappingException
394
+ {
395
+ // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do:
396
+ JsonSerializer <Object > serializer = provider .findTypedValueSerializer (type , false , _property );
397
+ PropertySerializerMap .SerializerAndMapResult result = _dynamicSerializers .addSerializer (type , serializer );
398
+ // did we get a new map of serializers? If so, start using it
399
+ if (map != result .map ) {
400
+ _dynamicSerializers = result .map ;
401
+ }
402
+ return serializer ;
403
+ }
404
+
405
+ // @since 2.12
406
+ protected final JsonSerializer <Object > _findAndAddDynamic (PropertySerializerMap map ,
407
+ JavaType type , SerializerProvider provider ) throws JsonMappingException
408
+ {
409
+ // 31-Oct-2020, tatu: Should not get typed/root serializer, but for now has to do:
410
+ JsonSerializer <Object > serializer = provider .findTypedValueSerializer (type , false , _property );
411
+ PropertySerializerMap .SerializerAndMapResult result = _dynamicSerializers .addSerializer (type , serializer );
412
+ // did we get a new map of serializers? If so, start using it
413
+ if (map != result .map ) {
414
+ _dynamicSerializers = result .map ;
415
+ }
416
+ return serializer ;
417
+ }
418
+
325
419
/*
326
420
/**********************************************************
327
421
/* Other methods
0 commit comments