20
20
import org .springframework .cache .support .NullValue ;
21
21
import org .springframework .lang .Nullable ;
22
22
import org .springframework .util .Assert ;
23
+ import org .springframework .util .ClassUtils ;
23
24
import org .springframework .util .StringUtils ;
24
25
25
26
import com .fasterxml .jackson .annotation .JsonTypeInfo ;
26
27
import com .fasterxml .jackson .annotation .JsonTypeInfo .As ;
27
28
import com .fasterxml .jackson .core .JsonGenerator ;
28
29
import com .fasterxml .jackson .core .JsonProcessingException ;
30
+ import com .fasterxml .jackson .core .TreeNode ;
31
+ import com .fasterxml .jackson .databind .JavaType ;
29
32
import com .fasterxml .jackson .databind .ObjectMapper ;
30
33
import com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping ;
31
34
import com .fasterxml .jackson .databind .SerializerProvider ;
32
35
import com .fasterxml .jackson .databind .jsontype .PolymorphicTypeValidator ;
33
36
import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
37
+ import com .fasterxml .jackson .databind .jsontype .impl .StdTypeResolverBuilder ;
34
38
import com .fasterxml .jackson .databind .module .SimpleModule ;
35
39
import com .fasterxml .jackson .databind .ser .SerializerFactory ;
36
40
import com .fasterxml .jackson .databind .ser .std .StdSerializer ;
@@ -71,12 +75,15 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
71
75
// the type hint embedded for deserialization using the default typing feature.
72
76
registerNullValueSerializer (mapper , classPropertyTypeName );
73
77
78
+ StdTypeResolverBuilder typer = new TypeResolverBuilder (DefaultTyping .EVERYTHING ,
79
+ mapper .getPolymorphicTypeValidator ());
80
+ typer = typer .init (JsonTypeInfo .Id .CLASS , null );
81
+ typer = typer .inclusion (JsonTypeInfo .As .PROPERTY );
82
+
74
83
if (StringUtils .hasText (classPropertyTypeName )) {
75
- mapper .activateDefaultTypingAsProperty (mapper .getPolymorphicTypeValidator (), DefaultTyping .EVERYTHING ,
76
- classPropertyTypeName );
77
- } else {
78
- mapper .activateDefaultTyping (mapper .getPolymorphicTypeValidator (), DefaultTyping .EVERYTHING , As .PROPERTY );
84
+ typer = typer .typeProperty (classPropertyTypeName );
79
85
}
86
+ mapper .setDefaultTyping (typer );
80
87
}
81
88
82
89
/**
@@ -184,8 +191,7 @@ private static class NullValueSerializer extends StdSerializer<NullValue> {
184
191
* @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
185
192
*/
186
193
@ Override
187
- public void serialize (NullValue value , JsonGenerator jgen , SerializerProvider provider )
188
- throws IOException {
194
+ public void serialize (NullValue value , JsonGenerator jgen , SerializerProvider provider ) throws IOException {
189
195
190
196
jgen .writeStartObject ();
191
197
jgen .writeStringField (classIdentifier , NullValue .class .getName ());
@@ -198,4 +204,52 @@ public void serializeWithType(NullValue value, JsonGenerator gen, SerializerProv
198
204
serialize (value , gen , serializers );
199
205
}
200
206
}
207
+
208
+ /**
209
+ * Custom {@link StdTypeResolverBuilder} that considers typing for non-primitive types. Primitives, their wrappers and
210
+ * primitive arrays do not require type hints. The default {@code DefaultTyping#EVERYTHING} typing does not satisfy
211
+ * those requirements.
212
+ *
213
+ * @author Mark Paluch
214
+ * @since 2.7.2
215
+ */
216
+ private static class TypeResolverBuilder extends ObjectMapper .DefaultTypeResolverBuilder {
217
+
218
+ public TypeResolverBuilder (DefaultTyping t , PolymorphicTypeValidator ptv ) {
219
+ super (t , ptv );
220
+ }
221
+
222
+ @ Override
223
+ public ObjectMapper .DefaultTypeResolverBuilder withDefaultImpl (Class <?> defaultImpl ) {
224
+ return this ;
225
+ }
226
+
227
+ /**
228
+ * Method called to check if the default type handler should be used for given type. Note: "natural types" (String,
229
+ * Boolean, Integer, Double) will never use typing; that is both due to them being concrete and final, and since
230
+ * actual serializers and deserializers will also ignore any attempts to enforce typing.
231
+ */
232
+ public boolean useForType (JavaType t ) {
233
+
234
+ if (t .isJavaLangObject ()) {
235
+ return true ;
236
+ }
237
+
238
+ while (t .isArrayType ()) {
239
+ t = t .getContentType ();
240
+ }
241
+
242
+ if (ClassUtils .isPrimitiveOrWrapper (t .getRawClass ())) {
243
+ return false ;
244
+ }
245
+
246
+ // 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
247
+ while (t .isReferenceType ()) {
248
+ t = t .getReferencedType ();
249
+ }
250
+
251
+ // [databind#88] Should not apply to JSON tree models:
252
+ return !TreeNode .class .isAssignableFrom (t .getRawClass ());
253
+ }
254
+ }
201
255
}
0 commit comments