当时用springSecurity+redis存储/读取用户信息的时候,发生报错。
报错异常
Class:class org.springframework.data.redis.serializer.SerializationException
LocalizedMessage:Could not read JSON: Problem deserializing 'setterless' property ("authorities"):
no way to handle typed deser with setterless yet at [Source: (byte[])"{"@class":"com.jia.pojo.User"
,"id":1,"username":"root",
"paassword":"{bcrypt}$2a$10$zI7PbpjGfcsxblk50lTlr.kLW65lAAoZU6Ic.a8b1.I6V4XXk/Je.",
"phone":"15061964947","enabled":true,"accountNonExpired":true,"accountNonLocked":true,
"credentialsNonExpired":true,"roles":["java.util.ArrayList",[]],"role":null,
"authorities":["java.util.HashSet",[]]}"; line: 1, column: 314] (through reference chain:
com.jia.pojo.User["authorities"]); nested exception is com.fasterxml.jackson.databind.exc.
InvalidDefinitionException: Problem deserializing 'setterless' property ("authorities"):
no way to handle typed deser with setterless yet at [Source: (byte[])"
{"@class":"com.jia.pojo.User","id":1,"username":"root","password":"{bcrypt}$2a$10$zI7PbpjGfcsxblk
50lTlr.kLW65lAAoZU6Ic.a8b1.I6V4XXk/Je.",
"phone":"15061964947","enabled":true,"accountNonExpired":true,"accountNonLocked":true,
"credentialsNonExpired":true,"roles":["java.util.ArrayList",[]],"role":null,
"authorities":["java.util.HashSet",[]]}"; line: 1, column: 314]
(through reference chain: com.jia.pojo.User["authorities"])
错误原因
这一段异常错误最主要的点在于这:
Problem deserializing 'setterless' property ("authorities"): no way to handle typed
deser with setterless yet at
大概意思就是反序列化属性(“authorities”)的问题:没有setterless 方法处理输入值。
说白了就是在我们设置redis时redisConfig我们采用的是jackson,而Jackson采用的反序列化时会调用属性的set方法注入值。
RedisConfig中自定义RedisTemplate代码:
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(factory);
//序列化配置
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//om.activateDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 过期方法,采用下面代替
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance , ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(om);
//String序列化
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
这里是配置写入读取redis值时采用jackson进行操作。
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
但我们自定义的user类缺只有重写的getAuthorities()方法。没有getAuthorities()方法,因此jackson反序列化的时候就会失败。
好了,知道了原因,解决方法就简单了。
解决方法(两个方法二选一即可)
1、在实体类中,手动添加authorities属性。添加setAuthorities()方法
@TableField(exist = false)
private Collection<? extends GrantedAuthority> authorities;
public void setAuthorities(Collection<? extends GrantedAuthority> authorities) {
this.authorities = authorities;
}
2、在实体类中,在getAuthorities()上添加@JsonIgnore,序列化时忽略此选项。
@Override
@JsonIgnore
public Collection<? extends GrantedAuthority> getAuthorities() {
Set<SimpleGrantedAuthority> authorities=new HashSet<>();
roles.forEach(role -> {
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(role.getName());
authorities.add(authority);
});
return authorities;
}
注意:如果你的前端需要authorities数据这个方法就不可以行。所以我还是建议第一种方法。可以在保证数据完整行的前提下完美解决问题。
搞定
要是解决了你的问题记得帮我点个赞哦!