问题描述
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);
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
){
if(compatibleWithJavaBean){
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;
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.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.append(endSeperator);
}
} catch (Exception e) {
.....处理异常,忽略
} finally {
serializer.context = parent;
}
}
|