一、问题描述
最近在和前端对接接口的时候,发现后端接口返回给前端的一个字段大小写有问题,具体如下。
使用的开发框架及版本:
框架:SpringMVC;
Lombok版本:1.18.12;
对象简化后如下:
@Data
public class MobileInfo {
private String iPhone;
}
预期返回结果:iPhone
,实际返回结果:iphone
。
也就是说SpringMVC环境下,使用Lombok注解
@Data
之后,返回给前端的是iphone
,而不是我们预期中的iPhone
。
二、原因
针对首字母小写,第二个字母大写的这种驼峰命名时,使用@Data注解生成的getter和setter方法分别是:
public String getIPhone() {
return iPhone;
}
public void setIPhone(String iPhone) {
this.iPhone = iPhone;
}
而正常场景下及Spring中对象的getter和setter方法应该是:
public String getiPhone() {
return iPhone;
}
public void setiPhone(String iPhone) {
this.iPhone = iPhone;
}
也就是说Lombok与Spring针对这种首字母小写,第二个字母大写的对象的解析是不同的,而这也就自然而然影响到默认的Jackson的解析,导致返回给前端的属性名称不是我们预期中的名称。
2.1 Lombok问题
其实,针对这个问题,多年前就有人已经在lombok的github提出过对应的issue,参考:
其实,无论是Lombok还是Spring,在处理对象的时候总会有一个API规范进行参考的,这个规范一般就是JavaBeans API的规范。而针对这个问题,Lombok的官方回复是:
JavaBeans的规范就是这样的,Lombok只是遵循这个规范而已,并且不应该使用首字母小写,第二个字母大写这样的命名规则,而Spring的处理方式才是没有遵循JavaBean的规范。除非Oracle官方推荐如此或者大家都是这样处理的化,Lombok才会进行修改。
也就是说,Lombok认为,JavaBeans的规范就是这么定义的,而针对JavaBean的规范,Spring和Lombok选择了不同的实现方式:
- Spring,Jackson针对get/set的生成方式,和我们使用 IDEA 编译器自动生成get/set的方式是相同的,都是诸如
getiPhone()
的形式。- Lombok,针对get/set的生成方式,是
getIPhone()
的形式。
那么,针对JavaBeans规范的定义,到底是Spring的这种方式正确呢,还是Lombok的解析方式正确呢?
2.2 JavaBeans API规范
Lombok官方回复的JavaBeans API规范,是Sun 1997年的API规范文档:
https://download.oracle.com/otndocs/jcp/7224-javabeans-1.01-fr-spec-oth-JSpec/
根据这个文档,我去stackoverflow上搜了一下,最接近这个问题的描述应该是:8.8 Capitalization of inferred names
其实根据JavaBeans的描述,是没有具体说明针对我们文中这个问题,首字母小写,第二个字母大写这样的字段该如何get/set的,不过如果强行按照JavaBeans的规范来的话,那这个其实应该是:
public String getiPhone() { return iPhone;}
public void setiPhone(String iPhone) { this.iPhone = iPhone;}
那如果从这点上来说的话,其实Lombok的说法就不太恰当的了。
不过还有一种方式,就是如果站在Java中方法命名的角度上来说的话,也就是:Defing Methods - Naming a Method
那么,正确的命名方式应该是:
public String getIPhone() { return iPhone;}
public void setIPhone(String iPhone) { this.iPhone = iPhone;}
那么站到这个角度的话,Spring的方式又是不太恰当的了。
不过,总的来说,Lombok和Spring他们各自的实现本身没啥问题,只是针对javaBean的规范,各自选择了不同的实现策咯而已。
大家有兴趣的可以看下stackoverflow上的讨论及Lombok的回复:
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;
}
当然为了避免这种问题发生,还有一种更简单的方式,就是命名的时候,不要使用诸如xXXXX
这种格式的命名,使用正常的命名方式,比如indexX
这种形式。
网友评论