SLF4J: Failed toString() invocation on an object of type [java.util.HashMap] 的解决
- 问题背景:
对体类Bean进行
BeanUtils.describe(purchaseCatalogBo);
转换成Map,但是日志打印报错,并且从map里获取参数报错,报错明细如下:
SLF4J: Failed toString() invocation on an object of type [java.util.HashMap]
Reported exception:
java.lang.StackOverflowError
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:534)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:536)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractCollection.toString(AbstractCollection.java:462)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:536)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:536)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractCollection.toString(AbstractCollection.java:462)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
at java.util.AbstractMap.toString(AbstractMap.java:536)
at java.lang.String.valueOf(String.java:2994)
at java.lang.StringBuilder.append(StringBuilder.java:131)
并且更奇怪的是在本机验证是没有问题的,只有在线上环境才会出现,很是令人头疼,心想肯定是哪里的底层没有涉及到导致这个表面的错误浮现。
- 解决方案:
使用阿里巴巴的json转换。
将 Map reqMap = BeanUtils.describe(allChannelsCheckResReq); 改成
Map reqMap = JSON.parseObject(JSON.toJSONString(allChannelsCheckResReq), Map.class);
- 问题原因
经过网上查证,问题原因很可能是 实体类使用JPA方法来实现实体类之间的对应关系和BeanUtils.describe()方法的tostring方法都无休止地相互调用引起的。因为BeanUtils.describe()的原理是 BeanUtils调用 BeanUtilsBean的这个getNestedProperty方法,该方法在读取值之后,会再调用一次(getConvertUtils().convert(value));,进行类型转化成String。即转化出来的Map的value都是String。
- 总结:
BeanUtils虽然做了封装提高了开发效率,但是阿里巴巴的json感觉更优秀点。以后转换多多使用json - 拓展:
BeanUtils.describe与PropertyUtils.describe区别
BeanUtils.describe转换出来的值为string; PropertyUtils.describe 转换出来的值不做转换,但是两者都会将class也转换到Map里,如图所示
PurchaseCatalogBo purchaseCatalogBo=new PurchaseCatalogBo();
purchaseCatalogBo.setRsId("123");
purchaseCatalogBo.setPricePre(88);
purchaseCatalogBo.setUpdatime(new Date());
Map<String, String> describe = BeanUtils.describe(purchaseCatalogBo);
System.out.println(JSON.toJSONString(describe));
Map<String, Object> describe1 = PropertyUtils.describe(purchaseCatalogBo);
System.out.println(JSON.toJSONString(describe1));
Map map = JSON.parseObject(JSON.toJSONString(purchaseCatalogBo), Map.class);
System.out.println(JSON.toJSONString(map));
输出结果:
BeanUtils.describe{“pricePre”:“88”,“rsId”:“123”,“updatime”:“Mon Feb 03 20:19:18 CST 2020”,“class”:“class com.chinaunicom.cbss2.rc.external.bean.PurchaseCatalogBo”}
PropertyUtils.describe{“pricePre”:88,“rsId”:“123”,“updatime”:1580732358529,“class”:“com.chinaunicom.cbss2.rc.external.bean.PurchaseCatalogBo”}
Json
{“updatime”:1580732358529,“pricePre”:88,“rsId”:“123”}