【运行报错】使用BeanUtil做beanToMap时,转换字段(可能为null)的属性为String类型
1. 报错信息:使用Redis代替session做缓存时,需要将redis中未命中的数据,从数据库查出再存入redis缓存首先得将对象转为hashmap(这里使用得是hutool的BeanUtil)且使用StringRedisTemplateredis需要转换成的map的各个字段都是String类型!而bean的各个字段类型各不相同如何在不遍历map(繁琐)的情况下,在转换为map时就直接将字段类
·
1. 报错信息:
- 使用Redis代替session做缓存时,需要将redis中未命中的数据,从数据库查出再存入redis缓存
- 首先得将对象转为hashmap(这里使用得是hutool的BeanUtil)
- 且使用
StringRedisTemplateredis
需要转换成的map的各个字段都是String类型!而bean的各个字段类型各不相同 - 如何在不遍历map(繁琐)的情况下,在转换为map时就直接将字段类型也转换为String?
Map<String, Object> map = BeanUtil.beanToMap(shop,new HashMap<>(), CopyOptions.create(). setIgnoreNullValue(true) .setFieldValueEditor((fieldName,fieldValue) -> fieldValue.toString())); stringRedisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id,map);
hutool的BeanUtil提供了CopyOptions可以在转换时,做自定义规则
https://apidoc.gitee.com/dromara/hutool/ - 但是执行报错:
java.lang.NullPointerException: null at com.hmdp.service.impl.ShopServiceImpl.lambda$queryById$0(ShopServiceImpl.java:81) ~[classes/:na] at cn.hutool.core.bean.copier.CopyOptions.editFieldValue(CopyOptions.java:258) ~[hutool-all-5.7.17.jar:na] at cn.hutool.core.bean.copier.BeanCopier.lambda$beanToMap$1(BeanCopier.java:233) ~[hutool-all-5.7.17.jar:na] at java.util.LinkedHashMap$LinkedValues.forEach(LinkedHashMap.java:608) ~[na:1.8.0_181] at cn.hutool.core.bean.BeanUtil.descForEach(BeanUtil.java:182) ~[hutool-all-5.7.17.jar:na] at cn.hutool.core.bean.copier.BeanCopier.beanToMap(BeanCopier.java:195) ~[hutool-all-5.7.17.jar:na] at cn.hutool.core.bean.copier.BeanCopier.copy(BeanCopier.java:106) ~[hutool-all-5.7.17.jar:na] at cn.hutool.core.bean.BeanUtil.beanToMap(BeanUtil.java:690) ~[hutool-all-5.7.17.jar:na]
- 空指针异常!
2. 原因分析:
- 发现需要转成map得bean中有字段是null
- 而null不能toString()
- 故将代码修改为:
Map<String, Object> map = BeanUtil.beanToMap(shop,new HashMap<>(), CopyOptions.create(). setIgnoreNullValue(true) .setFieldValueEditor((fieldName,fieldValue) -> fieldValue + "")); stringRedisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id,map);
- 但还是存在问题:
- 现在空值是以字符串 “null” 存在redis中的
- 当再次点击此商铺,此时缓存命中,故将redis中的hash类型数据转为 shop 对象时,“null” 又无法将string类型的value解析成一个数字类型
- 此时注意到,我代码中明明将 空值忽略掉了
setIgnoreNullValue(true)
- 但debug却发现
setIgnoreNullValue(true)
并没有 生效
3. 解决方法:
- 在gitee 上问了作者才知道:https://gitee.com/dromara/hutool/issues/I557F3
- setFieldValueEditor优先级要高于ignoreNullValue导致前者首先被触发,因此出现空指针问题。你在setFieldValueEditor中也需要判空
- 这么设计的原因主要是,如果原值确实是null,但是你想给一个默认值,在此前过滤掉就不合理了,而你的值编辑后转换为null,后置的判断就会过滤掉
- 修改代码:
Map<String, Object> map = BeanUtil.beanToMap(shop,new HashMap<>(), CopyOptions.create(). setIgnoreNullValue(true) //.setFieldValueEditor((fieldName,fieldValue) -> fieldValue.toString())); //解决方法:⭐在setFieldValueEditor中也需要判空 .setFieldValueEditor((fieldName,fieldValue) -> { if (fieldValue == null){ fieldValue = "0"; }else { fieldValue = fieldValue + ""; } return fieldValue; })); stringRedisTemplate.opsForHash().putAll(RedisConstants.CACHE_SHOP_KEY + id,map); return Result.ok(shop);
- 问题解决!
更多推荐
已为社区贡献2条内容
所有评论(0)