Skip to content

Commit 7f368c4

Browse files
Resolve target type of wrapped one in custom StdTypeResolverBuilder.
This commit makes sure to avoid typing of primitive wrapper types wrapped inside what is considered a jackson ReferenceType (such as Optional, AtomicReference,...). Original Pull Request: #2364
1 parent b43c98a commit 7f368c4

File tree

2 files changed

+112
-10
lines changed

2 files changed

+112
-10
lines changed

src/main/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializer.java

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -349,21 +349,33 @@ public boolean useForType(JavaType t) {
349349
return true;
350350
}
351351

352-
while (t.isArrayType()) {
353-
t = t.getContentType();
354-
}
352+
t = resolveArrayOrWrapper(t);
355353

356354
if (ClassUtils.isPrimitiveOrWrapper(t.getRawClass())) {
357355
return false;
358356
}
359357

360-
// 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
361-
while (t.isReferenceType()) {
362-
t = t.getReferencedType();
363-
}
364-
365358
// [databind#88] Should not apply to JSON tree models:
366359
return !TreeNode.class.isAssignableFrom(t.getRawClass());
367360
}
361+
362+
private JavaType resolveArrayOrWrapper(JavaType type) {
363+
364+
while (type.isArrayType()) {
365+
type = type.getContentType();
366+
if (type.isReferenceType()) {
367+
type = resolveArrayOrWrapper(type);
368+
}
369+
}
370+
371+
while (type.isReferenceType()) {
372+
type = type.getReferencedType();
373+
if (type.isArrayType()) {
374+
type = resolveArrayOrWrapper(type);
375+
}
376+
}
377+
378+
return type;
379+
}
368380
}
369381
}

src/test/java/org/springframework/data/redis/serializer/GenericJackson2JsonRedisSerializerUnitTests.java

Lines changed: 92 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import lombok.ToString;
2525

2626
import java.io.IOException;
27+
import java.util.concurrent.atomic.AtomicReference;
2728
import java.util.Map;
2829

2930
import org.junit.jupiter.api.Test;
@@ -171,7 +172,7 @@ void deserializeShouldBeAbleToRestoreFinalObjectAfterSerialization() {
171172
}
172173

173174
@Test // GH-2361
174-
void shouldDeserializeArrayWithoutTypeHint() {
175+
void shouldDeserializePrimitiveArrayWithoutTypeHint() {
175176

176177
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
177178
CountAndArray result = (CountAndArray) gs.deserialize(
@@ -262,6 +263,87 @@ void shouldConsiderReader() {
262263
});
263264
}
264265

266+
@Test // GH-2361
267+
void shouldDeserializePrimitiveWrapperArrayWithoutTypeHint() {
268+
269+
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
270+
CountAndArray result = (CountAndArray) gs.deserialize(
271+
("{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$CountAndArray\", \"count\":1, \"arrayOfPrimitiveWrapper\":[0,1]}")
272+
.getBytes());
273+
274+
assertThat(result.getCount()).isEqualTo(1);
275+
assertThat(result.getArrayOfPrimitiveWrapper()).containsExactly(0L, 1L);
276+
}
277+
278+
@Test // GH-2361
279+
void doesNotIncludeTypingForPrimitiveArrayWrappers() {
280+
281+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
282+
283+
WithWrapperTypes source = new WithWrapperTypes();
284+
source.primitiveWrapper = new AtomicReference<>();
285+
source.primitiveArrayWrapper = new AtomicReference<>(new Integer[] { 200, 300 });
286+
source.simpleObjectWrapper = new AtomicReference<>();
287+
288+
byte[] serializedValue = serializer.serialize(source);
289+
290+
assertThat(new String(serializedValue)) //
291+
.contains("\"primitiveArrayWrapper\":[200,300]") //
292+
.doesNotContain("\"[Ljava.lang.Integer;\"");
293+
294+
assertThat(serializer.deserialize(serializedValue)) //
295+
.isInstanceOf(WithWrapperTypes.class) //
296+
.satisfies(it -> {
297+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
298+
assertThat(deserialized.primitiveArrayWrapper).hasValue(source.primitiveArrayWrapper.get());
299+
});
300+
}
301+
302+
@Test // GH-2361
303+
void doesNotIncludeTypingForPrimitiveWrappers() {
304+
305+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
306+
307+
WithWrapperTypes source = new WithWrapperTypes();
308+
source.primitiveWrapper = new AtomicReference<>(123L);
309+
310+
byte[] serializedValue = serializer.serialize(source);
311+
312+
assertThat(new String(serializedValue)) //
313+
.contains("\"primitiveWrapper\":123") //
314+
.doesNotContain("\"Ljava.lang.Long;\"");
315+
316+
assertThat(serializer.deserialize(serializedValue)) //
317+
.isInstanceOf(WithWrapperTypes.class) //
318+
.satisfies(it -> {
319+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
320+
assertThat(deserialized.primitiveWrapper).hasValue(source.primitiveWrapper.get());
321+
});
322+
}
323+
324+
@Test // GH-2361
325+
void includesTypingForWrappedObjectTypes() {
326+
327+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
328+
329+
SimpleObject simpleObject = new SimpleObject(100L);
330+
WithWrapperTypes source = new WithWrapperTypes();
331+
source.simpleObjectWrapper = new AtomicReference<>(simpleObject);
332+
333+
byte[] serializedValue = serializer.serialize(source);
334+
335+
assertThat(new String(serializedValue)) //
336+
.contains(
337+
"\"simpleObjectWrapper\":{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$SimpleObject\",\"longValue\":100}");
338+
339+
assertThat(serializer.deserialize(serializedValue)) //
340+
.isInstanceOf(WithWrapperTypes.class) //
341+
.satisfies(it -> {
342+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
343+
assertThat(deserialized.simpleObjectWrapper).hasValue(source.simpleObjectWrapper.get());
344+
});
345+
}
346+
265347
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
266348

267349
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
@@ -311,7 +393,6 @@ public boolean equals(Object obj) {
311393
return nullSafeEquals(this.stringValue, other.stringValue)
312394
&& nullSafeEquals(this.simpleObject, other.simpleObject);
313395
}
314-
315396
}
316397

317398
@Data
@@ -373,5 +454,14 @@ static class CountAndArray {
373454

374455
private int count;
375456
private int[] available;
457+
private Long[] arrayOfPrimitiveWrapper;
458+
}
459+
460+
@Data
461+
static class WithWrapperTypes {
462+
463+
AtomicReference<Long> primitiveWrapper;
464+
AtomicReference<Integer[]> primitiveArrayWrapper;
465+
AtomicReference<SimpleObject> simpleObjectWrapper;
376466
}
377467
}

0 commit comments

Comments
 (0)