疑难杂症整理汇总1

FastJson反序列化异常

问题

调试程序是发现报了一个null异常,定位代码行如下:

 BaseMessage message = JSON.parseObject(content, BaseMessage.class);

很明显,是FastJson组件,将json字符串反序列化成对象时出现了问题。

分析

实际传入的json字符串,并不是BaseMessage类的对象,而是它的一个子类,开始的时候怀疑是这个地方有问题,FastJson不能将一个子类的json字符串反序列化成父类。后来进一步想了下,这块应该没什么问题,要构建的父类对象,子类有所有的属性值,因此写了几个简单测试类用来验证,快速排查和定位问题。

@Data
public abstract class Person {
    protected String name;
}
@Data
public class Man extends Person {
    private String gender;
}

   @Test
    public void testFastJsonSuper()
    {

        Man man=new Man();
        man.setName("张三");
        man.setGender("男"); 
        String message = JSON.toJSONString(man); 
        Person person = JSON.parseObject(message, Person.class);
        log.info(JSON.toJSONString(person));

    }

测试结果,输出了期望的结果。

原因

于是对比,自己系统中有问题的类,与上面简单的类,差异在什么地方。
最终发现,BaseMessage,定义的是抽象类,而FastJson,反序列化时需要调用构造方法,明显是矛盾的。

以下是fastjson底层代码,当构造方法不存在时,会直接返回强制类型转换,这时候,转换结果就是一个null对象,并且没有抛出异常,这地方有点坑……

      Method buildMethod = beanInfo.buildMethod;
            if (buildMethod == null) {
                return (T) object;
            }
            

像这种情况,fastjson是否抛出个异常提示是不是更友好一些?

windows运行SpringBoot jar包控制台显示中文乱码

原因

中文乱码一般是因为字符编码方式与字符解码方式不一致导致的,如果出现乱码,首先我们应该检查项目的编码是否与cmd控制台的编码方式是否一致。如果不一致,修改编码使其一致。

window系统命令行cmd控制台默认编码为GBK,而SpringBoot项目设置为utf-8,则直接运行 java -jar platform-core-1.0.0.jar,中文会出现乱码。

网上的文章,如下并无法解决
java -Dfile.encoding=UTF-8 -jar platform-core-1.0.0.jar

解决方式

在cmd窗口输入chcp命令,可查看当前字符编码,默认情况下为936,即GBK

输入如下命令chcp 65001,可临时更改编码方式为UTF-8,注意是临时更改,关闭窗口后再打开,依旧是GBK编码方式。

建议通过批处理来解决,即新建文本文件,将后缀名txt更改为bat,内容如下:
chcp 65001
java -jar platform-core-1.0.0.jar

这种情况下,无需附加启动参数 -Dfile.encoding=UTF-8。

lombok隐含的坑点——对布尔数据类型的属性读取方法的特殊处理

问题

lombok是一个几乎必备的辅助插件,通过使用它的注解,可以在编译阶段自动生成我们需要的代码,如最常用的属性的getter和setter方法。

这里有个特殊的点需要注意下,对于布尔数据类型的属性,插件有其自身的特殊处理方式,而不是跟其他基本数据类型一样生成getXXX和setXXX方法。

例如下面这个全局配置类中,我们定义了一个控制消息是否重发的布尔类型属性enableResend

/**
 * 全局容器,存放通道及配置参数
 * 使用spring单例模式
 * @author  wqliu
 * @date  2021-10-5
*/
@Data
@ConfigurationProperties(prefix = "params")
public class MessageClientGlobalHolder
{

	……

	/**
	 * 是否启用消息重发
	 */
	private  boolean enableResend;

	
    ……


}

当我们要读取其属性时,会发现,相应的对象上,并没有getEnableResend()这个方法,反而是isEnableResend()的方法,为什么会这样呢?

原因

原来是lombok插件内部针对布尔类型做了一些额外的逻辑处理,具体规则为:

1.读取属性的方法默认生成规则是is+属性名而不是get+属性名,即isEnableResend而不是getEnableResend
2.假如属性名自身以is开头,如isEnableResend,则获取属性的方法依旧是isEnableResend,而不是别扭的isIsEnableResend
3.以上两条规则,会出现一种因为不合理导致的极端情况,即有两个属性,一个名字是isEnableResend,另一个是enableResend,这里本质上是设计存在问题,对于这种情况,插件的处理方式是只生成一个isEnableResend,至于读取的是哪个属性,取决于属性的顺序,居前者优先。

注意事项

需要注意的问题还有几个:
1.以上的处理规则,实际都是指使用基本布尔类型boolean,而不是包装类型Boolean,对于包装类型,lombok插件依旧是get+属性名的规则,不做额外处理。
2.对于写入属性的方法,依旧是set+属性名,没有额外处理。

这个地方的特殊性,表面看起来很简单,只是一个小坑而已,即使开发时遇到了,只是错愕一下,翻翻方法列表,就能找到对应的方法,或者进一步百度下,就能找到为什么方法名不是预期的getXXX。

但是,这里面有一个更大的隐含的坑,就是lombok进一步和其他组件组合使用,则有可能会发生问题,例如对象创建、反序列化,对象属性的拷贝,如果这些功能组件底层是使用反射去寻找对应的get属性,则很可能会找不到合适的方法,导致属性丢失或异常,特别是将一个布尔类型true值变成了false,需要特别注意。

  • 0
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

学海无涯,行者无疆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值