Redis采用Jackson作为value的序列化器,但是对于复杂的泛型实体类如User,不能正常反序列化,而是会反序列化成LinkedHashMap类型

现象

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <version>3.4.0</version>
</dependency>

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.18.1</version>
</dependency>

Redis缓存数据,使用GenericJackson2JsonRedisSerializer作为value和hash value的序列化器

// 将用户信息存入redis
redisTemplate.opsForValue().set(RedisConstants.LOGIN_USER_ID + loginUser.getUser().getId(), loginUser);

// 从redis中获取用户信息
LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(RedisConstants.LOGIN_USER_ID + userId);

从redis中获取用户信息时,会报错:LinkedHashMap cannot convert to LoginUser


分析

Redis采用Jackson作为value的序列化器,但是对于复杂的泛型实体类如User,不能正常反序列化而是会反序列化成LinkedHashMap类型

好像是User的createTime和updateTime属性由Date类型改为LocalDateTime之后,出现的问题。


解决方式

让objectMapper启用默认类型信息,使得序列化时包含类型信息,反序列化时就能根据类型信息进行类型判断,正确反序列化。

objectMapper = new ObjectMapper();
...

// 类型验证器,在反序列化时验证类型信息的安全性
BasicPolymorphicTypeValidator typeValidator = BasicPolymorphicTypeValidator.builder()
    .allowIfBaseType(Object.class)
    .build();
// 启用默认类型信息,使得序列化时包含类型信息,反序列化时根据类型信息进行类型判断。否则,反序列化复杂的泛型实体类型时会报错。
objectMapper.activateDefaultTyping(typeValidator, ObjectMapper.DefaultTyping.NON_FINAL,
                                   JsonTypeInfo.As.PROPERTY);

...
GenericJackson2JsonRedisSerializer jackson2JsonRedisSerializer =
	new GenericJackson2JsonRedisSerializer(objectMapper);

参考

  1. Redis取值时取出的是HashMap - FigSprite - 博客园
  2. Jackson反序列时,将LinkedHashMap转成对象(Object类型转成实体)_jackson linkedhashmap-CSDN博客