fastjson @JSONField坑


现象

定义了一个类,使用JSONField指定toString后的key值(主要想用来解决首字母大写问题)

@Data

@EqualsAndHashCode(callSuper = false)

public class ShareholderInOutVO extends BasePojo {

   

    @JSONField(name = "Period")

    private String     Period;

    ……

}

通过JSONObject.toJSONString(obj)后结果为:

 

修改实体类:

@Data

@EqualsAndHashCode(callSuper = false)

public class ShareholderInOutVO extends BasePojo {

   

    @JSONField(name = "Period")

    private String     period;

    ……

}

通过JSONObject.toJSONString(obj)后结果为:

 

 

分析

几个主要的断点:

JSONSerializer类

 

 

 

public ObjectSerializer getObjectWriter(Class<?> clazz) {

……

                if (Proxy.isProxyClass(clazz)) {

                    config.put(clazz, config.createJavaBeanSerializer(clazz));

                } else {

                    config.put(clazz, config.createJavaBeanSerializer(clazz));

                }

            }

 

            writer = config.get(clazz);

        }

        return writer;

}

SerializeConfig类

 

 

 

 

 

ASMSerializerFactory类

 

 

 

最终定位到TypeUtils.computeGetters方法

    public static List<FieldInfo> computeGetters(Class<?> clazz, Map<String, String> aliasMap, boolean sorted) {

        Map<String, FieldInfo> fieldInfoMap = new LinkedHashMap<String, FieldInfo>();

 

        for (Method method : clazz.getMethods()) {

            String methodName = method.getName();

 

            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;

                }

 

                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));

                    continue;

                }

            }

 

            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 = Introspector.decapitalize(methodName.substring(3));

                    } else {

// flag: 根据get方法拿到属性名后把首字母变成小写了

                        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 {

                    continue;

                }

 

                boolean ignore = isJSONTypeIgnore(clazz, propertyName);

 

                if (ignore) {

                    continue;

                }

// flag:根据全小写的属性名获取类中的Field,导致无法获取

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

// flag:以下获取@JSONField定义被忽略

                if (field != null) {

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

 

                    if (fieldAnnotation != null) {

                        if (!fieldAnnotation.serialize()) {

                            continue;

                        }

 

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

                            propertyName = fieldAnnotation.name();

 

                            if (aliasMap != null) {

                                propertyName = aliasMap.get(propertyName);

                                if (propertyName == null) {

                                    continue;

                                }

                            }

                        }

                    }

                }

 

                if (aliasMap != null) {

                    propertyName = aliasMap.get(propertyName);

                    if (propertyName == null) {

                        continue;

                    }

                }

 

                fieldInfoMap.put(propertyName, new FieldInfo(propertyName, method, field));

            }

 

            if (methodName.startsWith("is")) {

                if (methodName.length() < 3) {

                    continue;

                }

 

                char c2 = methodName.charAt(2);

 

                String propertyName;

                if (Character.isUpperCase(c2)) {

                    if (compatibleWithJavaBean) {

                        propertyName = Introspector.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;

                        }

 

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

                            propertyName = fieldAnnotation.name();

 

                            if (aliasMap != null) {

                                propertyName = aliasMap.get(propertyName);

                                if (propertyName == null) {

                                    continue;

                                }

                            }

                        }

                    }

                }

 

                if (aliasMap != null) {

                    propertyName = aliasMap.get(propertyName);

                    if (propertyName == null) {

                        continue;

                    }

                }

 

                fieldInfoMap.put(propertyName, new FieldInfo(propertyName, method, field));

            }

        }

 

        for (Field field : clazz.getFields()) {

            if (Modifier.isStatic(field.getModifiers())) {

                continue;

            }

 

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

 

            String propertyName = field.getName();

            if (fieldAnnotation != null) {

                if (!fieldAnnotation.serialize()) {

                    continue;

                }

 

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

                    propertyName = fieldAnnotation.name();

                }

            }

 

            if (aliasMap != null) {

                propertyName = aliasMap.get(propertyName);

                if (propertyName == null) {

                    continue;

                }

            }

 

            if (!fieldInfoMap.containsKey(propertyName)) {

                fieldInfoMap.put(propertyName, new FieldInfo(propertyName, null, field));

            }

        }

 

        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;

    }

 

解决思路

  1. 属性名改成”period”
  2. 不使用lombok的get/set方法,并将@JSONField写在get方法上:

 

 

 

总结

Java规范【属性小驼峰命名】很重要

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM