2020import org .springframework .cache .support .NullValue ;
2121import org .springframework .lang .Nullable ;
2222import org .springframework .util .Assert ;
23+ import org .springframework .util .ClassUtils ;
2324import org .springframework .util .StringUtils ;
2425
2526import com .fasterxml .jackson .annotation .JsonTypeInfo ;
2627import com .fasterxml .jackson .annotation .JsonTypeInfo .As ;
2728import com .fasterxml .jackson .core .JsonGenerator ;
2829import com .fasterxml .jackson .core .JsonProcessingException ;
30+ import com .fasterxml .jackson .core .TreeNode ;
31+ import com .fasterxml .jackson .databind .JavaType ;
2932import com .fasterxml .jackson .databind .ObjectMapper ;
3033import com .fasterxml .jackson .databind .ObjectMapper .DefaultTyping ;
3134import com .fasterxml .jackson .databind .SerializerProvider ;
3235import com .fasterxml .jackson .databind .jsontype .PolymorphicTypeValidator ;
3336import com .fasterxml .jackson .databind .jsontype .TypeSerializer ;
37+ import com .fasterxml .jackson .databind .jsontype .impl .StdTypeResolverBuilder ;
3438import com .fasterxml .jackson .databind .module .SimpleModule ;
3539import com .fasterxml .jackson .databind .ser .SerializerFactory ;
3640import com .fasterxml .jackson .databind .ser .std .StdSerializer ;
@@ -71,12 +75,15 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
7175 // the type hint embedded for deserialization using the default typing feature.
7276 registerNullValueSerializer (mapper , classPropertyTypeName );
7377
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+
7483 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 );
7985 }
86+ mapper .setDefaultTyping (typer );
8087 }
8188
8289 /**
@@ -184,8 +191,7 @@ private static class NullValueSerializer extends StdSerializer<NullValue> {
184191 * @see com.fasterxml.jackson.databind.ser.std.StdSerializer#serialize(java.lang.Object, com.fasterxml.jackson.core.JsonGenerator, com.fasterxml.jackson.databind.SerializerProvider)
185192 */
186193 @ 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 {
189195
190196 jgen .writeStartObject ();
191197 jgen .writeStringField (classIdentifier , NullValue .class .getName ());
@@ -198,4 +204,52 @@ public void serializeWithType(NullValue value, JsonGenerator gen, SerializerProv
198204 serialize (value , gen , serializers );
199205 }
200206 }
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+ }
201255}
0 commit comments