反序列化后的JSON字段是如何一对一映射到Java对象中的字段的?
一、总览
JSON里的报文是怎么一对一赋值给OrderV1里面的属性的?
不会对应错或者对应不上吗?
这个过程是自动的吗?
后端工程师按照示例JSON报文和接口开发文档来定义了一个OrderV1,但是这里面的属性名肯定与JSON里面的字段名不完全一致,可能是相似的,然后反序列化以后就全都一对一对应的赋值上了?
package xxx; import xxx; /** * 订单接入服务接口 * @author xxx */ @Controller @RequestMapping("/api/orderComeInto") public class OrderComeIntoController{ private static final Logger logger = LoggerFactory.getLogger(OrderComeIntoController.class); private final static String APPLICATION_JSON_UTF8_VALUE = "application/json;charset=UTF-8"; @Autowired private orderService orderService; /** * 订单接入接口 * @param content * @return */ @RequestMapping(value = "/orderReceive", method = RequestMethod.POST, consumes = APPLICATION_JSON_UTF8_VALUE, produces = APPLICATION_JSON_UTF8_VALUE) @ResponseBody public Map<String, Object> orderService(@RequestBody String content){ logger.info(content); //1) 解析请求对象 List<OrderV1> orderV1List = JSON.parseObject(content, new TypeReference<List<OrderV1>>() {}); //2) 新增订单 Map<String, Object> result = new HashMap<>(); for(OrderV1 orderV1: orderV1List) { result = orderService.receiveOrderV1(orderV1); logger.info("订单处理结果:" + result); } return result; } }
package xxx; import xxx; @Data public class OrderV1 { private Set<String> iscpSector =new HashSet<>(Arrays.asList("0100","0251","0252","0241","0242","0211","0200")); // 添加一个新的字段来匹配JSON中的containerNeedList private List<RequestContainer> containerNeedList; // 订单头 private OrderHeader order; // 货信息列表 private List<GoodsV1> goodsList; // 预x箱列表 private ContainerV1 containerV1; // 服务内容 private List<Map<String, Object>> serviceList; public ExOrder getObject() { ... }
二、JSON解析与Java对象映射
在后端开发中,JSON解析和Java对象映射通常是通过一些库来实现的。常用的库有Fastjson、Jackson和Gson 等。
根据你提供的代码,这里使用的是Fastjson来进行JSON数据的反序列化(将JSON转换成Java对象)。
1. 反序列化过程(JSON -> Java 对象)
看这段代码:
List<OrderV1> orderV1List = JSON.parseObject(content, new TypeReference<List<OrderV1>>() {});
这是Fastjson的反序列化过程:
- content是请求的JSON字符串,它通常是前端传递过来的数据。
- JSON.parseObject(content, new TypeReference<List<OrderV1>>() {}) 会把这个JSON 字符串解析成一个List<OrderV1> 类型的对象。
Fastjson 会根据字段名的匹配将JSON 中的数据映射到Java对象的属性上。
2. 字段匹配与赋值
Fastjson是如何知道JSON中的字段与Java 对象的字段怎么对应的呢?主要有两个方式:
(1)字段名自动匹配:如果Java对象的属性名与JSON 中的字段名相同,Fastjson会直接把JSON中的字段值赋值给对应的Java 属性。
(2)通过注解指定映射:如果Java 对象的字段名和JSON 字段名不一致,可以使用Fastjson提供的注解来指定映射规则。
比如,假设你的OrderV1类中有以下字段:
@Data public class OrderV1 { private Set<String> sector; private List<RequestContainer> containerNeedList; private OrderHeader order; private List<GoodsV1> goodsList; private ContainerV1 containerV1; private List<Map<String, Object>> serviceList; }
JSON 传递的内容可能如下:
[ { "sector": ["0100", "0251"], "containerNeedList": [{...}], "order": {...}, "goodsList": [{...}], "containerV1": {...}, "serviceList": [{...}] } ]
3. 字段映射规则
假设这个JSON中的字段名与Java类中的属性名是一样的,Fastjson就会自动完成字段值的映射。例如:
- JSON中的sector对应Java类中的sector,Fastjson 会把JSON中的数组 ["0100", "0251"] 转换为 Set<String> 类型的集合,并赋值给OrderV1类中的sector 属性。
- 同样的,JSON中的containerNeedList会映射到OrderV1类中的containerNeedList属性,依此类推。
4. 自动化匹配的前提
自动匹配依赖于以下两个条件:
- 字段名相同:如果JSON中的字段名与Java对象的属性名一致,Fastjson会自动进行匹配。
- 类型匹配:JSON中字段的类型需要与Java对象属性的类型兼容,例如JSON中的array会映射为Java中的List或Set,JSON 中的string会映射为String。
5. 字段名不一致的处理
如果JSON中的字段名与Java类中的字段名不一致,Fastjson 提供了注解@JSONField来显式指定映射关系。比如:
@Data public class OrderV1 { @JSONField(name = "order_head") private OrderHeader order; }
如果JSON中的字段是order_head,Fastjson会将这个字段映射到OrderV1类中的order属性。
6. 复杂类型的映射
对于复杂类型(如嵌套的对象或集合),Fastjson会递归地处理嵌套的对象或集合。例如:
- JSON中的goodsList是一个数组,它对应OrderV1类中List<GoodsV1>,Fastjson会把JSON中的每个对象映射成GoodsV1 类的实例。
- 如果containerNeedList是一个包含多个RequestContainer对象的数组,Fastjson也会自动将每个数组元素映射为RequestContainer对象。
三、全文总重点的精华内容(可仅看此段)
Q1:条件一(字段名相同),条件二(类型匹配),只有同时满足这两个条件,才会自动化匹配映射赋值吗?
Answer:是的,必须同时满足这两个条件才可以。
条件一是需要被硬性满足的;而关于条件二,有时候比如带引号的字符串类型赋值给数值类型也是可以的,有一定的容错率。
但是要大概其过得去,比如JSON报文里的Arrays要匹配Java对象中的Set类型或者List类型。
Q2:若JSON报文字段名和Java对象字段名仅仅是相似(比如isxxOrderType和oxxOrderType这种相似),且也满足类型匹配,会自动化匹配映射赋值吗?
不可以,字段名必须完全相同才行。
Q3:建议全部写上@JSONField注解吗?
其实倒不完全必要。
但是对于有些情况:比如JSON报文里全是a_b_c这种格式的字段名,而java对象中全是abc这种字段名的情况,建议全部统一写上@JSONField注解。