SpringBoot+redis 使用jackson2JsonR
2019-04-19 本文已影响0人
烛火的咆哮
错误提示
org.springframework.data.redis.serializer.SerializationException: Could not read JSON: Cannot construct instance of `com.example.learn_1.entity.LearnUser` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"["com.example.learn_1.entity.LearnUser",{"userId":null,"userName":"唢呐","userAge":988,"remark":null}]"; line: 1, column: 42]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `com.example.learn_1.entity.LearnUser` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
代码
RedisConfig
@Bean("userRedistemplate")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// 将刚才的redis连接工厂设置到模板类中
template.setConnectionFactory(redisConnectionFactory);
// 设置key的序列化器
template.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化器
//使用Jackson 2,将对象序列化为JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json转对象类,不设置默认的会将json转成hashmap
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
return template;
}
entity
@Data
@Builder
@Accessors(chain = true)
public class LearnUser //extends BaseEntity
{
private static final long serialVersionUID = 1L;
@TableId(value = "user_id", type = IdType.AUTO)
private Integer userId;
private String userName;
private Integer userAge;
private String remark;
}
test
@Test
public void testRedisTemplate(){
// 以注解的形式把 bean 注入Spring 并获取 Spring 的上下文环境
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(RedisConfig.class);
// 获取自己配置的 bean 实例
RedisTemplate template = ctx.getBean(RedisTemplate.class);
LearnUser user = LearnUser.builder().userAge(988).userName("唢呐").build();
template.opsForValue().set("key1", user);
System.out.println(template.opsForValue().get("key1"));
}
解决
1. 在entity中添加注解@AllArgsConstructor(access = AccessLevel.PRIVATE)
2. 新建一个无参构造方法
LearnUser(){
}
- 根据错误提示
(no Creators, like default construct, exist)
分析得无法创建实例 - 报错行
System.out.println(template.opsForValue().get("key1"));
- 即在使用jackson2JsonRedisSerializer反序列化创建LearnUser对象时,发现LearnUser类中没有合适的构造方法,确定问题在LearnUser类中
- 贴上链接https://www.jianshu.com/p/0d8fc3df3647?from=timeline&isappinstalled=0
- 原因在于使用lombok插件,添加@Builder后,为LearnUser创建了一个全参的构造方法,而jackson2JsonRedisSerializer无法调用这个构造方法.
- 添加注解后,@Builder为我们创建的构造方法会被修饰为Private,防止了@Builder注解对其他类的影响
总结
- 关于@Builder为什么使用建造者模式,建议阅读Effective Java一书
- 只是一个小问题,虽然报错信息交杂,只要认真阅读,即可找到出路
- 学会利用idea的反编译工具
- 当没有定义构造方法时,java会自动创建一个无参的构造方法,当手动书写构造方法时,会使用手动书写的构造方法