Closed
Description
Describe the bug
Serialized result of java Class
& Record
is different with RedisTemplate
.
Version information
2.13.3
To Reproduce
====== RedisConfiguration ======
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
@ConditionalOnClass(RedisOperations.class)
public class RedisConfiguration {
@Bean
public RedisTemplate<String, ?> jacksonRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
final RedisSerializer<String> stringRedisSerializer = new StringRedisSerializer();
final RedisTemplate<String, ?> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
final GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer = genericJackson2JsonRedisSerializer();
template.setKeySerializer(stringRedisSerializer);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashKeySerializer(stringRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
@Bean
public GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer() {
final ObjectMapper mapper = new ObjectMapper()
.registerModule(new ParameterNamesModule(JsonCreator.Mode.DEFAULT))
.registerModule(new Jdk8Module())
.registerModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(),
DefaultTyping.NON_FINAL,
As.PROPERTY);
return new GenericJackson2JsonRedisSerializer(mapper);
}
}
====== RequestDto ======
@Data
@NoArgsConstructor
@AllArgsConstructor
public class RequestDto {
private Long id;
private String name;
private OffsetDateTime createdAt;
}
====== RequestRecord ======
public record RequestRecord(Long id,
String name,
OffsetDateTime createdAt) {
}
====== Test Code ======
@SpringBootTest
class RedisRecordTest {
@Autowired
private RedisTemplate<String, RequestRecord> redisRecordTemplate;
@Autowired
private RedisTemplate<String, RequestDto> redisDtoTemplate;
@Autowired
private RedisTemplate<String, String> redisStringTemplate;
@Autowired
private RedisTemplate<String, Object> redisObjectTemplate;
@Autowired
private ObjectMapper mapper;
@DisplayName("record -> String -> set() -> get() -> String -> record -> O")
@Test
void test() throws JsonProcessingException {
final RequestRecord record = new RequestRecord(1L, "doljae", OffsetDateTime.now());
final String serialized = mapper.writeValueAsString(record);
System.out.println(serialized);
redisStringTemplate.opsForValue().set("key", serialized);
final String fromRedis = redisStringTemplate.opsForValue().get("key");
System.out.println(fromRedis);
final RequestRecord deserialized = mapper.readValue(fromRedis, RequestRecord.class);
System.out.println(deserialized);
}
@DisplayName("Class -> set() -> get() -> Class -> O")
@Test
void test2() {
final RequestDto dto = new RequestDto(1L, "doljae", OffsetDateTime.now());
redisDtoTemplate.opsForValue().set("key", dto);
/*
redis-cli
get key
-> "{\"@class\":\"com.example.redis.RequestDto\",\"id\":1,\"name\":\"doljae\",\"createdA\":\"2022-06-08T21:39:01.166705+09:00\"}"
*/
final RequestDto fromRedis = redisDtoTemplate.opsForValue().get("key");
System.out.println(fromRedis);
}
@DisplayName("record -> set() -> get() -> record -> X")
@Test
void test3() {
final RequestRecord record = new RequestRecord(1L, "seokjae", OffsetDateTime.now());
redisRecordTemplate.opsForValue().set("key", record);
/*
redis-cli
get key
-> "{\"id\":1,\"name\":\"doljae\",\"createdAt\":\"2022-06-08T21:40:36.057138+09:00\"}"
*/
// Caused by: com.fasterxml.jackson.databind.exc.InvalidTypeIdException: Could not resolve subtype of [simple type, class java.lang.Object]: missing type id property '@class'
// at [Source: (byte[])"{"id":1,"name":"doljae","createdAt":"2022-06-08T21:40:36.057138+09:00"}"; line: 1, column: 72]
final RequestRecord deserialized = redisRecordTemplate.opsForValue().get("key");
}
}
Expected behavior
Both class and record objects should be stored and deserialized normally in RedisTemplate.
Additional context
-
The issue occurred while using
Spring Data Redis
class, but sinceObjectMapper
does serialization and deserialization, I reported it to Jackson issue borad. -
You can reproduce this issue with this repository's test class (use redis docker image in
repo/docker/docker-compose.yml
) -
I found that if i adjust ObjectMapper Configuration, both Class & Record serialize & deserialize normally.
mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(),
DefaultTyping.EVERYTHING,
As.PROPERTY);
- but this way exposes every meta data of object's fields...
Metadata
Metadata
Assignees
Labels
No labels