is开头boolean属性序列化问题

JavaBean类的属性的类型是boolean类型,那么该属性的读方法的格式可以是isXxx()或者getXxx(),例如,名为state的boolean类型的属性,它的读方法可以是isState()或者是getState()。

【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则部分框架解析会引起序列
化错误。
反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。

一、布尔类型IDE自动生成的Get方法

  1. is开头boolean
public class testBoolean {
	private boolean isTestBoolean;
	
	public boolean isTestBoolean() {
		return isTestBoolean;
	}
}
  1. 非is开头boolean
public class testBoolean {
	private boolean testBoolean;
	
	public boolean isTestBoolean() {
		return testBoolean;
	}
}

基础数据类型boolean属性不管属性名是否是is开头IDE自动生成的getter方式都是isXxx()。

二、Gson、Jackson和FastJson序列化的区别

测试类

static class TestJsonBoolean {

        private boolean isBooTest;

        // IDE自动生成的getter方法
        public boolean isBooTest() {
            return isBooTest;
        }

        public void setBooTest(boolean booTest) {
            isBooTest = booTest;
        }

        // 类中不存在的属性
        public String getTestAtt() {
            return "testatt";
        }
    }

分别使用Gson、Jackson和FastJson对类进行初始化。

public static void main(String[] args) throws JsonProcessingException {
        TestJsonBoolean test = new TestJsonBoolean();
        test.setBooTest(true);

        String gJson = new Gson().toJson(test);// Gson序列化
        String jJson = new ObjectMapper().writeValueAsString(test); // Jackson序列化
        String fJson = JSON.toJSONString(test);// FastJson序列化

        System.out.println("GsonToJson:" + gJson);
        System.out.println("JacksonToJson:" + jJson);
        System.out.println("FastJsonToJson:" + fJson);
    }

输出结果

GsonToJson:{"isBooTest":true}
JacksonToJson:{"booTest":true,"testAtt":"testatt"}
FastJsonToJson:{"booTest":true,"testAtt":"testatt"}

可见这三种序列化工具的序列化方式还是有所差异,Gson是根据类中属性进行序列化,所以结果没什么问题。而Jackson和FastJson的序列化方式是先找到getter方法,再根据JavaBean规范生成对应的属性名,所以不仅isBooTest属性被序列化成booTesttestAtt这个类中根本不存在的属性也在序列化的结果中。

三、产生的问题

测试类

static class TestJsonBoolean {

        private boolean isBooTest;

        // IDE自动生成的getter方法
        public boolean isBooTest() {
            return isBooTest;
        }

        public void setBooTest(boolean booTest) {
            isBooTest = booTest;
        }

        @Override
        public String toString() {
            return "TestJsonBoolean{" +
                    "isBooTest=" + isBooTest +
                    '}';
        }
    }

使用Gson反序列化Jackson或FastJson序列化结果

public static void main(String[] args) throws JsonProcessingException {
        TestJsonBoolean test = new TestJsonBoolean();
        test.setBooTest(true);

        // 使用Jackson序列化
        String jJson = new ObjectMapper().writeValueAsString(test);
        System.out.println("JacksonToJson:" + jJson);
        // 使用Gson反序列化Jackson序列化结果
        System.out.println("JsonToObj:" + new Gson().fromJson(jJson, TestJsonBoolean.class));

    }

输出结果

JacksonToJson:{"booTest":true}
JsonToObj:TestJsonBoolean{isBooTest=false}

在使用Gson对Jackson或FastJson的序列化结果进行反序列化时,由于序列化结果中将isBooTest属性序列化为booTest,Gson对其反序列化时没有找到该属性且基础数据类型给了默认值false,出现了序列化前后结果不一致。

四、总结

不要在类中为boolean类型属性命名以is开头,这点在阿里的开发手册也有明确说明。

上一篇:Java秘技之Json数据解析与转换 -- Java使用示例


下一篇:Gson解析封装