今天使用 JSONObject.toJavaObject()方法试图将一个 JSONObject 对象装换为指定 class 对象,该对象属性如下所示
private Integer ID;
private String fertilizerSiteName;
private String userName;
private Boolean sendOk;
转换后发现 ID 字段一直为 null,然后我们跟踪代码发现,fastjson 通过获取 set 开头的方法,然后通过字符串截取来获取属性(见 com.alibaba.fastjson.util.DeserializeBeanInfo 的 DeserializeBeanInfo computeSetters(Class<?> clazz, Type type)方法),因为正常的命名习惯都是 set 然后属性首字母大写,正常这么写是没有问题的,不过这里我们的 ID 都是大写,他这里默认截取后首字母小写 ID,就变成了 iD 再来做映射的时候就找不到字段了,代码如下
if (methodName.startsWith("set")) {
char c3 = methodName.charAt(3);
String propertyName;
if (Character.isUpperCase(c3)) {
if (TypeUtils.compatibleWithJavaBean) {
propertyName = TypeUtils.decapitalize(methodName.substring(3));
} else {
propertyName = Character.toLowerCase(methodName.charAt(3)) + methodName.substring(4);
}
} else if (c3 == '_') {
propertyName = methodName.substring(4);
} else if (c3 == 'f') {
propertyName = methodName.substring(3);
} else {
if (methodName.length() < 5 || !Character.isUpperCase(methodName.charAt(4))) {
continue;
}
propertyName = TypeUtils.decapitalize(methodName.substring(3));
}
Field field = TypeUtils.getField(clazz, propertyName);
if (field == null && method.getParameterTypes()[0] == Boolean.TYPE) {
String isFieldName = "is" + Character.toUpperCase(propertyName.charAt(0)) + propertyName.substring(1);
field = TypeUtils.getField(clazz, isFieldName);
}
if (field != null) {
JSONField fieldAnnotation = (JSONField)field.getAnnotation(JSONField.class);
if (fieldAnnotation != null) {
ordinal = fieldAnnotation.ordinal();
serialzeFeatures = SerializerFeature.of(fieldAnnotation.serialzeFeatures());
if (fieldAnnotation.name().length() != 0) {
propertyName = fieldAnnotation.name();
beanInfo.add(new FieldInfo(propertyName, method, field, clazz, type, ordinal, serialzeFeatures));
continue;
}
}
}
beanInfo.add(new FieldInfo(propertyName, method, (Field)null, clazz, type, ordinal, serialzeFeatures));
TypeUtils.setAccessible(method);
}
如下,ID 被转成了 iD
从代码中可以看到 fastjson 是根据 TypeUtils.compatibleWithJavaBean 属性(默认 false)决定是否转换首字母大小写,我们在代码中调用 JSONObject.toJavaObject 前将这个值设置为 true 即可
TypeUtils.compatibleWithJavaBean = true;
B_FertilizerSite b_fertilizerSite = JSONObject.toJavaObject(data, B_FertilizerSite.class);
此时他获取属性就会调用 decapitalize 方法如下,可见对于一个属性,如果首字母和第二个字母都是大写,那么直接返回,否则还是会做首字母转小写处理
public static String decapitalize(String name) {
if (name != null && name.length() != 0) {
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))) {
return name;
} else {
char[] chars = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
} else {
return name;
}
}
欢迎来到这里!
我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。
注册 关于