60
60
* @author Mark Paluch
61
61
* @author Mao Shuai
62
62
* @author John Blum
63
+ * @author Anne Lee
63
64
* @see org.springframework.data.redis.serializer.JacksonObjectReader
64
65
* @see org.springframework.data.redis.serializer.JacksonObjectWriter
65
66
* @see com.fasterxml.jackson.databind.ObjectMapper
@@ -92,13 +93,13 @@ public GenericJackson2JsonRedisSerializer() {
92
93
* In case {@link String name} is {@literal empty} or {@literal null}, then {@link JsonTypeInfo.Id#CLASS} will be
93
94
* used.
94
95
*
95
- * @param classPropertyTypeName {@link String name} of the JSON property holding type information; can be
96
+ * @param typeHintPropertyName {@link String name} of the JSON property holding type information; can be
96
97
* {@literal null}.
97
98
* @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
98
99
* @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
99
100
*/
100
- public GenericJackson2JsonRedisSerializer (@ Nullable String classPropertyTypeName ) {
101
- this (classPropertyTypeName , JacksonObjectReader .create (), JacksonObjectWriter .create ());
101
+ public GenericJackson2JsonRedisSerializer (@ Nullable String typeHintPropertyName ) {
102
+ this (typeHintPropertyName , JacksonObjectReader .create (), JacksonObjectWriter .create ());
102
103
}
103
104
104
105
/**
@@ -109,40 +110,22 @@ public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName
109
110
* In case {@link String name} is {@literal empty} or {@literal null}, then {@link JsonTypeInfo.Id#CLASS} will be
110
111
* used.
111
112
*
112
- * @param classPropertyTypeName {@link String name} of the JSON property holding type information; can be
113
+ * @param typeHintPropertyName {@link String name} of the JSON property holding type information; can be
113
114
* {@literal null}.
114
115
* @param reader {@link JacksonObjectReader} function to read objects using {@link ObjectMapper}.
115
116
* @param writer {@link JacksonObjectWriter} function to write objects using {@link ObjectMapper}.
116
117
* @see ObjectMapper#activateDefaultTypingAsProperty(PolymorphicTypeValidator, DefaultTyping, String)
117
118
* @see ObjectMapper#activateDefaultTyping(PolymorphicTypeValidator, DefaultTyping, As)
118
119
* @since 3.0
119
120
*/
120
- public GenericJackson2JsonRedisSerializer (@ Nullable String classPropertyTypeName , JacksonObjectReader reader ,
121
+ public GenericJackson2JsonRedisSerializer (@ Nullable String typeHintPropertyName , JacksonObjectReader reader ,
121
122
JacksonObjectWriter writer ) {
122
123
123
- this (new ObjectMapper (), reader , writer , classPropertyTypeName );
124
+ this (new ObjectMapper (), reader , writer , typeHintPropertyName );
124
125
125
- registerNullValueSerializer (this .mapper , classPropertyTypeName );
126
+ registerNullValueSerializer (this .mapper , typeHintPropertyName );
126
127
127
- StdTypeResolverBuilder typer = TypeResolverBuilder .forEverything (this .mapper ).init (JsonTypeInfo .Id .CLASS , null )
128
- .inclusion (JsonTypeInfo .As .PROPERTY );
129
-
130
- if (StringUtils .hasText (classPropertyTypeName )) {
131
- typer = typer .typeProperty (classPropertyTypeName );
132
- }
133
-
134
- this .mapper .setDefaultTyping (typer );
135
- }
136
-
137
- /**
138
- * Factory method returning a {@literal Builder} used to construct and configure a {@link GenericJackson2JsonRedisSerializer}.
139
- *
140
- * @return new {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
141
- * @since 3.3
142
- */
143
- public static GenericJackson2JsonRedisSerializerBuilder builder (ObjectMapper objectMapper , JacksonObjectReader reader ,
144
- JacksonObjectWriter writer ) {
145
- return new GenericJackson2JsonRedisSerializerBuilder (objectMapper , reader , writer );
128
+ this .mapper .setDefaultTyping (createDefaultTypeResolverBuilder (getObjectMapper (), typeHintPropertyName ));
146
129
}
147
130
148
131
/**
@@ -188,7 +171,7 @@ private GenericJackson2JsonRedisSerializer(ObjectMapper mapper, JacksonObjectRea
188
171
this .typeResolver = newTypeResolver (mapper , typeHintPropertyName , this .defaultTypingEnabled );
189
172
}
190
173
191
- private TypeResolver newTypeResolver (ObjectMapper mapper , @ Nullable String typeHintPropertyName ,
174
+ private static TypeResolver newTypeResolver (ObjectMapper mapper , @ Nullable String typeHintPropertyName ,
192
175
Lazy <Boolean > defaultTypingEnabled ) {
193
176
194
177
Lazy <TypeFactory > lazyTypeFactory = Lazy .of (mapper ::getTypeFactory );
@@ -199,19 +182,17 @@ private TypeResolver newTypeResolver(ObjectMapper mapper, @Nullable String typeH
199
182
return new TypeResolver (lazyTypeFactory , lazyTypeHintPropertyName );
200
183
}
201
184
202
- private Lazy <String > newLazyTypeHintPropertyName (ObjectMapper mapper , Lazy <Boolean > defaultTypingEnabled ) {
185
+ private static Lazy <String > newLazyTypeHintPropertyName (ObjectMapper mapper , Lazy <Boolean > defaultTypingEnabled ) {
203
186
204
187
Lazy <String > configuredTypeDeserializationPropertyName = getConfiguredTypeDeserializationPropertyName (mapper );
205
188
206
- Lazy <String > resolvedLazyTypeHintPropertyName = Lazy .of (() -> defaultTypingEnabled .get () ? null
207
- : configuredTypeDeserializationPropertyName .get ());
208
-
209
- resolvedLazyTypeHintPropertyName = resolvedLazyTypeHintPropertyName .or ("@class" );
189
+ Lazy <String > resolvedLazyTypeHintPropertyName = Lazy
190
+ .of (() -> defaultTypingEnabled .get () ? null : configuredTypeDeserializationPropertyName .get ());
210
191
211
- return resolvedLazyTypeHintPropertyName ;
192
+ return resolvedLazyTypeHintPropertyName . or ( "@class" ) ;
212
193
}
213
194
214
- private Lazy <String > getConfiguredTypeDeserializationPropertyName (ObjectMapper mapper ) {
195
+ private static Lazy <String > getConfiguredTypeDeserializationPropertyName (ObjectMapper mapper ) {
215
196
216
197
return Lazy .of (() -> {
217
198
@@ -226,20 +207,43 @@ private Lazy<String> getConfiguredTypeDeserializationPropertyName(ObjectMapper m
226
207
});
227
208
}
228
209
210
+ private static StdTypeResolverBuilder createDefaultTypeResolverBuilder (ObjectMapper objectMapper ,
211
+ @ Nullable String typeHintPropertyName ) {
212
+
213
+ StdTypeResolverBuilder typer = TypeResolverBuilder .forEverything (objectMapper ).init (JsonTypeInfo .Id .CLASS , null )
214
+ .inclusion (As .PROPERTY );
215
+
216
+ if (StringUtils .hasText (typeHintPropertyName )) {
217
+ typer = typer .typeProperty (typeHintPropertyName );
218
+ }
219
+ return typer ;
220
+ }
221
+
222
+ /**
223
+ * Factory method returning a {@literal Builder} used to construct and configure a
224
+ * {@link GenericJackson2JsonRedisSerializer}.
225
+ *
226
+ * @return new {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
227
+ * @since 3.3.1
228
+ */
229
+ public static GenericJackson2JsonRedisSerializerBuilder builder () {
230
+ return new GenericJackson2JsonRedisSerializerBuilder ();
231
+ }
232
+
229
233
/**
230
234
* Register {@link NullValueSerializer} in the given {@link ObjectMapper} with an optional
231
- * {@code classPropertyTypeName }. This method should be called by code that customizes
235
+ * {@code typeHintPropertyName }. This method should be called by code that customizes
232
236
* {@link GenericJackson2JsonRedisSerializer} by providing an external {@link ObjectMapper}.
233
237
*
234
238
* @param objectMapper the object mapper to customize.
235
- * @param classPropertyTypeName name of the type property. Defaults to {@code @class} if {@literal null}/empty.
239
+ * @param typeHintPropertyName name of the type property. Defaults to {@code @class} if {@literal null}/empty.
236
240
* @since 2.2
237
241
*/
238
- public static void registerNullValueSerializer (ObjectMapper objectMapper , @ Nullable String classPropertyTypeName ) {
242
+ public static void registerNullValueSerializer (ObjectMapper objectMapper , @ Nullable String typeHintPropertyName ) {
239
243
240
244
// Simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here
241
245
// since we need the type hint embedded for deserialization using the default typing feature.
242
- objectMapper .registerModule (new SimpleModule ().addSerializer (new NullValueSerializer (classPropertyTypeName )));
246
+ objectMapper .registerModule (new SimpleModule ().addSerializer (new NullValueSerializer (typeHintPropertyName )));
243
247
}
244
248
245
249
/**
@@ -376,8 +380,7 @@ protected JavaType resolveType(byte[] source, Class<?> type) throws IOException
376
380
*/
377
381
private static class NullValueSerializer extends StdSerializer <NullValue > {
378
382
379
- @ Serial
380
- private static final long serialVersionUID = 1999052150548658808L ;
383
+ @ Serial private static final long serialVersionUID = 1999052150548658808L ;
381
384
382
385
private final String classIdentifier ;
383
386
@@ -408,65 +411,155 @@ public void serializeWithType(NullValue value, JsonGenerator jsonGenerator, Seri
408
411
}
409
412
410
413
/**
411
- * {@literal Builder} for creating a {@link GenericJackson2JsonRedisSerializer}.
414
+ * Builder for configuring and creating a {@link GenericJackson2JsonRedisSerializer}.
412
415
*
413
416
* @author Anne Lee
414
- * @since 3.3
417
+ * @author Mark Paluch
418
+ * @since 3.3.1
415
419
*/
416
420
public static class GenericJackson2JsonRedisSerializerBuilder {
417
- @ Nullable
418
- private String classPropertyTypeName ;
419
- private JacksonObjectReader reader ;
420
- private JacksonObjectWriter writer ;
421
- private ObjectMapper mapper ;
422
- @ Nullable
423
- private StdSerializer <NullValue > nullValueSerializer ;
424
-
425
- private GenericJackson2JsonRedisSerializerBuilder (
426
- ObjectMapper objectMapper ,
427
- JacksonObjectReader reader ,
428
- JacksonObjectWriter writer
429
- ) {
430
- this .mapper = objectMapper ;
421
+
422
+ private @ Nullable String typeHintPropertyName ;
423
+
424
+ private JacksonObjectReader reader = JacksonObjectReader .create ();
425
+
426
+ private JacksonObjectWriter writer = JacksonObjectWriter .create ();
427
+
428
+ private @ Nullable ObjectMapper objectMapper ;
429
+
430
+ private @ Nullable Boolean defaultTyping ;
431
+
432
+ private boolean registerNullValueSerializer = true ;
433
+
434
+ private @ Nullable StdSerializer <NullValue > nullValueSerializer ;
435
+
436
+ private GenericJackson2JsonRedisSerializerBuilder () {}
437
+
438
+ /**
439
+ * Enable or disable default typing. Enabling default typing will override
440
+ * {@link ObjectMapper#setDefaultTyping(com.fasterxml.jackson.databind.jsontype.TypeResolverBuilder)} for a given
441
+ * {@link ObjectMapper}. Default typing is enabled by default if no {@link ObjectMapper} is provided.
442
+ *
443
+ * @param defaultTyping whether to enable/disable default typing. Enabled by default if the {@link ObjectMapper} is
444
+ * not provided.
445
+ * @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
446
+ */
447
+ public GenericJackson2JsonRedisSerializerBuilder defaultTyping (boolean defaultTyping ) {
448
+ this .defaultTyping = defaultTyping ;
449
+ return this ;
450
+ }
451
+
452
+ /**
453
+ * Configure a property name to that represents the type hint.
454
+ *
455
+ * @param typeHintPropertyName {@link String name} of the JSON property holding type information.
456
+ * @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
457
+ */
458
+ public GenericJackson2JsonRedisSerializerBuilder typeHintPropertyName (String typeHintPropertyName ) {
459
+
460
+ Assert .hasText (typeHintPropertyName , "Type hint property name must bot be null or empty" );
461
+
462
+ this .typeHintPropertyName = typeHintPropertyName ;
463
+ return this ;
464
+ }
465
+
466
+ /**
467
+ * Configure a provided {@link ObjectMapper}. Note that the provided {@link ObjectMapper} can be reconfigured with a
468
+ * {@link #nullValueSerializer} or default typing depending on the builder configuration.
469
+ *
470
+ * @param objectMapper must not be {@literal null}.
471
+ * @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
472
+ */
473
+ public GenericJackson2JsonRedisSerializerBuilder objectMapper (ObjectMapper objectMapper ) {
474
+
475
+ Assert .notNull (objectMapper , "ObjectMapper must not be null" );
476
+
477
+ this .objectMapper = objectMapper ;
478
+ return this ;
479
+ }
480
+
481
+ /**
482
+ * Configure {@link JacksonObjectReader}.
483
+ *
484
+ * @param reader must not be {@literal null}.
485
+ * @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
486
+ */
487
+ public GenericJackson2JsonRedisSerializerBuilder reader (JacksonObjectReader reader ) {
488
+
489
+ Assert .notNull (reader , "JacksonObjectReader must not be null" );
490
+
431
491
this .reader = reader ;
432
- this . writer = writer ;
492
+ return this ;
433
493
}
434
494
435
495
/**
436
- * Configure a classPropertyName .
496
+ * Configure {@link JacksonObjectWriter} .
437
497
*
438
- * @param classPropertyTypeName can be {@literal null}.
498
+ * @param writer must not be {@literal null}.
439
499
* @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
440
- * @since 3.3
441
500
*/
442
- public GenericJackson2JsonRedisSerializerBuilder classPropertyTypeName (@ Nullable String classPropertyTypeName ) {
443
- this .classPropertyTypeName = classPropertyTypeName ;
501
+ public GenericJackson2JsonRedisSerializerBuilder writer (JacksonObjectWriter writer ) {
502
+
503
+ Assert .notNull (writer , "JacksonObjectWriter must not be null" );
504
+
505
+ this .writer = writer ;
444
506
return this ;
445
507
}
446
508
447
509
/**
448
- * Register a nullValueSerializer .
510
+ * Register a {@link StdSerializer serializer} for {@link NullValue} .
449
511
*
450
- * @param nullValueSerializer the {@link StdSerializer} to use for {@link NullValue} serialization. Can be {@literal null}.
512
+ * @param nullValueSerializer the {@link StdSerializer} to use for {@link NullValue} serialization, must not be
513
+ * {@literal null}.
451
514
* @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
452
515
*/
453
- public GenericJackson2JsonRedisSerializerBuilder registerNullValueSerializer (@ Nullable StdSerializer <NullValue > nullValueSerializer ) {
516
+ public GenericJackson2JsonRedisSerializerBuilder nullValueSerializer (StdSerializer <NullValue > nullValueSerializer ) {
517
+
518
+ Assert .notNull (nullValueSerializer , "Null value serializer must not be null" );
519
+
454
520
this .nullValueSerializer = nullValueSerializer ;
455
521
return this ;
456
522
}
457
523
458
524
/**
459
- * Create new instance of {@link GenericJackson2JsonRedisSerializer} with configuration options applied.
525
+ * Configure whether to register a {@link StdSerializer serializer} for {@link NullValue} serialization. The default
526
+ * serializer considers {@link #typeHintPropertyName(String)}.
460
527
*
461
- * @return new instance of {@link GenericJackson2JsonRedisSerializer}.
528
+ * @param registerNullValueSerializer {@code true} to register the default serializer; {@code false} otherwise.
529
+ * @return this {@link GenericJackson2JsonRedisSerializer.GenericJackson2JsonRedisSerializerBuilder}.
530
+ */
531
+ public GenericJackson2JsonRedisSerializerBuilder registerNullValueSerializer (boolean registerNullValueSerializer ) {
532
+ this .registerNullValueSerializer = registerNullValueSerializer ;
533
+ return this ;
534
+ }
535
+
536
+ /**
537
+ * Creates a new instance of {@link GenericJackson2JsonRedisSerializer} with configuration options applied. Creates
538
+ * also a new {@link ObjectMapper} if none was provided.
539
+ *
540
+ * @return a new instance of {@link GenericJackson2JsonRedisSerializer}.
462
541
*/
463
542
public GenericJackson2JsonRedisSerializer build () {
464
- Assert .notNull (this .mapper , "ObjectMapper must not be null" );
465
- Assert .notNull (this .reader , "Reader must not be null" );
466
- Assert .notNull (this .writer , "Writer must not be null" );
467
543
468
- this .mapper .registerModule (new SimpleModule ().addSerializer (this .nullValueSerializer != null ? this .nullValueSerializer : new NullValueSerializer (this .classPropertyTypeName )));
469
- return new GenericJackson2JsonRedisSerializer (this .mapper , this .reader , this .writer , this .classPropertyTypeName );
544
+ ObjectMapper objectMapper = this .objectMapper ;
545
+ boolean providedObjectMapper = objectMapper != null ;
546
+
547
+ if (objectMapper == null ) {
548
+ objectMapper = new ObjectMapper ();
549
+ }
550
+
551
+ if (registerNullValueSerializer ) {
552
+ objectMapper .registerModule (new SimpleModule ("GenericJackson2JsonRedisSerializerBuilder" )
553
+ .addSerializer (this .nullValueSerializer != null ? this .nullValueSerializer
554
+ : new NullValueSerializer (this .typeHintPropertyName )));
555
+ }
556
+
557
+ if ((!providedObjectMapper && (defaultTyping == null || defaultTyping ))
558
+ || (defaultTyping != null && defaultTyping )) {
559
+ objectMapper .setDefaultTyping (createDefaultTypeResolverBuilder (objectMapper , typeHintPropertyName ));
560
+ }
561
+
562
+ return new GenericJackson2JsonRedisSerializer (objectMapper , this .reader , this .writer , this .typeHintPropertyName );
470
563
}
471
564
}
472
565
0 commit comments