Skip to content

Commit 0897825

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 0e23a80 commit 0897825

File tree

2 files changed

+111
-10
lines changed

2 files changed

+111
-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
@@ -235,21 +235,33 @@ public boolean useForType(JavaType t) {
235235
return true;
236236
}
237237

238-
while (t.isArrayType()) {
239-
t = t.getContentType();
240-
}
238+
t = resolveArrayOrWrapper(t);
241239

242240
if (ClassUtils.isPrimitiveOrWrapper(t.getRawClass())) {
243241
return false;
244242
}
245243

246-
// 19-Apr-2016, tatu: ReferenceType like Optional also requires similar handling:
247-
while (t.isReferenceType()) {
248-
t = t.getReferencedType();
249-
}
250-
251244
// [databind#88] Should not apply to JSON tree models:
252245
return !TreeNode.class.isAssignableFrom(t.getRawClass());
253246
}
247+
248+
private JavaType resolveArrayOrWrapper(JavaType type) {
249+
250+
while (type.isArrayType()) {
251+
type = type.getContentType();
252+
if (type.isReferenceType()) {
253+
type = resolveArrayOrWrapper(type);
254+
}
255+
}
256+
257+
while (type.isReferenceType()) {
258+
type = type.getReferencedType();
259+
if (type.isArrayType()) {
260+
type = resolveArrayOrWrapper(type);
261+
}
262+
}
263+
264+
return type;
265+
}
254266
}
255267
}

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

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import lombok.Data;
2424

2525
import java.io.IOException;
26+
import java.util.concurrent.atomic.AtomicReference;
2627

2728
import org.junit.jupiter.api.Test;
2829
import org.mockito.Mockito;
@@ -168,7 +169,7 @@ void deserializeShouldBeAbleToRestoreFinalObjectAfterSerialization() {
168169
}
169170

170171
@Test // GH-2361
171-
void shouldDeserializeArrayWithoutTypeHint() {
172+
void shouldDeserializePrimitiveArrayWithoutTypeHint() {
172173

173174
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
174175
CountAndArray result = (CountAndArray) gs.deserialize(
@@ -179,6 +180,87 @@ void shouldDeserializeArrayWithoutTypeHint() {
179180
assertThat(result.getAvailable()).containsExactly(0, 1);
180181
}
181182

183+
@Test // GH-2361
184+
void shouldDeserializePrimitiveWrapperArrayWithoutTypeHint() {
185+
186+
GenericJackson2JsonRedisSerializer gs = new GenericJackson2JsonRedisSerializer();
187+
CountAndArray result = (CountAndArray) gs.deserialize(
188+
("{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$CountAndArray\", \"count\":1, \"arrayOfPrimitiveWrapper\":[0,1]}")
189+
.getBytes());
190+
191+
assertThat(result.getCount()).isEqualTo(1);
192+
assertThat(result.getArrayOfPrimitiveWrapper()).containsExactly(0L, 1L);
193+
}
194+
195+
@Test // GH-2361
196+
void doesNotIncludeTypingForPrimitiveArrayWrappers() {
197+
198+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
199+
200+
WithWrapperTypes source = new WithWrapperTypes();
201+
source.primitiveWrapper = new AtomicReference<>();
202+
source.primitiveArrayWrapper = new AtomicReference<>(new Integer[] { 200, 300 });
203+
source.simpleObjectWrapper = new AtomicReference<>();
204+
205+
byte[] serializedValue = serializer.serialize(source);
206+
207+
assertThat(new String(serializedValue)) //
208+
.contains("\"primitiveArrayWrapper\":[200,300]") //
209+
.doesNotContain("\"[Ljava.lang.Integer;\"");
210+
211+
assertThat(serializer.deserialize(serializedValue)) //
212+
.isInstanceOf(WithWrapperTypes.class) //
213+
.satisfies(it -> {
214+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
215+
assertThat(deserialized.primitiveArrayWrapper).hasValue(source.primitiveArrayWrapper.get());
216+
});
217+
}
218+
219+
@Test // GH-2361
220+
void doesNotIncludeTypingForPrimitiveWrappers() {
221+
222+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
223+
224+
WithWrapperTypes source = new WithWrapperTypes();
225+
source.primitiveWrapper = new AtomicReference<>(123L);
226+
227+
byte[] serializedValue = serializer.serialize(source);
228+
229+
assertThat(new String(serializedValue)) //
230+
.contains("\"primitiveWrapper\":123") //
231+
.doesNotContain("\"Ljava.lang.Long;\"");
232+
233+
assertThat(serializer.deserialize(serializedValue)) //
234+
.isInstanceOf(WithWrapperTypes.class) //
235+
.satisfies(it -> {
236+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
237+
assertThat(deserialized.primitiveWrapper).hasValue(source.primitiveWrapper.get());
238+
});
239+
}
240+
241+
@Test // GH-2361
242+
void includesTypingForWrappedObjectTypes() {
243+
244+
GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();
245+
246+
SimpleObject simpleObject = new SimpleObject(100L);
247+
WithWrapperTypes source = new WithWrapperTypes();
248+
source.simpleObjectWrapper = new AtomicReference<>(simpleObject);
249+
250+
byte[] serializedValue = serializer.serialize(source);
251+
252+
assertThat(new String(serializedValue)) //
253+
.contains(
254+
"\"simpleObjectWrapper\":{\"@class\":\"org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializerUnitTests$SimpleObject\",\"longValue\":100}");
255+
256+
assertThat(serializer.deserialize(serializedValue)) //
257+
.isInstanceOf(WithWrapperTypes.class) //
258+
.satisfies(it -> {
259+
WithWrapperTypes deserialized = (WithWrapperTypes) it;
260+
assertThat(deserialized.simpleObjectWrapper).hasValue(source.simpleObjectWrapper.get());
261+
});
262+
}
263+
182264
private static void serializeAndDeserializeNullValue(GenericJackson2JsonRedisSerializer serializer) {
183265

184266
NullValue nv = BeanUtils.instantiateClass(NullValue.class);
@@ -228,7 +310,6 @@ public boolean equals(Object obj) {
228310
return nullSafeEquals(this.stringValue, other.stringValue)
229311
&& nullSafeEquals(this.simpleObject, other.simpleObject);
230312
}
231-
232313
}
233314

234315
@Data
@@ -275,6 +356,14 @@ static class CountAndArray {
275356

276357
private int count;
277358
private int[] available;
359+
private Long[] arrayOfPrimitiveWrapper;
278360
}
279361

362+
@Data
363+
static class WithWrapperTypes {
364+
365+
AtomicReference<Long> primitiveWrapper;
366+
AtomicReference<Integer[]> primitiveArrayWrapper;
367+
AtomicReference<SimpleObject> simpleObjectWrapper;
368+
}
280369
}

0 commit comments

Comments
 (0)