成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一個Getter引發的血案

開發 前端
許多bug都是在自以為沒有問題的地方產生,看似簡單,更需要小心,同時也需要多注意序列化原理,整體感覺序列化還是用Gson更省心,完全不用關心Getter和Setter方法,會完全按照屬性名來序列化。

[[413398]]

本文轉載自微信公眾號「你呀不牛」,作者不牛。轉載本文請聯系你呀不牛公眾號。

1需求

最近做一了個需求,調用其他服務的REST接口,感覺很簡單,于是迅速就搞起來了

構造Request類

  1. public class User { 
  2.     private String name
  3.     private Integer age; 
  4.  
  5.     public User(String nameInteger age) { 
  6.         this.name = name
  7.         this.age = age; 
  8.     } 

啪,我上來就一new

  1. service.sendRequest(new User("niu", 18)); 

打完,收工,又是努力工作(摸魚)的一天。

2定位

但是,某天晚上8點,測試人員突然給我打電話,說調用失敗,同時本身又缺少打印,沒有辦法具體哪出問題了。

我是不會認為這么簡單的代碼自己會出錯的,不可能!!

經過網絡抓包后發現,收到的參數都是null,但是我這邊明明調用構造器傳入參數了

難道出現靈異事件了?

經過分析,整體數據流為:

能出現問題的地方只能是序列化JSON地方,于是本地測試驗證了這一結論:

  1. public static void main(String[] args) throws IOException { 
  2.     ObjectMapper objectMapper = new ObjectMapper(); 
  3.     String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  4.     System.out.println(request); 

雖然是出問題了,但是序列化并沒有轉為屬性為null的對象,而是直接拋出異常

  1. Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class online.jvm.bean.User and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) 
  2.  at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77) 

通過查詢異常資料,解決掉這種異常需要在增加Jackson的序列化配置FAIL_ON_EMPTY_BEANS,FAIL_ON_EMPTY_BEANS這個配置表示如果某個bean序列化為空時不會異常失敗

  1. public static void main(String[] args) throws IOException { 
  2.     ObjectMapper objectMapper = new ObjectMapper(); 
  3.     objectMapper.configure(FAIL_ON_EMPTY_BEANS, false); 
  4.     String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  5.     System.out.println(request); 

這種就不會報錯,而是返回序列化成空串,也就導致接受方為屬性都為null

通過看自研RPC框架看到是有該FAIL_ON_EMPTY_BEANS的配置

3解決

再來分析一下原因,Jackson序列化時需要調用bean的getter方法

1、寫上getter后再看下結果:

  1. public class User { 
  2.     private String name
  3.     private Integer age; 
  4.  
  5.     public User(String nameInteger age) { 
  6.         this.name = name
  7.         this.age = age; 
  8.     } 
  9.  
  10.     public String getName() { 
  11.         return name
  12.     } 
  13.  
  14.     public Integer getAge() { 
  15.         return age; 
  16.     } 
  17.  
  18.     public static void main(String[] args) throws IOException { 
  19.         ObjectMapper objectMapper = new ObjectMapper(); 
  20.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  21.         System.out.println(request); 
  22.         // 輸出正常 : {"name":"niu","age":18} 
  23.     } 

2、或者把屬性訪問權限改為public

  1. public class User { 
  2.     public String name
  3.     public Integer age; 
  4.  
  5.     public User(String nameInteger age) { 
  6.         this.name = name
  7.         this.age = age; 
  8.     } 
  9.  
  10.     public static void main(String[] args) throws IOException { 
  11.         ObjectMapper objectMapper = new ObjectMapper(); 
  12.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  13.         System.out.println(request); 
  14.         // 輸出正常 : {"name":"niu","age":18} 
  15.     } 

但是如果要求不能暴露bean的屬性即使是getter也不行呢?

3、注解 @JsonProperty

這是就需要使用Jackson提供的注解 @JsonProperty

  1. public class User { 
  2.     @JsonProperty("userName"
  3.     private String name
  4.     @JsonProperty 
  5.     private Integer age; 
  6.  
  7.     public User(String nameInteger age) { 
  8.         this.name = name
  9.         this.age = age; 
  10.     } 
  11.  
  12.     public static void main(String[] args) throws IOException { 
  13.         ObjectMapper objectMapper = new ObjectMapper(); 
  14.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  15.         System.out.println(request); 
  16.         //   {"userName":"niu","age":18} 
  17.     } 

來看下注解@JsonProperty的源碼注釋

  1. Marker annotation that can be used to define a non-static method as a "setter" or "getter" for a logical property (depending on its signature), or non-static object field to be used (serialized, deserialized) as a logical property. 

大體意思是注解如果用在屬性上相當于為該屬性定義getter和setter。

那如果既有getter又有@JsonProperty注解,以哪個為準呢?

  1. public class User { 
  2.     @JsonProperty("userName"
  3.     private String name
  4.     @JsonProperty 
  5.     private Integer age; 
  6.  
  7.     public User(String nameInteger age) { 
  8.         this.name = name
  9.         this.age = age; 
  10.     } 
  11.  
  12.     public String getName() { 
  13.         return name
  14.     } 
  15.  
  16.     public static void main(String[] args) throws IOException { 
  17.         ObjectMapper objectMapper = new ObjectMapper(); 
  18.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  19.         System.out.println(request); 
  20.         // {"age":18,"userName":"niu"
  21.     } 

如果getter一個沒有的屬性,效果如何呢?

  1. public class User { 
  2.     @JsonProperty("userName"
  3.     private String name
  4.     @JsonProperty 
  5.     private Integer age; 
  6.  
  7.     public User(String nameInteger age) { 
  8.         this.name = name
  9.         this.age = age; 
  10.     } 
  11.  
  12.     public String getName2() { 
  13.         return name
  14.     } 
  15.  
  16.     public static void main(String[] args) throws IOException { 
  17.         ObjectMapper objectMapper = new ObjectMapper(); 
  18.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  19.         System.out.println(request); 
  20.         // {"age":18,"name2":"niu","userName":"niu"
  21.     } 

這說明如果有@JsonProperty注解,先以注解為準

然后利用反射找到對象類的所有get方法,接下來去get,然后小寫化,作為json的每個key值,而get方法的返回值作為value。接下來再反射field,添加到json中。

4、特殊情況

還有一種比較特殊的情況, getter方法由lombok生成,且屬性的次首字母是大寫:

  1. @Getter 
  2. public class User { 
  3.     @JsonProperty 
  4.     private String nAme
  5.     @JsonProperty 
  6.     private Integer age; 
  7.  
  8.     public User(String nameInteger age) { 
  9.         this.nAme = name
  10.         this.age = age; 
  11.     } 
  12.  
  13.     public static void main(String[] args) throws IOException { 
  14.         ObjectMapper objectMapper = new ObjectMapper(); 
  15.         String request = objectMapper.writeValueAsString(new User("niu", 18)); 
  16.         System.out.println(request); 
  17.         // {"nAme":"niu","age":18,"name":"niu"
  18.     } 

這是因為lombok生成的getter會把屬性的第一個字母變成大寫,

序列化時會把get后與小寫字母中間的大寫變成小寫,也就是會把NA變成小寫

所以序列化結果會有name(getter獲取)和nAme(注解獲取)兩個屬性

  1. public String getNAme() { 
  2.     return this.nAme

如果我們自己用idea快捷鍵生成getter,

此時之后序列化nAme

  1. public String getnAme() { 
  2.     return nAme

4小結

許多bug都是在自以為沒有問題的地方產生,看似簡單,更需要小心,同時也需要多注意序列化原理,整體感覺序列化還是用Gson更省心,完全不用關心Getter和Setter方法,會完全按照屬性名來序列化。

 

本文的涉及的bug過程和解決方式希望對你也有所幫助,再見。

 

責任編輯:武曉燕 來源: 你呀不牛
相關推薦

2021-12-01 06:59:27

架構

2018-11-22 15:50:27

MySQL數據庫雙引號

2021-01-25 08:08:22

APP機器人KOB

2017-05-22 08:35:07

MySQL雙引號錯位

2021-02-01 10:42:47

MySQL雙引號數據庫

2017-08-25 16:38:05

表達式正則血案

2010-08-09 09:46:40

2017-03-20 19:40:29

AndroidSwipeRefres下拉刷新

2021-01-11 05:30:04

Boot 單機片

2012-02-13 09:42:41

備份服務器數據中心

2015-02-04 14:36:07

格式串漏洞Ghost漏洞安全漏洞

2011-02-28 09:31:30

HashtableHashMap

2019-09-09 08:30:57

MYSQL代碼數據庫

2011-11-25 13:04:43

空格usr

2020-01-06 09:43:14

賠償TSB遷移

2023-01-11 08:41:47

微服務循環依賴

2013-12-05 10:50:13

2017-06-12 16:13:13

曼聯皇馬傳真機

2016-12-01 09:30:03

運維網絡網線

2022-04-12 08:43:04

生產故障Dubbo調用
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 91在线免费视频 | 免费久久久久久 | 日韩欧美在线一区 | 91在线精品秘密一区二区 | 中文字幕在线观看一区二区 | 中文字幕亚洲一区二区va在线 | 国产精品av久久久久久久久久 | 国产精品美女久久久久aⅴ国产馆 | 久久y| 中文字幕 国产 | 日韩免费高清视频 | 欧美一区二区二区 | 99这里只有精品视频 | 久久久久无码国产精品一区 | 视频1区 | 久久久久久99 | 亚洲女优在线播放 | 黄色国产视频 | 欧美不卡一区二区三区 | 精品久久久久香蕉网 | 国产精品中文字幕一区二区三区 | 综合精品 | 免费一区二区三区 | 成人在线电影网站 | 久久国 | 99久久精品国产一区二区三区 | 男女视频在线观看 | 精品一区欧美 | 国产专区在线 | 欧美视频在线看 | 91看国产 | 亚洲精品99| 日韩欧美综合 | 国产在线精品一区二区三区 | 欧美1区2区| 成人国产在线视频 | 中文字幕在线不卡 | 日韩中文视频 | www.日本精品 | 亚洲精品一区国产精品 | 天天干天天玩天天操 |