使用fastjson进行JSON序列化存储到数据库后,发现JSON字符串“莫名其妙地”多了一些属性。
public class MyClass {
// boolean 类型的属性
private boolean isActive;
private boolean valid;
// int 类型的属性
private int id;
// 默认构造器
public MyClass() {
}
// 带有所有属性的构造器
public MyClass(boolean isActive, boolean valid, int id) {
this.isActive = isActive;
this.valid = valid;
this.id = id;
}
// isActive 的 getter 和 setter 方法
public boolean isActive() {
return isActive;
}
public void setActive(boolean isActive) {
this.isActive = isActive;
}
// valid 的 getter 和 setter 方法
public boolean getValid() {
return valid;
}
public void setValid(boolean valid) {
this.valid = valid;
}
// id 的 getter 和 setter 方法
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
测试
import com.alibaba.fastjson.JSON;
public class MyClassMain {
public static void main(String[] args) {
// 创建 MyClass 对象
MyClass myClass = new MyClass(true, false, 123);
// 使用 fastjson 序列化对象
String jsonString = JSON.toJSONString(myClass);
// 打印 JSON 字符串
System.out.println(jsonString);
}
}
结果
多了一个 active 属性,少了一个isActive属性。
问题出在这个函数
com.alibaba.fastjson.serializer.SerializeConfig
public final ObjectSerializer createJavaBeanSerializer(Class<?> clazz) {
String className = clazz.getName();
long hashCode64 = TypeUtils.fnv1a_64(className);
if (Arrays.binarySearch(denyClasses, hashCode64) >= 0) {
throw new JSONException("not support class : " + className);
}
// 关键
SerializeBeanInfo beanInfo = TypeUtils.buildBeanInfo(clazz, null, propertyNamingStrategy, fieldBased);
if (beanInfo.fields.length == 0 && Iterable.class.isAssignableFrom(clazz)) {
return MiscCodec.instance;
}
return createJavaBeanSerializer(beanInfo);
}
om.alibaba.fastjson.util.TypeUtils#computeGetters
public static List<FieldInfo> computeGetters(Class<?> clazz, //
JSONType jsonType, //
Map<String,String> aliasMap, //
Map<String,Field> fieldCacheMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy //
){
// 省略部分代码
if(methodName.startsWith("is")){
if(methodName.length() < 3){
continue;
}
if(returnType != Boolean.TYPE
&& returnType != Boolean.class){
continue;
}
char c2 = methodName.charAt(2);
String propertyName;
Field field = null;
if(Character.isUpperCase(c2)){
if(compatibleWithJavaBean){
propertyName = decapitalize(methodName.substring(2));
} else{
propertyName = Character.toLowerCase(methodName.charAt(2)) + methodName.substring(3);
}
// 这里 isActive 的属性名被计算出 active
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 2);
}
// 省略其他
JSONField fieldAnnotation = null;
if(field != null){
fieldAnnotation = TypeUtils.getAnnotation(field, JSONField.class);
if(fieldAnnotation != null){
if(!fieldAnnotation.serialize()){
continue;
}
ordinal = fieldAnnotation.ordinal();
serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
parserFeatures = Feature.of(fieldAnnotation.parseFeatures());
if(fieldAnnotation.name().length() != 0){
//关键: 使用 JSONField 注解设置的 name 替代属性名
propertyName = fieldAnnotation.name();
if(aliasMap != null){
propertyName = aliasMap.get(propertyName);
if(propertyName == null){
continue;
}
}
}
if(fieldAnnotation.label().length() != 0){
label = fieldAnnotation.label();
}
}
}
// 省略部分代码
FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
annotation, fieldAnnotation, label);
fieldInfoMap.put(propertyName, fieldInfo);
}
}
Field[] fields = clazz.getFields();
computeFields(clazz, aliasMap, propertyNamingStrategy, fieldInfoMap, fields);
return getFieldInfos(clazz, sorted, fieldInfoMap);
}
fastjson通过反射虽然有能力识别真实的属性名,但是实际操作时会根据 getter 方法反推出属性名,造成转为JSON字符串时和实际属性名存在偏差。
解决办法
布尔类型的变量不要加is前缀或者使用fastjson自带的@JSONField注解,不过这种方式fastjson的侵入性太强。
public class MyClass {
@JSONField( name="isActive")
// boolean 类型的属性
private boolean isActive;
private boolean valid;
// 省略其他
}
阿里巴巴java开发手册