共计 4444 个字符,预计需要花费 12 分钟才能阅读完成。
问题形容
public class Demo {
private Boolean isHot;
private Boolean isQuick;
public Boolean getHot() {return isHot;}
public void setHot(Boolean hot) {isHot = hot;}
public Boolean getQuick() {return isQuick;}
public void setQuick(Boolean quick) {isQuick = quick;}
}
例如下面一个 bean,getset 办法均为 idea 主动生成的(Idea 2020.1),Fastjson 序列化后的后果为
{
"hot":true,
"quick":true
}
咱们其实冀望的是
{
"isHot":true,
"isQuick":true
}
解决方案
计划一
批改 get 办法为getIsXXX
public Boolean getHot()
->public Boolean getIsHot()
计划二
去掉 getset 办法应用 lombok,如果公司容许的话
计划三
批改 idea 默认模板
#set($paramName = $helper.getParamName($field, $project))
#if($field.modifierStatic)
static ##
#end
$field.type ##
#set($name = $StringUtil.capitalizeWithJavaBeanConvention($StringUtil.sanitizeJavaIdentifier($helper.getPropertyName($field, $project))))
#if ($field.name == $paramName)
get##
#else
getIs##
#end
${name}() {
return this.##
$field.name;
}
计划四
不要以 is 结尾,退出公司的代码标准,《Java 开发手册(泰山版)》中也提到了
【强制】POJO 类中的任何布尔类型的变量,都不要加 is 前缀,否则局部框架解析会引起序列 化谬误。
源码剖析
上面咱们看一下 Fastjson 源码
public static List<FieldInfo> computeGetters(Class<?> clazz, //
JSONType jsonType, //
Map<String,String> aliasMap, //
Map<String,Field> fieldCacheMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy //
){Map<String,FieldInfo> fieldInfoMap = new LinkedHashMap<String,FieldInfo>();
boolean kotlin = TypeUtils.isKotlin(clazz);
// for kotlin
Constructor[] constructors = null;
Annotation[][] paramAnnotationArrays = null;
String[] paramNames = null;
short[] paramNameMapping = null;
Method[] methods = clazz.getMethods();
for(Method method : methods){
..... 此处省略
// 次要是这里
if(methodName.startsWith("get")){if(methodName.length() < 4){continue;}
if(methodName.equals("getClass")){continue;}
if(methodName.equals("getDeclaringClass") && clazz.isEnum()){continue;}
char c3 = methodName.charAt(3);
String propertyName;
Field field = null;
if(Character.isUpperCase(c3) //
|| c3 > 512 // for unicode method name
){if(compatibleWithJavaBean){
// 依据 get 办法取值
propertyName = decapitalize(methodName.substring(3));
} else{propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);
}
...... 再度省略
fieldInfoMap.put(propertyName, fieldInfo);
}
}
Field[] fields = clazz.getFields();
computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
return getFieldInfos(clazz, sorted, fieldInfoMap);
}
前面就基本上以这个名称为准了。
这个 writer 是通过动静生成的一个 bean,所以代码无奈追踪,然而它强转了下 `
return (JavaBeanSerializer) instance;所以咱们能够看下
JavaBeanSerializer::write 办法看下是如何把
bean 转成
String 的 `
protected void write(JSONSerializer serializer, //
Object object, //
Object fieldName, //
Type fieldType, //
int features,
boolean unwrapped
) throws IOException {
SerializeWriter out = serializer.out;
if (object == null) {out.writeNull();
return;
}
if (writeReference(serializer, object, features)) {return;}
final FieldSerializer[] getters;
// 获取咱们刚刚解析的成员变量 c h
if (out.sortField) {getters = this.sortedGetters;} else {getters = this.getters;}
SerialContext parent = serializer.context;
if (!this.beanInfo.beanType.isEnum()) {serializer.setContext(parent, object, fieldName, this.beanInfo.features, features);
}
final boolean writeAsArray = isWriteAsArray(serializer, features);
FieldSerializer errorFieldSerializer = null;
try {
final char startSeperator = writeAsArray ? '[' : '{';
final char endSeperator = writeAsArray ? ']' : '}';
if (!unwrapped) {
// 全程增加到 out 外面,最初 toJSONString 输入的也是 out
out.append(startSeperator);
}
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {serializer.incrementIndent();
serializer.println();}
boolean commaFlag = false;
if ((this.beanInfo.features & SerializerFeature.WriteClassName.mask) != 0
||(features & SerializerFeature.WriteClassName.mask) != 0
|| serializer.isWriteClassName(fieldType, object)) {Class<?> objClass = object.getClass();
final Type type;
if (objClass != fieldType && fieldType instanceof WildcardType) {type = TypeUtils.getClass(fieldType);
} else {type = fieldType;}
if (objClass != type) {writeClassName(serializer, beanInfo.typeKey, object);
commaFlag = true;
}
}
char seperator = commaFlag ? ',' : '\0';
final boolean writeClassName = out.isEnabled(SerializerFeature.WriteClassName);
char newSeperator = this.writeBefore(serializer, object, seperator);
commaFlag = newSeperator == ',';
final boolean skipTransient = out.isEnabled(SerializerFeature.SkipTransientField);
final boolean ignoreNonFieldGetter = out.isEnabled(SerializerFeature.IgnoreNonFieldGetter);
for (int i = 0; i < getters.length; ++i) {..... 字符串拼接}
this.writeAfter(serializer, object, commaFlag ? ',' : '\0');
if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {serializer.decrementIdent();
serializer.println();}
if (!unwrapped) {
// 全程增加进 out 外面
out.append(endSeperator);
}
} catch (Exception e) {..... 解决异样,疏忽} finally {serializer.context = parent;}
}
正文完