很少用fastjson,写了个demo准备研究一下源码,奇怪的事情发生了,序列化一个Bean类后的字符串居然是空的,这跟我想的有点不一样
public class Student {
int id;
String name;
int age;
public static void main(String[] args) {
Student student = new Student();
student.id = 100;
student.name = "lbt";
student.age = 18;
String jsonString = JSON.toJSONString(student);
System.out.println(jsonString);
}
}
输出结果如下:
{}
带着疑问读了一下源码,从Json.toJSONString(Object object)开始
public static String toJSONString(Object object, //
SerializeConfig config, //
SerializeFilter[] filters, //
String dateFormat, //
int defaultFeatures, //
SerializerFeature... features) {
SerializeWriter out = new SerializeWriter(null, defaultFeatures, features);
try {
JSONSerializer serializer = new JSONSerializer(out, config);
if (dateFormat != null && dateFormat.length() != 0) {
serializer.setDateFormat(dateFormat);
serializer.config(SerializerFeature.WriteDateUseDateFormat, true);
}
if (filters != null) {
for (SerializeFilter filter : filters) {
serializer.addFilter(filter);
}
}
serializer.write(object);
return out.toString();
} finally {
out.close();
}
}
首先初始化一个SerializeWriter对象,接着将该SerializeWriter对象传入JSONSerializer构造器并创建出一个JSONSerializer对象serializer,toJSONString()方法的不同构造器传参数可以知道dateFormat为空,该dateFormat是序列化日期的一种格式;filters也是空的,可在序列化的过程中过滤掉某些变量
接着看serializer.write(object)方法,该方法是序列化过程的核心方法
public final void write(Object object) {
if (object == null) {
out.writeNull();
return;
}
Class<?> clazz = object.getClass();
ObjectSerializer writer = getObjectWriter(clazz);
try {
writer.write(this, object, null, null, 0);
} catch (IOException e) {
throw new JSONException(e.getMessage(), e);
}
}
首先获取object的class对象,用于后面通过Class获取方法和全局变量 接着调用getObjectWriter()方法获取ObjectSerializer
public ObjectSerializer getObjectWriter(Class<?> clazz) {
return config.getObjectWriter(clazz);
}
往下看,执行到SerializeConfig类的getObjectWriter()方法中,该方法很长,看主要的
public ObjectSerializer getObjectWriter(Class<?> clazz, boolean create) {
ObjectSerializer writer = get(clazz);
if (writer != null) {
return writer;
}
if (create) {
writer = createJavaBeanSerializer(clazz);
put(clazz, writer);
}
return writer;
}
1. 首先get(clazz)从当前缓存中获取writer对象,如果存在writer对象则返回该writer,否则执行下一步
2. 调用createJavaBeanSerializer(clazz)对象并赋值给writer
接着看createJavaBeanSerializer()方法
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);
}
接下来通过TypeUtils.buildBeanInfo()方法创建SerializeBeanInfo对象,buildBeanInfo()也很长,看主要方法
public static SerializeBeanInfo buildBeanInfo(Class<?> beanType //
, Map<String,String> aliasMap //
, PropertyNamingStrategy propertyNamingStrategy //
, boolean fieldBased //){
List<FieldInfo> fieldInfoList = fieldBased
? computeGettersWithFieldBase(beanType, aliasMap, false, propertyNamingStrategy) //
: computeGetters(beanType, jsonType, aliasMap, fieldCacheMap, false, propertyNamingStrategy);
return new SerializeBeanInfo(beanType, jsonType, typeName, typeKey, features, fields, sortedFields);
}
调用computeGetters()方法,将序列化的类的FieldInfo存入List中
public static List<FieldInfo> computeGetters(Class<?> clazz, //
JSONType jsonType, //
Map<String,String> aliasMap, //
Map<String,Field> fieldCacheMap, //
boolean sorted, //
PropertyNamingStrategy propertyNamingStrategy //
){
Method[] methods = clazz.getMethods();
for(Method method : methods){
if(Modifier.isStatic(method.getModifiers())){
continue;
}
Class<?> returnType = method.getReturnType();
if(returnType.equals(Void.TYPE)){
continue;
}
if(method.getParameterTypes().length != 0){
continue;
}
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){
propertyName = decapitalize(methodName.substring(3));
} else{
propertyName = TypeUtils.getPropertyNameByMethodName(methodName);
}
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 3);
}
FieldInfo fieldInfo = new FieldInfo(propertyName, method, field, clazz, null, ordinal, serialzeFeatures, parserFeatures,
annotation, fieldAnnotation, label);
fieldInfoMap.put(propertyName, fieldInfo);
}
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);
}
propertyName = getPropertyNameByCompatibleFieldName(fieldCacheMap, methodName, propertyName, 2);
}
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);
}
1. 首先遍历类中的public方法,找到方法名称以get或者is开头的方法,获取方法对应的变量对象名称propertyName,并将其存入Map中
2.接着获取Field对象数组并且调用 computeFields()方法滤除掉static属性变量,以及在遍历method获取到的变量,将其余的变量存入HashMap中
public Field[] getFields() throws SecurityException {
List<Field> fields = new ArrayList<Field>();
getPublicFieldsRecursive(fields);
return fields.toArray(new Field[fields.size()]);
}
接着看getPublicFieldsRecursive()方法,该方法会调用getPublicDeclaredFields()方法,获取该类、父类和接口中的所有的public属性方法
private void getPublicFieldsRecursive(List<Field> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.superClass) {
Collections.addAll(result, c.getPublicDeclaredFields());
}
// search iftable which has a flattened and uniqued list of interfaces
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
}
}
}
结论:
由此可以看出,如果一个Bean类没有实现public修饰的get、is等方法获取变量,以及变量的可见性为非public,那么这些变量均不会参与序列化
理由也很简单,因为对象序列化后必然要经过反序列化,反序列化过程需要对变量进行赋值,如果是非public变量,而且没有public修饰的set、get方法,是无法给变量赋值,因此序列化只序列化能够设置值得变量