Alibaba FastJson支持对象中私有属性的json解析

项目中需要使用fastjson做数据处理,而且部分对象中的属性很多都是第三方的非public的,且没有getter/setter方法,找了很久没有找到fastjson对这个问题的解决
所以自己动手,基于fastjson的源代码构造了单独的javabean的序列化器。
使用方式:直接使用封装好的MetaJsonUtil的工具方法即可。
fastjson版本为1.2.7
MetaJsonUtil.getJSONString(bean)
MetaJsonUtil 类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializeConfig;

/**
 * fastJson不支持对象中私有属性的转换
 * Created by 魔力鸟 on 2015-10-15.
 */
public final class MetaJsonUtil {

    /**
     * 获取对象对应属性数据组成的JSON对象
     * @param target
     * @return
     */
    public static JSONObject getJSONObject(Object target) {
       return JSON.parSEObject(getJSONString(target));
    }

    /**
     * 获取对象对应属性数据组成的字符串
     * @param target
     * @return
     */
    public static String getJSONString(Object target) {
        if (target != null) {
            SerializeConfig globalInstance = SerializeConfig.getGlobalInstance();
            globalInstance.put(target.getClass(),new MetaBeanSerializer(target.getClass()));
            return JSON.toJSONString(target,globalInstance);
        }else{
            return "{}";
        }
    }
}
用到的2个类:
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.serializer.*;
import com.alibaba.fastjson.util.FieldInfo;
import com.alibaba.fastjson.util.TypeUtils;
import org.springframework.util.ReflectionUtils;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * fastjson不支持私有或保护属性的序列化,使用本类支持。
 * 注意:仅实现了序列化,未实现反序列化
 * Created by 张三丰 on 2015-10-14.
 */
public class MetaBeanSerializer extends JavaBeanSerializer {

    private final FieldSerializer[]                getters ;
    private final FieldSerializer[]                sortedGetters;
    private int                                    features = 0;
    public MetaBeanSerializer(Class<?> clazz) {
        this(clazz,null);
    }
    public MetaBeanSerializer(Class<?> clazz,Map<String,String> aliasMap) {
        super(clazz,aliasMap);
        this.features = TypeUtils.getSerializefeatures(clazz);
        {
            List<FieldSerializer> getterList = new ArrayList<FieldSerializer>();
            List<FieldInfo> fieldInfoList = MetaTypeUtils.computeGetters(clazz,aliasMap,false);

            for (FieldInfo fieldInfo : fieldInfoList) {
                getterList.add(createFieldSerializer(fieldInfo));
            }

            getters = getterList.toArray(new FieldSerializer[getterList.size()]);
        }
        {
            List<FieldSerializer> getterList = new ArrayList<FieldSerializer>();
            List<FieldInfo> fieldInfoList = MetaTypeUtils.computeGetters(clazz,true);

            for (FieldInfo fieldInfo : fieldInfoList) {
                getterList.add(createFieldSerializer(fieldInfo));
            }

            sortedGetters = getterList.toArray(new FieldSerializer[getterList.size()]);
        }
    }
    public void write(JSONSerializer serializer,Object object,Object fieldName,Type fieldType,int features)
            throws IOException {
        SerializeWriter out = serializer.getWriter();

        if (object == null) {
            out.writeNull();
            return;
        }

        if (writeReference(serializer,object,features)) {
            return;
        }

        final FieldSerializer[] getters;

        if (out.isEnabled(SerializerFeature.sortField)) {
            getters = this.sortedGetters;
        } else {
            getters = this.getters;
        }

        SerialContext parent = serializer.getContext();
        serializer.setContext(parent,fieldName,this.features,features);

        final boolean writeAsArray = isWriteAsArray(serializer);

        try {
            final char startSeperator = writeAsArray ? '[' : '{';
            final char endSeperator = writeAsArray ? ']' : '}';
            out.append(startSeperator);

            if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
                serializer.incrementIndent();
                serializer.println();
            }

            boolean commaFlag = false;

            if (isWriteClassName(serializer,fieldType,fieldName)) {
                Class<?> objClass = object.getClass();
                if (objClass != fieldType) {
                    out.writeFieldName(JSON.DEFAULT_TYPE_KEY);
                    serializer.write(object.getClass());
                    commaFlag = true;
                }
            }

            char seperator = commaFlag ? ',' : '\0';

            char newSeperator = FilterUtils.writeBefore(serializer,seperator);
            commaFlag = newSeperator == ',';

            for (int i = 0; i < getters.length; ++i) {
                FieldSerializer fieldSerializer = getters[i];

                Field field = fieldSerializer.getField();
                if (serializer.isEnabled(SerializerFeature.SkipTransientField)) {
                    if (field != null) {
                        if (Modifier.isTransient(field.getModifiers())) {
                            continue;
                        }
                    }
                }

                if (serializer.isEnabled(SerializerFeature.IgnoreNonFieldGetter)) {
                    if (field == null) {
                        continue;
                    }
                }

                if (!FilterUtils.applyName(serializer,fieldSerializer.getName())) {
                    continue;
                }

                if (!FilterUtils.applyLabel(serializer,fieldSerializer.getLabel())) {
                    continue;
                }

                Object propertyValue = fieldSerializer.getPropertyValue(object);

                if (!FilterUtils.apply(serializer,fieldSerializer.getName(),propertyValue)) {
                    continue;
                }

                String key = FilterUtils.processKey(serializer,propertyValue);

                Object originalValue = propertyValue;
                propertyValue = FilterUtils.processValue(serializer,propertyValue);

                if (propertyValue == null && !writeAsArray) {
                    if ((!fieldSerializer.isWriteNull())
                            && (!serializer.isEnabled(SerializerFeature.WriteMapNullValue))) {
                        continue;
                    }
                }

                if (propertyValue != null && serializer.isEnabled(SerializerFeature.NotWriteDefaultValue)) {
                    Field field1 =  ReflectionUtils.findField(FieldSerializer.class,"fieldInfo");
                    ReflectionUtils.makeAccessible(field1);
                    Class<?> fieldCLass = ((FieldInfo)ReflectionUtils.getField(field1,fieldSerializer)).getFieldClass();
                    if (fieldCLass == byte.class && propertyValue instanceof Byte
                            && ((Byte) propertyValue).byteValue() == 0) {
                        continue;
                    } else if (fieldCLass == short.class && propertyValue instanceof Short
                            && ((Short) propertyValue).shortValue() == 0) {
                        continue;
                    } else if (fieldCLass == int.class && propertyValue instanceof Integer
                            && ((Integer) propertyValue).intValue() == 0) {
                        continue;
                    } else if (fieldCLass == long.class && propertyValue instanceof Long
                            && ((Long) propertyValue).longValue() == 0L) {
                        continue;
                    } else if (fieldCLass == float.class && propertyValue instanceof Float
                            && ((Float) propertyValue).floatValue() == 0F) {
                        continue;
                    } else if (fieldCLass == double.class && propertyValue instanceof Double
                            && ((Double) propertyValue).doubleValue() == 0D) {
                        continue;
                    } else if (fieldCLass == boolean.class && propertyValue instanceof Boolean
                            && !((Boolean) propertyValue).booleanValue()) {
                        continue;
                    }
                }

                if (commaFlag) {
                    out.append(',');
                    if (out.isEnabled(SerializerFeature.PrettyFormat)) {
                        serializer.println();
                    }
                }

                if (key != fieldSerializer.getName()) {
                    if (!writeAsArray) {
                        out.writeFieldName(key);
                    }
                    serializer.write(propertyValue);
                } else if (originalValue != propertyValue) {
                    if (!writeAsArray) {
                        fieldSerializer.writePrefix(serializer);
                    }
                    serializer.write(propertyValue);
                } else {
                    if (!writeAsArray) {
                        fieldSerializer.writeProperty(serializer,propertyValue);
                    } else {
                        fieldSerializer.writeValue(serializer,propertyValue);
                    }
                }

                commaFlag = true;
            }

            FilterUtils.writeAfter(serializer,commaFlag ? ',' : '\0');

            if (getters.length > 0 && out.isEnabled(SerializerFeature.PrettyFormat)) {
                serializer.decrementIdent();
                serializer.println();
            }

            out.append(endSeperator);
        } catch (Exception e) {
            throw new JSONException("write javaBean error",e);
        } finally {
            serializer.setContext(parent);
        }
    }
}

public class MetaTypeUtils extends TypeUtils {

    public static List<FieldInfo> computeGetters(Class<?> clazz,String> aliasMap,boolean sorted) {
        Map<String,FieldInfo> fieldInfoMap = new LinkedHashMap<String,FieldInfo>();

        for (Method method : clazz.getmethods()) {
            String methodName = method.getName();
            int ordinal = 0,serialzefeatures = 0;
            String label = null;

            if (Modifier.isstatic(method.getModifiers())) {
                continue;
            }

            if (method.getReturnType().equals(Void.TYPE)) {
                continue;
            }

            if (method.getParameterTypes().length != 0) {
                continue;
            }

            if (method.getReturnType() == ClassLoader.class) {
                continue;
            }

            if (method.getName().equals("getMetaClass")
                    && method.getReturnType().getName().equals("groovy.lang.MetaClass")) {
                continue;
            }

            JSONField annotation = method.getAnnotation(JSONField.class);

            if (annotation == null) {
                annotation = getSupperMethodAnnotation(clazz,method);
            }

            if (annotation != null) {
                if (!annotation.serialize()) {
                    continue;
                }

                ordinal = annotation.ordinal();
                serialzefeatures = SerializerFeature.of(annotation.serialzefeatures());

                if (annotation.name().length() != 0) {
                    String propertyName = annotation.name();

                    if (aliasMap != null) {
                        propertyName = aliasMap.get(propertyName);
                        if (propertyName == null) {
                            continue;
                        }
                    }

                    fieldInfoMap.put(propertyName,new FieldInfo(propertyName,method,null,ordinal,serialzefeatures,annotation.label()));
                    continue;
                }

                if (annotation.label().length() != 0) {
                    label = annotation.label();
                }
            }

            if (methodName.startsWith("get")) {
                if (methodName.length() < 4) {
                    continue;
                }

                if (methodName.equals("getClass")) {
                    continue;
                }

                char c3 = methodName.charat(3);

                String propertyName;
                if (Character.isUpperCase(c3)) {
                    if (compatibleWithJavaBean) {
                        propertyName = 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))){
                    propertyName = decapitalize(methodName.substring(3));
                } else {
                    continue;
                }

                boolean ignore = isJSONTypeIgnore(clazz,propertyName);

                if (ignore) {
                    continue;
                }

                Field field = ParserConfig.getField(clazz,propertyName);

                if (field != null) {
                    JSONField fieldAnnotation = field.getAnnotation(JSONField.class);

                    if (fieldAnnotation != null) {
                        if (!fieldAnnotation.serialize()) {
                            continue;
                        }

                        ordinal = fieldAnnotation.ordinal();
                        serialzefeatures = SerializerFeature.of(fieldAnnotation.serialzefeatures());

                        if (fieldAnnotation.name().length() != 0) {
                            propertyName = fieldAnnotation.name();

                            if (aliasMap != null) {
                                propertyName = aliasMap.get(propertyName);
                                if (propertyName == null) {
                                    continue;
                                }
                            }
                        }

                        if (fieldAnnotation.label().length() != 0) {
                            label = fieldAnnotation.label();
                        }
                    }
                }

                if (aliasMap != null) {
                    propertyName = aliasMap.get(propertyName);
                    if (propertyName == null) {
                        continue;
                    }
                }

                fieldInfoMap.put(propertyName,field,label));
            }

            if (methodName.startsWith("is")) {
                if (methodName.length() < 3) {
                    continue;
                }

                char c2 = methodName.charat(2);

                String propertyName;
                if (Character.isUpperCase(c2)) {
                    if (compatibleWithJavaBean) {
                        propertyName = decapitalize(methodName.substring(2));
                    } else {
                        propertyName = Character.toLowerCase(methodName.charat(2)) + methodName.substring(3);
                    }
                } else if (c2 == '_') {
                    propertyName = methodName.substring(3);
                } else if (c2 == 'f') {
                    propertyName = methodName.substring(2);
                } else {
                    continue;
                }

                Field field = ParserConfig.getField(clazz,propertyName);

                if (field == null) {
                    field = ParserConfig.getField(clazz,methodName);
                }

                if (field != null) {
                    JSONField fieldAnnotation = field.getAnnotation(JSONField.class);

                    if (fieldAnnotation != null) {
                        if (!fieldAnnotation.serialize()) {
                            continue;
                        }

                        ordinal = fieldAnnotation.ordinal();
                        serialzefeatures = SerializerFeature.of(fieldAnnotation.serialzefeatures());

                        if (fieldAnnotation.name().length() != 0) {
                            propertyName = fieldAnnotation.name();

                            if (aliasMap != null) {
                                propertyName = aliasMap.get(propertyName);
                                if (propertyName == null) {
                                    continue;
                                }
                            }
                        }

                        if (fieldAnnotation.label().length() != 0) {
                            label = fieldAnnotation.label();
                        }
                    }
                }

                if (aliasMap != null) {
                    propertyName = aliasMap.get(propertyName);
                    if (propertyName == null) {
                        continue;
                    }
                }

                fieldInfoMap.put(propertyName,label));
            }
        }
//此处改动:获取所有属性
        for (Field field : clazz.getDeclaredFields()) {
            if (Modifier.isstatic(field.getModifiers())) {
                continue;
            }

            JSONField fieldAnnotation = field.getAnnotation(JSONField.class);

            int ordinal = 0,serialzefeatures = 0;
            String propertyName = field.getName();
            String label = null;
            if (fieldAnnotation != null) {
                if (!fieldAnnotation.serialize()) {
                    continue;
                }

                ordinal = fieldAnnotation.ordinal();
                serialzefeatures = SerializerFeature.of(fieldAnnotation.serialzefeatures());

                if (fieldAnnotation.name().length() != 0) {
                    propertyName = fieldAnnotation.name();
                }

                if (fieldAnnotation.label().length() != 0) {
                    label = fieldAnnotation.label();
                }
            }

            if (aliasMap != null) {
                propertyName = aliasMap.get(propertyName);
                if (propertyName == null) {
                    continue;
                }
            }

            if (!fieldInfoMap.containsKey(propertyName)) {
                fieldInfoMap.put(propertyName,label));
            }
        }

        List<FieldInfo> fieldInfoList = new ArrayList<FieldInfo>();

        boolean containsAll = false;
        String[] orders = null;

        JSONType annotation = clazz.getAnnotation(JSONType.class);
        if (annotation != null) {
            orders = annotation.orders();

            if (orders != null && orders.length == fieldInfoMap.size()) {
                containsAll = true;
                for (String item : orders) {
                    if (!fieldInfoMap.containsKey(item)) {
                        containsAll = false;
                        break;
                    }
                }
            } else {
                containsAll = false;
            }
        }

        if (containsAll) {
            for (String item : orders) {
                FieldInfo fieldInfo = fieldInfoMap.get(item);
                fieldInfoList.add(fieldInfo);
            }
        } else {
            for (FieldInfo fieldInfo : fieldInfoMap.values()) {
                fieldInfoList.add(fieldInfo);
            }

            if (sorted) {
                Collections.sort(fieldInfoList);
            }
        }
        return fieldInfoList;
    }
    private static boolean isJSONTypeIgnore(Class<?> clazz,String propertyName) {
        JSONType jsonType = clazz.getAnnotation(JSONType.class);

        if (jsonType != null) {
            // 1、新增 includes 支持,如果 JSONType 同时设置了includes 和 ignores 属性,则以includes为准。
            // 2、个人认为对于大小写敏感的Java和JS而言,使用 equals() 比 equalsIgnoreCase() 更好,改动的唯一风险就是向后兼容性的问题
            // 不过,相信开发者应该都是严格按照大小写敏感的方式进行属性设置的
            String[] fields = jsonType.includes();
            if (fields.length > 0) {
                for (int i = 0; i < fields.length; i++) {
                    if (propertyName.equals(fields[i])) {
                        return false;
                    }
                }
                return true;
            } else {
                fields = jsonType.ignores();
                for (int i = 0; i < fields.length; i++) {
                    if (propertyName.equals(fields[i])) {
                        return true;
                    }
                }
            }
        }

        if (clazz.getSuperclass() != Object.class && clazz.getSuperclass() != null) {
            if (isJSONTypeIgnore(clazz.getSuperclass(),propertyName)) {
                return true;
            }
        }

        return false;
    }
}
代码使用到了spring的反射工具类,所以依赖spring-core.

注意:理论上不存在问题,但未经过严格测试。

相关文章

AJAX是一种基于JavaScript和XML的技术,能够使网页实现异步交...
在网页开发中,我们常常需要通过Ajax从后端获取数据并在页面...
在前端开发中,经常需要循环JSON对象数组进行数据操作。使用...
AJAX(Asynchronous JavaScript and XML)是一种用于创建 We...
AJAX技术被广泛应用于现代Web开发,它可以在无需重新加载页面...
Ajax是一种通过JavaScript和HTTP请求交互的技术,可以实现无...