文章目录
1. 先说结论
-
@ConstructorProperties注解并不是json里面的,而是jdk自身携带的类。
-
当一个类有多个构造函数,在进行json转化成对象的时候,需要指定其使用那个构造函数时,可以使用@ConstructorProperties注解,告诉json转化过程中,使用哪个构造函数进行反序列化为对象。
-
默认不加任何其他条件情况下,json使用构造函数反序列化为对象时:
- 若有无参构造函数,以及有参构造函数时,优先会选择无参构造函数反序列化。
- 若有多个有参构造函数的情况下,但没有无参构造函数,优先会选择最多参数的有参构造函数反序列化。
- 上述两种情况,若新增条件@ConstructorProperties注解的话,优先选择被该注解的构造函数反序列化。
-
@ConstructorProperties一个注解 可以替代 json注解中的@JsonCreator与@JsonProperty同时使用的情况。
-
在springboot中使用@ConstructorProperties注解,其注解本身参数的功能完全失效,该注解的作用只剩:告诉ObjectMapper使用那个构造函数进行反序列化,原因尚未查明。
2. 快速入门使用
1. @JsonCreator与@JsonProperty的使用
-
@JsonCreator 指定使用那个构造函数进行反序列化。
-
@JsonProperty 指定json对象字段名字,与具体属性名字的对应关系。
-
代码如下:
@ToString public class AA { private String name; private String password; public AA(String name){ System.out.println("使用只有一个参数的构造函数"); this.name = name; } // 指定使用该构造函数进行反序列化 // @JsonProperty("pwd") 指名,属性password 与json的pwd字段对应 @JsonCreator public AA(@JsonProperty("name") String name, @JsonProperty("pwd") String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } }
public class demo { public static void main(String[] args) throws Exception{ String jsonStr = "{\n" + " \"name\":\"1\",\n" + " \"pwd\":\"123\"\n" + "}"; ObjectMapper objectMapper = new ObjectMapper(); final AA aa = objectMapper.readValue(jsonStr, AA.class); System.out.println(aa); } }
2. @ConstructorProperties使用
-
@ConstructorProperties 完全可以替代 @JsonCreator与@JsonProperty。
-
注解参数是指定json字段,与 构造函数 参数的对应,绑定关系。
-
代码如下:
@ToString public class AA { private String name; private String password; public AA(String name){ System.out.println("使用只有一个参数的构造函数"); this.name = name; } // 该注解参数是指定json字段,与 构造函数 参数的对应 // 将属性password 与json的pwd字段对应 // 将属性namee 与json的name字段对应 @ConstructorProperties({"name", "pwd"}) public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } }
public class demo { public static void main(String[] args) throws Exception{ String jsonStr = "{\n" + " \"name\":\"1\",\n" + " \"pwd\":\"123\"\n" + "}"; ObjectMapper objectMapper = new ObjectMapper(); final AA aa = objectMapper.readValue(jsonStr, AA.class); System.out.println(aa); } }
-
该@ConstructorProperties注解参数是指定json字段,与 构造函数 参数的对应
将代码改成@ConstructorProperties({“pwd”, “name”})@ToString public class AA { private String name; private String password; public AA(String name) { System.out.println("使用只有一个参数的构造函数"); this.name = name; } // 故意将 对应关系写反 // 因此这里的绑定关系是: // json的pwd 对应 name // json的name 对应 password @ConstructorProperties({"pwd", "name"}) public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } } public class demo { public static void main(String[] args) throws Exception{ String jsonStr = "{\n" + " \"pwd\":\"123\",\n" + " \"name\":\"1\"\n" + "}"; ObjectMapper objectMapper = new ObjectMapper(); final AA aa = objectMapper.readValue(jsonStr, AA.class); System.out.println(aa); } }
由上图可知,原本name=1,现在则是name=123
3. 验证结论
1. 前言准备
-
下面的ObjectMapper,都是基于ObjectMapper,毕竟其是springboot默认使用的json转化工具。
-
准备一个实体类,一个controller层:
@ToString public class AA { private String name; private String password; public AA(String name){ System.out.println("使用只有一个参数的构造函数"); this.name = name; } public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } public AA(){ System.out.println("使用无参构造函数"); } } @RestController public class ConstructorTestController { @PostMapping("/test/A") public void testA(@RequestBody AA a){ System.out.println(a); } }
-
在AA实体类上,只加@ToString方法,为了方便查看其属性的赋值,这里并不能增加@Getter或者@Setter注解,因为json在转化也可以基于这两个方法进行,具体可以查阅:(ObjectMapper)Json转化对象的基本原理
-
基于上述第三点,做个小科普,json的转化使用方式的优先级是:set方法、public的field属性、get方法、构造函数。
2. 验证无参构造与有参构造同时存在情况
-
无参构造与有参构造同时存在,优先级是无参构造函数:
-
若此时使用 @ConstructorProperties({“name”, “password”}),优先级则是被注解指定的构造函数
@ToString public class AA { private String name; private String password; public AA(String name) { System.out.println("使用只有一个参数的构造函数"); this.name = name; } @ConstructorProperties({"name", "password"}) public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } public AA() { System.out.println("使用无参构造函数"); } }
3. 验证只有 有参构造函数情况
-
当只有有参构造函数,无加其他任何注解,优先级则是参数最多的构造函数进行反序列化。
-
代码如下:
@ToString public class AA { private String name; private String password; public AA(String name) { System.out.println("使用只有一个参数的构造函数"); this.name = name; } public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } }
有的人可能会说,因为刚刚好json有两个字段,所有才使用了全参的构造函数,现我们改成只有name字段的json请求:
由上可知,优先级:则是最多参数的构造函数 -
当我们使用@ConstructorProperties注解,注解参数写上 name,password
-
或者注解参数只写上name
4. 在springboot中使用@ConstructorProperties注解时,参数功能完全失效
-
在快速入门中,我们提及到@ConstructorProperties注解的参数,是将json字段与自身构造函数的参数进行对应
-
但经测试,在springboot中,似乎并不是这样子,代码如下:
对应关系为:json的字段pwd 对应 属性name,json的字段name对应属性password@ToString public class AA { private String name; private String password; public AA(String name) { System.out.println("使用只有一个参数的构造函数"); this.name = name; } @ConstructorProperties({"pwd", "name"}) public AA(String name, String password) { System.out.println("使用了全参构造函数哦"); this.name = name; this.password = password; } }