新项目,创建了一个统一响应的对象,有一个 isSuccess()
的方法判断是否成功,然后发现响应结果中多了个 success
属性。
然后在 Controller 层把要响应的数据直接 JSON 序列化输出,发出确实多了 success
属性,可以定位是 JSON 序列化出了问题。
统一响应对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Data public class ResponseModel<T> {
public static final int SUCCESS_CODE = HttpStatus.OK.value();
private int code = SUCCESS_CODE;
private String message = "success";
private T data;
public boolean isSuccess() { return this.code == SUCCESS_CODE; } }
|
原因分析
响应数据使用的是 FastJson 序列化,Debug 断点进入,看到多了个 success
属性,而 ResponseModel 没有这个属性,但有一个 isSuccess
方法,可以确定两者是有关系的。
查看 JavaBeans(TM) Specification对 Bean 的 setter/getter 方法的定义:
普通属性定义其 setter/getter 方法 如下:
1 2
| public <PropertyType> get<PropertyName>(); public void set<PropertyName>(<PropertyType> a);
|
但布尔类型则做了单独定义,如下:
1 2
| public boolean is<PropertyName>(); public void set<PropertyName>(boolean m);
|
布尔类型的属性使用 Intellij IDEA 自动生成 setter/getter
方法时,会遵循如下规律:
- 基本类型自动生成的 getter 和 setter 方法,名称都是
isXXX()
和setXXX()
形式的。
- 包装类型自动生成的 getter 和 setter 方法,名称都是
getXXX()
和setXXX()
形式的。
演示示例如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
| public class ResponseHelper { public static void main(String[] args) { Model0 model0 = new Model0(); Model1 model1 = new Model1(true); Model2 model2 = new Model2(true); Model21 model21 = new Model21(true); Model3 model3 = new Model3(true); Model31 model31 = new Model31(true); Model4 model4 = new Model4(true);
System.out.println("--------------FastJson序列化---------------------"); System.out.println("无success:" + JSON.toJSONString(model0)); System.out.println("基本类型success:" + JSON.toJSONString(model1)); System.out.println("基本类型isSuccess:" + JSON.toJSONString(model2)); System.out.println("手动isIsSuccess:" + JSON.toJSONString(model21)); System.out.println("包装类型isSuccess:" + JSON.toJSONString(model3)); System.out.println("手动getIsSuccess:" + JSON.toJSONString(model31)); System.out.println("普通succeed:" + JSON.toJSONString(model4));
System.out.println("----------------Gson序列化-----------------------"); Gson gson = new Gson(); System.out.println("无success:" + gson.toJson(model0)); System.out.println("基本类型success:" + gson.toJson(model1)); System.out.println("基本类型isSuccess:" + gson.toJson(model2)); System.out.println("手动isIsSuccess:" + gson.toJson(model21)); System.out.println("包装类型isSuccess:" + gson.toJson(model3)); System.out.println("手动getIsSuccess:" + gson.toJson(model31)); System.out.println("普通succeed:" + gson.toJson(model4));
} }
class Model0 { public static final int SUCCESS_CODE = HttpStatus.OK.value();
private int code = SUCCESS_CODE;
public boolean isSuccess() { return code == SUCCESS_CODE; } }
class Model1 { private boolean success;
public Model1(boolean success) { this.success = success; } public boolean isSuccess() { return success; }
public void setSuccess(boolean success) { this.success = success; } }
class Model2 { private boolean isSuccess;
public Model2(boolean isSuccess) { this.isSuccess = isSuccess; }
public boolean isSuccess() { return isSuccess; }
public void setSuccess(boolean success) { isSuccess = success; } }
class Model21 { private boolean isSuccess;
public Model21(boolean isSuccess) { this.isSuccess = isSuccess; }
public boolean isIsSuccess() { return isSuccess; }
public void setIsSuccess(boolean isSuccess) { this.isSuccess = isSuccess; } }
class Model3 { private Boolean isSuccess;
public Model3(Boolean isSuccess) { this.isSuccess = isSuccess; }
public Boolean getSuccess() { return isSuccess; }
public void setSuccess(Boolean success) { isSuccess = success; } }
class Model31 { private Boolean isSuccess;
public Model31(Boolean isSuccess) { this.isSuccess = isSuccess; } public Boolean getIsSuccess() { return isSuccess; }
public void setIsSuccess(Boolean isSuccess) { this.isSuccess = isSuccess; } }
class Model4 { private Boolean succeed;
public Model4(Boolean succeed) { this.succeed = succeed; }
public Boolean getSucceed() { return succeed; }
public void setSucceed(Boolean succeed) { this.succeed = succeed; } }
|
根本原因是 JSON 框架在序列化时对布尔类型的处理,FastJson 和 Jackson 框架序列化是通过反射遍历所有 getter
方法找到属性,就会把 isSuccess()
的方法序列成 success
属性,属性值为该方法的返回值。
此问题在 Gson 中则不存在,Gson 框架序列化是通过反射遍历类中的所有属性,只会序列化存在的属性,就不存在把 isSuccess()
的方法序列成 success 属性的问题。
在阿里巴巴Java开发手册中关于这一点,有过一个『强制性』规定:
问题解决
方式一:布尔类型变量,不加 is。——建议
方式二:不序列化 isSuccess() 方法,在该方法上添加 @JsonIgnore
注解忽略序列化。——不建议
方式三:手动设置布尔类型的 getter 方法,例如基础类型的 isIsSuccess()
,包装类型的 getIsSuccess()
。——不建议
相关参考
- 为什么强烈禁止开发人员使用isSuccess作为变量名