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
This commit is contained in:
Christoph Strobl
2022-07-14 12:29:25 +02:00
parent b43c98a1a5
commit 7f368c48ed
2 changed files with 112 additions and 10 deletions

View File

@@ -349,21 +349,33 @@ public class GenericJackson2JsonRedisSerializer implements RedisSerializer<Objec
return true;
}
while (t.isArrayType()) {
t = t.getContentType();
}
t = resolveArrayOrWrapper(t);
if (ClassUtils.isPrimitiveOrWrapper(t.getRawClass())) {
return false;
}
// 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
while (t.isReferenceType()) {
t = t.getReferencedType();
}
// [databind#88] Should not apply to JSON tree models:
return !TreeNode.class.isAssignableFrom(t.getRawClass());
}
private JavaType resolveArrayOrWrapper(JavaType type) {
while (type.isArrayType()) {
type = type.getContentType();
if (type.isReferenceType()) {
type = resolveArrayOrWrapper(type);
}
}
while (type.isReferenceType()) {
type = type.getReferencedType();
if (type.isArrayType()) {
type = resolveArrayOrWrapper(type);
}
}
return type;
}
}
}

View File

@@ -24,6 +24,7 @@ import lombok.Data;
import lombok.ToString;
import java.io.IOException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.Map;
import org.junit.jupiter.api.Test;
@@ -171,7 +172,7 @@ class GenericJackson2JsonRedisSerializerUnitTests {
}
@Test // GH-2361
void shouldDeserializeArrayWithoutTypeHint() {
void shouldDeserializePrimitiveArrayWithoutTypeHint() {
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
CountAndArray result = (CountAndArray) gs.deserialize(
@@ -262,6 +263,87 @@ class GenericJackson2JsonRedisSerializerUnitTests {
});
}
@Test // GH-2361
void shouldDeserializePrimitiveWrapperArrayWithoutTypeHint() {
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
CountAndArray result = (CountAndArray) gs.deserialize(
("{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$CountAndArray\", \"count\":1, \"arrayOfPrimitiveWrapper\":[0,1]}")
.getBytes());
assertThat(result.getCount()).isEqualTo(1);
assertThat(result.getArrayOfPrimitiveWrapper()).containsExactly(0L, 1L);
}
@Test // GH-2361
void doesNotIncludeTypingForPrimitiveArrayWrappers() {
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
WithWrapperTypes source = new WithWrapperTypes();
source.primitiveWrapper = new AtomicReference<>();
source.primitiveArrayWrapper = new AtomicReference<>(new Integer[] { 200, 300 });
source.simpleObjectWrapper = new AtomicReference<>();
byte[] serializedValue = serializer.serialize(source);
assertThat(new String(serializedValue)) //
.contains("\"primitiveArrayWrapper\":[200,300]") //
.doesNotContain("\"[Ljava.lang.Integer;\"");
assertThat(serializer.deserialize(serializedValue)) //
.isInstanceOf(WithWrapperTypes.class) //
.satisfies(it -> {
WithWrapperTypes deserialized = (WithWrapperTypes) it;
assertThat(deserialized.primitiveArrayWrapper).hasValue(source.primitiveArrayWrapper.get());
});
}
@Test // GH-2361
void doesNotIncludeTypingForPrimitiveWrappers() {
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
WithWrapperTypes source = new WithWrapperTypes();
source.primitiveWrapper = new AtomicReference<>(123L);
byte[] serializedValue = serializer.serialize(source);
assertThat(new String(serializedValue)) //
.contains("\"primitiveWrapper\":123") //
.doesNotContain("\"Ljava.lang.Long;\"");
assertThat(serializer.deserialize(serializedValue)) //
.isInstanceOf(WithWrapperTypes.class) //
.satisfies(it -> {
WithWrapperTypes deserialized = (WithWrapperTypes) it;
assertThat(deserialized.primitiveWrapper).hasValue(source.primitiveWrapper.get());
});
}
@Test // GH-2361
void includesTypingForWrappedObjectTypes() {
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
SimpleObject simpleObject = new SimpleObject(100L);
WithWrapperTypes source = new WithWrapperTypes();
source.simpleObjectWrapper = new AtomicReference<>(simpleObject);
byte[] serializedValue = serializer.serialize(source);
assertThat(new String(serializedValue)) //
.contains(
"\"simpleObjectWrapper\":{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$SimpleObject\",\"longValue\":100}");
assertThat(serializer.deserialize(serializedValue)) //
.isInstanceOf(WithWrapperTypes.class) //
.satisfies(it -> {
WithWrapperTypes deserialized = (WithWrapperTypes) it;
assertThat(deserialized.simpleObjectWrapper).hasValue(source.simpleObjectWrapper.get());
});
}
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
@@ -311,7 +393,6 @@ class GenericJackson2JsonRedisSerializerUnitTests {
return nullSafeEquals(this.stringValue, other.stringValue)
&& nullSafeEquals(this.simpleObject, other.simpleObject);
}
}
@Data
@@ -373,5 +454,14 @@ class GenericJackson2JsonRedisSerializerUnitTests {
private int count;
private int[] available;
private Long[] arrayOfPrimitiveWrapper;
}
@Data
static class WithWrapperTypes {
AtomicReference<Long> primitiveWrapper;
AtomicReference<Integer[]> primitiveArrayWrapper;
AtomicReference<SimpleObject> simpleObjectWrapper;
}
}