1. 前言
- 在实际开发过程中,会经常接收Json字符串并转化为相应对象,而这个转化过程中若报错,无非提示,没有set方法,或者没有get方法,或者静态内部类没有默认构造函数,静态内部类没有带全部参数构造函数,无法转化多了某某field属性等等。
- 因此,在大多数开发的过程中,我们自然会在实体类对象上,一股脑加上 @Data,@NoArgsConstructor,@AllArgsConstructor,@JsonIgnoreProperties(ignoreUnknown = true),甚至让实体类变量与json内部key字段起名完全一样,这确实可以解决百分之九十的问题。
- 剩下百分之十的问题如下(例子):
见鬼了,属性名字完全一致,该有的东西都有了,为什么还是转化失败呢?这待我慢慢细说一下。
2. 先说结论
- 在ObjectMapper json转化对象过程中,可以单独使用set方法,或field属性(强调是public 属性),或get方法,进行变量属性赋值。
- 若都存在,优先级是:set方法 > field属性(强调是public 属性) > get方法
- 容易遗忘点:在使用set方法,get方法的时候,请让实体类的属性名 第二个字符不要大写,不要大写,不要大写,因为在使用上述方法的时候,例如属性名xAge,对应的标准set方法,则是setXAge(),而在使用set方法转化的时候,会先找到setXAge()方法,并把set去掉,将后面遇到大写字符变成小写,直到遇到小写字符才会停止,此时得到的是 xage,显然与 属性名xAge 不一样,因此无法正确转化赋值。
3. 证明结论
先准备如下例子:
开始跟踪源码(请忽略一些细节):
代码会收集可以被转化的属性,如下:
在_addGetterMethod()或者_addSetterMethod()方法中,都会去获取方法名,并截掉对应的get/set方法前缀,获取到对应的属性名。
收集器 收集好可以被转化的属性之后,就要生成对应的赋值的工具对象了
这样子解释吧,比如转化这里肯定是使用反射的方式,对于set方法,使用 invoke方法,而field属性,使用filed.set()方法。
这里则是对收集到的属性生成对应的赋值方法(姑且可以这样子认为), 从代码上看,可以看出有顺序之分,set方法,field,get,构造。
之后开始赋值了:
最后结果:
4. 使用@JsonAutoDetect定义字段、方法的访问可见性规则
-
上面证明结论的时候,属性字段设置public可以赋值成功,但实体类并不想直接让属性字段暴露出来,可是又想赋值,此时我们可以使用@JsonAutoDetect,改变属性的可见性,这里的修改可见性仅仅是让json转化的时候,认为是可见而已,相当于一个标记,实际上外部调用该类属性,还是没办法类.字段属性
public enum Visibility { ANY, // 所有的访问修饰符 NON_PRIVATE, // 除 private 之外的 PROTECTED_AND_PUBLIC, // 允许 protected、public PUBLIC_ONLY, // 只允许 public NONE, // 禁用 AutoDetect DEFAULT; }
证明:
-
实际上,上面的set方法/get方法赋值也是建立在public,若set方法,或者get方法不是public也无法赋值,证明:
通过@JsonAutoDetect 修改方法可见性
-
源码上 在addField()以及addMethod()方法的时候,也有判断 可见性,以field为例子: