无尽爱丽丝免安装绿色中文版
7.51G · 2025-10-14
首先,我们先来看阿里巴巴的《Java开发手册》关于 isXXX 是怎么定义的吧:
【强制】POJO 类中布尔类型变量都不要加 is 前缀,否则部分框架解析会引起序列化错误。
反例:定义为基本数据类型 Boolean isDeleted 的属性,它的方法也是 isDeleted(),RPC 框架在反向解析的时候,“误以为”对应的属性名称是 deleted,导致属性获取不到,进而抛出异常。
就是说如果使用 isXXX 这种命名形式会引起潜在的异常。
我们来看一段由idea生成的getter/setter代码:
public class Student {
private String name;
private boolean isDeleted;
public Student(String name, boolean isDeleted) {
this.name = name;
this.isDeleted = isDeleted;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public boolean isDeleted() {
return isDeleted;
}
public void setDeleted(boolean deleted) {
isDeleted = deleted;
}
}
可以看到,isDeleted生成的getter/setter方法是isDeleted/setDeleted,这就会导致有些框架会去找对应的deleted变量,可是我们的变量名是isDeleted,并不是deleted。
经过验证,在fastjson和Jackson这两个序列化框架中,都会存在该问题。
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>2.0.9</version>
</dependency>
@Test
public void test1() throws JsonProcessingException {
//fastjson 序列化框架
Student student = new Student("aaa",true);
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);//输出{"deleted":true,"name":"aaa"}
}
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.13.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.4</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.4</version>
</dependency>
@Test
public void test1() throws JsonProcessingException {
//jackson 序列化框架
Student student = new Student("aaa",true);
ObjectMapper objectMapper = new ObjectMapper();
String jsonString = objectMapper.writeValueAsString(student);
System.out.println(jsonString);//输出{"deleted":true,"name":"aaa"}
}
再提一点,Jackson 是 Spring Boot 内置的 Json 解析框架,用来完成出入参的序列化和反序列化。通常,我们会在 Controller 类中方法上,加上 @RequestBody 或者 @ResponseBody 注解,Spring Boot 会自动对出入参做 Json 解析与转换工作。
注意:@RequestBody用于将入参 Json 转换成对象,而 @ResponseBody 用于将对象转换成 Json 返回。
如果你跟前端约定好的字段是isDeleted,没想到这里序列化之后返回给前端的是deleted,这就会导致前端取不到值。
我们来看一下jackson的源码:
/**
* @since 2.5
*/
public static String okNameForRegularGetter(AnnotatedMethod am, String name,
boolean stdNaming)
{
if (name.startsWith("get")) {
if ("getCallbacks".equals(name)) {
if (isCglibGetCallbacks(am)) {
return null;
}
} else if ("getMetaClass".equals(name)) {
if (isGroovyMetaClassGetter(am)) {
return null;
}
}
return stdNaming
? stdManglePropertyName(name, 3)
: legacyManglePropertyName(name, 3);
}
return null;
}
/**
* @since 2.5
*/
public static String okNameForIsGetter(AnnotatedMethod am, String name,
boolean stdNaming)
{
if (name.startsWith("is")) { // plus, must return a boolean
Class<?> rt = am.getRawType();
if (rt == Boolean.class || rt == Boolean.TYPE) {
return stdNaming
? stdManglePropertyName(name, 2)
: legacyManglePropertyName(name, 2);
}
}
return null;
}
/**
* @since 2.5
*/
@Deprecated // since 2.9, not used any more
public static String okNameForSetter(AnnotatedMethod am, boolean stdNaming) {
String name = okNameForMutator(am, "set", stdNaming);
if ((name != null)
// 26-Nov-2009, tatu: need to suppress this internal groovy method
&& (!"metaClass".equals(name) || !isGroovyMetaClassSetter(am))) {
return name;
}
return null;
}
/**
* @since 2.5
*/
public static String okNameForMutator(AnnotatedMethod am, String prefix,
boolean stdNaming) {
String name = am.getName();
if (name.startsWith(prefix)) {
return stdNaming
? stdManglePropertyName(name, prefix.length())
: legacyManglePropertyName(name, prefix.length());
}
return null;
}
可以看出,如果是Boolean类型的变量,会将isDeleted的前缀is去掉,剩下的deleted作为反序列化key,而将setDeleted的前缀set去掉,剩下的deleted作为序列化key。