一、問題描述
最近在和前端對接接口的時候,發(fā)現(xiàn)后端接口返回給前端的一個字段大小寫有問題,具體如下。
使用的開發(fā)框架及版本:
框架:SpringMVC;
Lombok版本:1.18.12;
對象簡化后如下:
@Data
public class MobileInfo {
private String iPhone;
}
預(yù)期返回結(jié)果:iPhone,實際返回結(jié)果:iphone。
也就是說SpringMVC環(huán)境下,使用Lombok注解
@Data之后,返回給前端的是iphone,而不是我們預(yù)期中的iPhone。
二、原因
針對首字母小寫,第二個字母大寫的這種駝峰命名時,使用@Data注解生成的getter和setter方法分別是:
public String getIPhone() {
return iPhone;
}
public void setIPhone(String iPhone) {
this.iPhone = iPhone;
}
而正常場景下及Spring中對象的getter和setter方法應(yīng)該是:
public String getiPhone() {
return iPhone;
}
public void setiPhone(String iPhone) {
this.iPhone = iPhone;
}
也就是說Lombok與Spring針對這種首字母小寫,第二個字母大寫的對象的解析是不同的,而這也就自然而然影響到默認的Jackson的解析,導(dǎo)致返回給前端的屬性名稱不是我們預(yù)期中的名稱。
2.1 Lombok問題
其實,針對這個問題,多年前就有人已經(jīng)在lombok的github提出過對應(yīng)的issue,參考:
其實,無論是Lombok還是Spring,在處理對象的時候總會有一個API規(guī)范進行參考的,這個規(guī)范一般就是JavaBeans API的規(guī)范。而針對這個問題,Lombok的官方回復(fù)是:
JavaBeans的規(guī)范就是這樣的,Lombok只是遵循這個規(guī)范而已,并且不應(yīng)該使用首字母小寫,第二個字母大寫這樣的命名規(guī)則,而Spring的處理方式才是沒有遵循JavaBean的規(guī)范。除非Oracle官方推薦如此或者大家都是這樣處理的化,Lombok才會進行修改。
也就是說,Lombok認為,JavaBeans的規(guī)范就是這么定義的,而針對JavaBean的規(guī)范,Spring和Lombok選擇了不同的實現(xiàn)方式:
- Spring,Jackson針對get/set的生成方式,和我們使用 IDEA 編譯器自動生成get/set的方式是相同的,都是諸如
getiPhone()的形式。- Lombok,針對get/set的生成方式,是
getIPhone()的形式。
那么,針對JavaBeans規(guī)范的定義,到底是Spring的這種方式正確呢,還是Lombok的解析方式正確呢?
2.2 JavaBeans API規(guī)范
Lombok官方回復(fù)的JavaBeans API規(guī)范,是Sun 1997年的API規(guī)范文檔:
https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/
根據(jù)這個文檔,我去stackoverflow上搜了一下,最接近這個問題的描述應(yīng)該是:8.8 Capitalization of inferred names

其實根據(jù)JavaBeans的描述,是沒有具體說明針對我們文中這個問題,首字母小寫,第二個字母大寫這樣的字段該如何get/set的,不過如果強行按照JavaBeans的規(guī)范來的話,那這個其實應(yīng)該是:
public String getiPhone() { return iPhone;}
public void setiPhone(String iPhone) { this.iPhone = iPhone;}
那如果從這點上來說的話,其實Lombok的說法就不太恰當(dāng)?shù)牧恕?/p>
不過還有一種方式,就是如果站在Java中方法命名的角度上來說的話,也就是:Defing Methods - Naming a Method
那么,正確的命名方式應(yīng)該是:
public String getIPhone() { return iPhone;}
public void setIPhone(String iPhone) { this.iPhone = iPhone;}
那么站到這個角度的話,Spring的方式又是不太恰當(dāng)?shù)牧恕?/p>
不過,總的來說,Lombok和Spring他們各自的實現(xiàn)本身沒啥問題,只是針對javaBean的規(guī)范,各自選擇了不同的實現(xiàn)策咯而已。
大家有興趣的可以看下stackoverflow上的討論及Lombok的回復(fù):
https://stackoverflow.com/questions/2948083/naming-convention-for-getters-setters-in-java/49348966#49348966
https://github.com/projectlombok/lombok/issues/504
三、解決方式
知道了原因,其實解決起來也非常簡單了,就是針對這種對象,手動生成get和set方法即可,或者使用編譯器自動生成的,也就是如下:
public String getiPhone() {
return iPhone;
}
public void setiPhone(String iPhone) {
this.iPhone = iPhone;
}
當(dāng)然為了避免這種問題發(fā)生,還有一種更簡單的方式,就是命名的時候,不要使用諸如xXXXX這種格式的命名,使用正常的命名方式,比如indexX這種形式。