Example usage for java.lang Class getAnnotations

List of usage examples for java.lang Class getAnnotations

Introduction

In this page you can find the example usage for java.lang Class getAnnotations.

Prototype

public Annotation[] getAnnotations() 

Source Link

Usage

From source file:ca.oson.json.Oson.java

<T> T deserialize2Object(FieldData objectDTO) {
    Object valueToProcess = objectDTO.valueToProcess;
    Map<String, Object> map = null;

    if (valueToProcess != null && Map.class.isAssignableFrom(valueToProcess.getClass())) {
        map = (Map) valueToProcess;
    } else {/*  w w  w .j  a  v a 2 s.  c om*/
        map = new HashMap<>();
    }

    Class<T> valueType = objectDTO.returnType;
    T obj = (T) objectDTO.returnObj;

    Set<String> nameKeys = new HashSet(map.keySet());

    if (valueType == null) {
        valueType = (Class<T>) obj.getClass();
    }

    // first build up the class-level processing rules

    ClassMapper classMapper = objectDTO.classMapper;
    //if (classMapper == null) {
    // 1. Create a blank class mapper instance
    classMapper = new ClassMapper(valueType);

    // 2. Globalize it
    classMapper = globalize(classMapper);
    objectDTO.classMapper = classMapper;
    //}

    if (objectDTO.fieldMapper != null && isInheritMapping()) {
        classMapper = overwriteBy(classMapper, objectDTO.fieldMapper);
    }

    objectDTO.incrLevel();

    try {
        boolean annotationSupport = getAnnotationSupport();
        Annotation[] annotations = null;

        if (annotationSupport) {
            ca.oson.json.annotation.ClassMapper classMapperAnnotation = null;

            // 3. Apply annotations from other sources
            annotations = valueType.getAnnotations();
            for (Annotation annotation : annotations) {
                if (ignoreClass(annotation)) {
                    return null;
                }

                switch (annotation.annotationType().getName()) {
                case "ca.oson.json.annotation.ClassMapper":
                    classMapperAnnotation = (ca.oson.json.annotation.ClassMapper) annotation;
                    if (!(classMapperAnnotation.serialize() == BOOLEAN.BOTH
                            || classMapperAnnotation.serialize() == BOOLEAN.FALSE)) {
                        classMapperAnnotation = null;
                    }
                    break;

                case "ca.oson.json.annotation.ClassMappers":
                    ca.oson.json.annotation.ClassMappers classMapperAnnotations = (ca.oson.json.annotation.ClassMappers) annotation;
                    for (ca.oson.json.annotation.ClassMapper ann : classMapperAnnotations.value()) {
                        if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.FALSE) {
                            classMapperAnnotation = ann;
                            // break;
                        }
                    }
                    break;

                case "com.google.gson.annotations.Since":
                    Since since = (Since) annotation;
                    classMapper.since = since.value();
                    break;

                case "com.google.gson.annotations.Until":
                    Until until = (Until) annotation;
                    classMapper.until = until.value();
                    break;

                case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                    JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                    String[] jsonnames = jsonIgnoreProperties.value();
                    if (jsonnames != null && jsonnames.length > 0) {
                        if (classMapper.jsonIgnoreProperties == null) {
                            classMapper.jsonIgnoreProperties = new HashSet();
                        }

                        classMapper.jsonIgnoreProperties.addAll(Arrays.asList(jsonnames));
                    }
                    break;

                case "org.codehaus.jackson.annotate.JsonIgnoreProperties":
                    org.codehaus.jackson.annotate.JsonIgnoreProperties jsonIgnoreProperties2 = (org.codehaus.jackson.annotate.JsonIgnoreProperties) annotation;
                    String[] jsonnames2 = jsonIgnoreProperties2.value();
                    if (jsonnames2 != null && jsonnames2.length > 0) {
                        if (classMapper.jsonIgnoreProperties == null) {
                            classMapper.jsonIgnoreProperties = new HashSet();
                        }

                        classMapper.jsonIgnoreProperties.addAll(Arrays.asList(jsonnames2));
                    }
                    break;

                case "com.fasterxml.jackson.annotation.JsonPropertyOrder":
                    // first come first serve
                    if (classMapper.propertyOrders == null) {
                        classMapper.propertyOrders = ((JsonPropertyOrder) annotation).value();
                    }
                    break;

                case "org.codehaus.jackson.annotate.JsonPropertyOrder":
                    // first come first serve
                    if (classMapper.propertyOrders == null) {
                        classMapper.propertyOrders = ((org.codehaus.jackson.annotate.JsonPropertyOrder) annotation)
                                .value();
                    }
                    break;

                case "com.fasterxml.jackson.annotation.JsonInclude":
                    if (classMapper.defaultType == JSON_INCLUDE.NONE) {
                        JsonInclude jsonInclude = (JsonInclude) annotation;
                        switch (jsonInclude.content()) {
                        case ALWAYS:
                            classMapper.defaultType = JSON_INCLUDE.ALWAYS;
                            break;
                        case NON_NULL:
                            classMapper.defaultType = JSON_INCLUDE.NON_NULL;
                            break;
                        case NON_ABSENT:
                            classMapper.defaultType = JSON_INCLUDE.NON_NULL;
                            break;
                        case NON_EMPTY:
                            classMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                            break;
                        case NON_DEFAULT:
                            classMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                            break;
                        case USE_DEFAULTS:
                            classMapper.defaultType = JSON_INCLUDE.DEFAULT;
                            break;
                        }
                    }
                    break;

                case "com.fasterxml.jackson.annotation.JsonAutoDetect":
                    JsonAutoDetect jsonAutoDetect = (JsonAutoDetect) annotation;
                    if (jsonAutoDetect.fieldVisibility() == Visibility.NONE) {
                        classMapper.useField = false;
                    } else if (jsonAutoDetect.fieldVisibility() != Visibility.DEFAULT) {
                        classMapper.useField = true;
                    }
                    if (jsonAutoDetect.setterVisibility() == Visibility.NONE) {
                        classMapper.useAttribute = false;
                    } else if (jsonAutoDetect.setterVisibility() != Visibility.DEFAULT) {
                        classMapper.useAttribute = true;
                    }

                    break;

                case "org.codehaus.jackson.annotate.JsonAutoDetect":
                    org.codehaus.jackson.annotate.JsonAutoDetect jsonAutoDetect2 = (org.codehaus.jackson.annotate.JsonAutoDetect) annotation;
                    if (jsonAutoDetect2
                            .fieldVisibility() == org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE) {
                        classMapper.useField = false;
                    }
                    if (jsonAutoDetect2
                            .getterVisibility() == org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE) {
                        classMapper.useAttribute = false;
                    }

                    break;

                case "org.junit.Ignore":
                    classMapper.ignore = true;
                    break;
                }
            }

            // 4. Apply annotations from Oson
            if (classMapperAnnotation != null) {
                classMapper = overwriteBy(classMapper, classMapperAnnotation);
            }
        }

        // 5. Apply Java configuration for this particular class
        ClassMapper javaClassMapper = getClassMapper(valueType);
        if (javaClassMapper != null) {
            classMapper = overwriteBy(classMapper, javaClassMapper);
        }

        // now processing at the class level

        if (classMapper.ignore()) {
            return null;
        }

        if (classMapper.since != null && classMapper.since > getVersion()) {
            return null;
        } else if (classMapper.until != null && classMapper.until <= getVersion()) {
            return null;
        }

        Function function = classMapper.deserializer; // = getDeserializer(valueType);
        if (function == null) {
            function = DeSerializerUtil.getDeserializer(valueType.getName());
        }
        if (function != null) {
            try {
                Object returnedValue = null;
                if (function instanceof Json2DataMapperFunction) {
                    DataMapper classData = new DataMapper(valueToProcess, valueType, obj, classMapper,
                            objectDTO.level, getPrettyIndentation());
                    Json2DataMapperFunction f = (Json2DataMapperFunction) function;

                    return (T) f.apply(classData);

                } else if (function instanceof Json2FieldDataFunction) {
                    Json2FieldDataFunction f = (Json2FieldDataFunction) function;
                    FieldData fieldData = objectDTO.clone();

                    returnedValue = f.apply(fieldData);

                } else {
                    returnedValue = function.apply(obj);
                }

                if (returnedValue instanceof Optional) {
                    Optional opt = (Optional) returnedValue;
                    returnedValue = opt.orElse(null);
                }

                if (returnedValue == null) {
                    return null;
                } else if (valueType.isAssignableFrom(returnedValue.getClass())) {
                    return (T) returnedValue;
                } else {
                    // not the correct returned object type, do nothing
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        Map<String, Method> getters = getGetters(valueType);
        Map<String, Method> setters = getSetters(valueType);
        Map<String, Method> otherMethods = getOtherMethods(valueType);
        Set<String> processedNameSet = new HashSet<>();

        Method jsonAnySetterMethod = null;

        Field[] fields = getFields(valueType); // getFields(obj);

        FIELD_NAMING format = getFieldNaming();

        // @Expose
        boolean exposed = false;
        if (isUseGsonExpose()) {
            // check if @exposed is used any where
            if (valueType.isAnnotationPresent(com.google.gson.annotations.Expose.class)) {
                exposed = true;
            }
            if (!exposed) {
                for (Field f : fields) {
                    if (f.isAnnotationPresent(com.google.gson.annotations.Expose.class)) {
                        exposed = true;
                        break;
                    }
                }
            }
        }

        for (Field f : fields) {
            String name = f.getName();
            String fieldName = name;
            String lcfieldName = name.toLowerCase();

            Class<?> returnType = f.getType(); // value.getClass();

            if (Modifier.isFinal(f.getModifiers()) && Modifier.isStatic(f.getModifiers())) {
                setters.remove(lcfieldName);
                nameKeys.remove(name);
                continue;
            }

            f.setAccessible(true);

            // getter and setter methods

            Method getter = null;
            Method setter = null;
            if (getters != null) {
                getter = getters.get(lcfieldName);
            }
            if (setters != null) {
                setter = setters.get(lcfieldName);
            }

            if (ignoreModifiers(f.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                if (setter != null) {
                    if (ignoreModifiers(setter.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                        setters.remove(lcfieldName);
                        nameKeys.remove(name);
                        continue;
                    }

                } else {
                    continue;
                }
            }

            // 6. Create a blank field mapper instance
            // using valueType of enclosing obj
            FieldMapper fieldMapper = new FieldMapper(name, name, valueType);

            // 7. get the class mapper of returnType
            ClassMapper fieldClassMapper = getClassMapper(returnType);

            // 8. Classify this field mapper with returnType
            fieldMapper = classifyFieldMapper(fieldMapper, fieldClassMapper);

            // 9. Classify this field mapper with enclosing class type
            fieldMapper = classifyFieldMapper(fieldMapper, classMapper);

            FieldMapper javaFieldMapper = getFieldMapper(name, null, valueType);

            boolean ignored = false;

            if (setter != null) {
                setter.setAccessible(true);
            }

            Set<String> names = new HashSet<>();

            if (annotationSupport) {
                annotations = f.getAnnotations();

                if (setter != null
                        && ((javaFieldMapper == null || javaFieldMapper.useAttribute == null)
                                && (fieldMapper.useAttribute == null || fieldMapper.useAttribute))
                        || (javaFieldMapper != null && javaFieldMapper.isDeserializing()
                                && javaFieldMapper.useAttribute != null && javaFieldMapper.useAttribute)) {
                    annotations = Stream
                            .concat(Arrays.stream(annotations), Arrays.stream(setter.getDeclaredAnnotations()))
                            .toArray(Annotation[]::new);
                }

                // no annotations, then try get method
                if ((annotations == null || annotations.length == 0) && getter != null) {
                    annotations = getter.getDeclaredAnnotations();
                }

                ca.oson.json.annotation.FieldMapper fieldMapperAnnotation = null;

                boolean exposexists = false;
                for (Annotation annotation : annotations) {
                    if (ignoreField(annotation, classMapper.ignoreFieldsWithAnnotations)) {
                        ignored = true;
                        break;

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                        fieldMapperAnnotation = (ca.oson.json.annotation.FieldMapper) annotation;
                        if (!(fieldMapperAnnotation.serialize() == BOOLEAN.BOTH
                                || fieldMapperAnnotation.serialize() == BOOLEAN.FALSE)) {
                            fieldMapperAnnotation = null;
                        }

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMappers) {
                        ca.oson.json.annotation.FieldMappers fieldMapperAnnotations = (ca.oson.json.annotation.FieldMappers) annotation;
                        for (ca.oson.json.annotation.FieldMapper ann : fieldMapperAnnotations.value()) {
                            if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.FALSE) {
                                fieldMapperAnnotation = ann;
                                //break; to enable the last one wins
                            }
                        }

                    } else {

                        switch (annotation.annotationType().getName()) {

                        case "com.fasterxml.jackson.annotation.JsonAnySetter":
                        case "org.codehaus.jackson.annotate.JsonAnySetter":
                            fieldMapper.jsonAnySetter = true;
                            break;

                        case "javax.persistence.Transient":
                            fieldMapper.ignore = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnore":
                        case "org.codehaus.jackson.annotate.JsonIgnore":
                            fieldMapper.ignore = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                            JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                            if (!jsonIgnoreProperties.allowSetters()) {
                                fieldMapper.ignore = true;
                            } else {
                                fieldMapper.ignore = false;
                                classMapper.jsonIgnoreProperties.remove(name);
                            }
                            break;

                        case "com.google.gson.annotations.Expose":
                            Expose expose = (Expose) annotation;
                            if (!expose.deserialize()) {
                                fieldMapper.ignore = true;
                            }
                            exposexists = true;
                            break;

                        case "com.google.gson.annotations.Since":
                            Since since = (Since) annotation;
                            fieldMapper.since = since.value();
                            break;

                        case "com.google.gson.annotations.Until":
                            Until until = (Until) annotation;
                            fieldMapper.until = until.value();
                            break;

                        case "com.google.gson.annotations.SerializedName":
                            SerializedName serializedName = (SerializedName) annotation;
                            String[] alternates = serializedName.alternate();

                            if (alternates != null && alternates.length > 0) {
                                for (String alternate : alternates) {
                                    names.add(alternate);
                                }
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonInclude":
                            if (fieldMapper.defaultType == JSON_INCLUDE.NONE) {
                                JsonInclude jsonInclude = (JsonInclude) annotation;

                                switch (jsonInclude.content()) {
                                case ALWAYS:
                                    fieldMapper.defaultType = JSON_INCLUDE.ALWAYS;
                                    break;
                                case NON_NULL:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_ABSENT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_EMPTY:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                                    break;
                                case NON_DEFAULT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                                    break;
                                case USE_DEFAULTS:
                                    fieldMapper.defaultType = JSON_INCLUDE.DEFAULT;
                                    break;
                                }
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonRawValue":
                            if (((JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.codehaus.jackson.annotate.JsonRawValue":
                            if (((org.codehaus.jackson.annotate.JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.junit.Ignore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.persistence.Enumerated":
                            fieldMapper.enumType = ((Enumerated) annotation).value();
                            break;

                        case "javax.validation.constraints.NotNull":
                            fieldMapper.required = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonProperty":
                            JsonProperty jsonProperty = (JsonProperty) annotation;
                            Access access = jsonProperty.access();
                            if (access == Access.READ_ONLY) {
                                fieldMapper.ignore = true;
                            }

                            if (jsonProperty.required()) {
                                fieldMapper.required = true;
                            }

                            if (fieldMapper.defaultValue == null) {
                                fieldMapper.defaultValue = jsonProperty.defaultValue();
                            }
                            break;

                        case "javax.validation.constraints.Size":
                            Size size = (Size) annotation;
                            if (size.min() > 0) {
                                fieldMapper.min = (long) size.min();
                            }
                            if (size.max() < Integer.MAX_VALUE) {
                                fieldMapper.max = (long) size.max();
                            }
                            break;

                        case "javax.persistence.Column":
                            Column column = (Column) annotation;
                            if (column.length() != 255) {
                                fieldMapper.length = column.length();
                            }
                            if (column.scale() > 0) {
                                fieldMapper.scale = column.scale();
                            }
                            if (column.precision() > 0) {
                                fieldMapper.precision = column.precision();
                            }

                            if (!column.nullable()) {
                                fieldMapper.required = true;
                            }
                            break;
                        }

                        String fname = ObjectUtil.getName(annotation);
                        if (!StringUtil.isEmpty(fname)) {
                            names.add(fname);
                        }

                    }
                }

                if (exposed && !exposexists) {
                    fieldMapper.ignore = true;
                }

                // 10. Apply annotations from Oson
                if (fieldMapperAnnotation != null) {
                    fieldMapper = overwriteBy(fieldMapper, fieldMapperAnnotation, classMapper);
                }
            }

            if (ignored) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                setters.remove(lcfieldName);
                if (exposed) {
                    setNull(f, obj);
                }
                continue;
            }

            // 11. Apply Java configuration for this particular field
            if (javaFieldMapper != null && javaFieldMapper.isDeserializing()) {
                fieldMapper = overwriteBy(fieldMapper, javaFieldMapper);
            }

            if (fieldMapper.ignore != null && fieldMapper.ignore) {
                if (setter != null) {
                    setters.remove(lcfieldName);
                }
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                if (exposed) {
                    setNull(f, obj);
                }
                continue;
            }

            // in the ignored list
            if (ObjectUtil.inSet(name, classMapper.jsonIgnoreProperties)) {
                setters.remove(lcfieldName);
                nameKeys.remove(name);
                continue;
            }

            if (fieldMapper.jsonAnySetter != null && fieldMapper.jsonAnySetter && setter != null) {
                setters.remove(lcfieldName);
                otherMethods.put(lcfieldName, setter);
                continue;
            }

            if (fieldMapper.useField != null && !fieldMapper.useField) {
                // both should not be used, just like ignore
                if (fieldMapper.useAttribute != null && !fieldMapper.useAttribute) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            if (fieldMapper.since != null && fieldMapper.since > getVersion()) {
                if (setter != null) {
                    setters.remove(lcfieldName);
                }
                continue;
            } else if (fieldMapper.until != null && fieldMapper.until <= getVersion()) {
                if (setter != null) {
                    setters.remove(lcfieldName);
                }
                continue;
            }

            // get value for name in map
            Object value = null;
            boolean jnameFixed = false;
            String json = fieldMapper.json;
            int size = nameKeys.size();
            if (json == null) {
                if (setter != null) {
                    setters.remove(lcfieldName);
                }
                continue;

            } else if (!json.equals(name)) {
                name = json;
                value = getMapValue(map, name, nameKeys);
                jnameFixed = true;
            }

            if (!jnameFixed) {
                for (String jsoname : names) {
                    if (!name.equals(jsoname) && !StringUtil.isEmpty(jsoname)) {
                        name = jsoname;
                        value = getMapValue(map, name, nameKeys);
                        if (value != null) {
                            jnameFixed = true;
                            break;
                        }
                    }
                }
            }

            if (!jnameFixed) {
                value = getMapValue(map, name, nameKeys);
                jnameFixed = true;
            }

            fieldMapper.java = fieldName;
            fieldMapper.json = name;

            // either not null, or a null value exists in the value map
            if (value != null || size == nameKeys.size() + 1) {
                Object oldValue = value;
                FieldData fieldData = new FieldData(obj, f, value, returnType, true, fieldMapper,
                        objectDTO.level, objectDTO.set);
                fieldData.setter = setter;
                Class fieldType = guessComponentType(fieldData);
                value = json2Object(fieldData);

                if (StringUtil.isNull(value)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_NULL
                            || classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                            || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;

                    }

                } else if (StringUtil.isEmpty(value)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                            || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;
                    }

                } else if (DefaultValue.isDefault(value, returnType)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;
                    }
                }

                try {
                    if (value == null && oldValue != null && oldValue.equals(f.get(obj) + "")) {
                        // keep original value

                    } else {
                        f.set(obj, value);
                    }

                } catch (IllegalAccessException | IllegalArgumentException ex) {
                    //ex.printStackTrace();
                    if (setter != null) {
                        ObjectUtil.setMethodValue(obj, setter, value);
                    }
                }
            }

            setters.remove(lcfieldName);
            nameKeys.remove(name);
        }

        for (Entry<String, Method> entry : setters.entrySet()) {
            String lcfieldName = entry.getKey();
            Method setter = entry.getValue();

            setter.setAccessible(true);

            String name = setter.getName();
            if (name != null && name.length() > 3 && name.substring(0, 3).equals("set")
                    && name.substring(3).equalsIgnoreCase(lcfieldName)) {
                name = StringUtil.uncapitalize(name.substring(3));
            }

            // just use field name, even it might not be a field
            String fieldName = name;

            if (ignoreModifiers(setter.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                nameKeys.remove(name);
                continue;
            }

            if (Modifier.isFinal(setter.getModifiers()) && Modifier.isStatic(setter.getModifiers())) {
                nameKeys.remove(name);
                continue;
            }

            // 6. Create a blank field mapper instance
            FieldMapper fieldMapper = new FieldMapper(name, name, valueType);

            Class returnType = null;
            Class[] types = setter.getParameterTypes();
            if (types != null && types.length > 0) {
                returnType = types[0];
            }

            // not a proper setter
            if (returnType == null) {
                continue;
            }

            // 7. get the class mapper of returnType
            ClassMapper fieldClassMapper = getClassMapper(returnType);

            // 8. Classify this field mapper with returnType
            fieldMapper = classifyFieldMapper(fieldMapper, fieldClassMapper);

            // 9. Classify this field mapper with enclosing class type
            fieldMapper = classifyFieldMapper(fieldMapper, classMapper);

            FieldMapper javaFieldMapper = getFieldMapper(name, null, valueType);

            boolean ignored = false;

            Method getter = getters.get(lcfieldName);

            Set<String> names = new HashSet<>();

            if (annotationSupport) {

                annotations = setter.getDeclaredAnnotations();

                // no annotations, then try get method
                if ((annotations == null || annotations.length == 0) && getter != null) {
                    annotations = getter.getDeclaredAnnotations();
                }

                ca.oson.json.annotation.FieldMapper fieldMapperAnnotation = null;

                for (Annotation annotation : annotations) {
                    if (ignoreField(annotation, classMapper.ignoreFieldsWithAnnotations)) {
                        ignored = true;
                        break;

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                        fieldMapperAnnotation = (ca.oson.json.annotation.FieldMapper) annotation;
                        if (!(fieldMapperAnnotation.serialize() == BOOLEAN.BOTH
                                || fieldMapperAnnotation.serialize() == BOOLEAN.FALSE)) {
                            fieldMapperAnnotation = null;
                        }

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMappers) {
                        ca.oson.json.annotation.FieldMappers fieldMapperAnnotations = (ca.oson.json.annotation.FieldMappers) annotation;
                        for (ca.oson.json.annotation.FieldMapper ann : fieldMapperAnnotations.value()) {
                            if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.FALSE) {
                                fieldMapperAnnotation = ann;
                                // break;
                            }
                        }

                    } else {
                        // to improve performance, using swith on string
                        switch (annotation.annotationType().getName()) {
                        case "com.fasterxml.jackson.annotation.JsonAnySetter":
                        case "org.codehaus.jackson.annotate.JsonAnySetter":
                            fieldMapper.jsonAnySetter = true;
                            break;

                        case "javax.persistence.Transient":
                            fieldMapper.ignore = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnore":
                        case "org.codehaus.jackson.annotate.JsonIgnore":
                            fieldMapper.ignore = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                            JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                            if (!jsonIgnoreProperties.allowSetters()) {
                                fieldMapper.ignore = true;
                            } else {
                                fieldMapper.ignore = false;
                                classMapper.jsonIgnoreProperties.remove(name);
                            }
                            break;

                        case "com.google.gson.annotations.Expose":
                            Expose expose = (Expose) annotation;
                            if (!expose.deserialize()) {
                                fieldMapper.ignore = true;
                            }
                            break;

                        case "com.google.gson.annotations.Since":
                            Since since = (Since) annotation;
                            fieldMapper.since = since.value();
                            break;

                        case "com.google.gson.annotations.Until":
                            Until until = (Until) annotation;
                            fieldMapper.until = until.value();
                            break;

                        case "com.fasterxml.jackson.annotation.JsonInclude":
                            if (fieldMapper.defaultType == JSON_INCLUDE.NONE) {
                                JsonInclude jsonInclude = (JsonInclude) annotation;

                                switch (jsonInclude.content()) {
                                case ALWAYS:
                                    fieldMapper.defaultType = JSON_INCLUDE.ALWAYS;
                                    break;
                                case NON_NULL:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_ABSENT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_EMPTY:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                                    break;
                                case NON_DEFAULT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                                    break;
                                case USE_DEFAULTS:
                                    fieldMapper.defaultType = JSON_INCLUDE.DEFAULT;
                                    break;
                                }
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonRawValue":
                            if (((JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.codehaus.jackson.annotate.JsonRawValue":
                            if (((org.codehaus.jackson.annotate.JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.junit.Ignore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.persistence.Enumerated":
                            fieldMapper.enumType = ((Enumerated) annotation).value();
                            break;

                        case "javax.validation.constraints.NotNull":
                            fieldMapper.required = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonProperty":
                            JsonProperty jsonProperty = (JsonProperty) annotation;
                            Access access = jsonProperty.access();
                            if (access == Access.READ_ONLY) {
                                fieldMapper.ignore = true;
                            }

                            if (jsonProperty.required()) {
                                fieldMapper.required = true;
                            }

                            if (fieldMapper.defaultValue == null) {
                                fieldMapper.defaultValue = jsonProperty.defaultValue();
                            }
                            break;

                        case "javax.validation.constraints.Size":
                            Size size = (Size) annotation;
                            if (size.min() > 0) {
                                fieldMapper.min = (long) size.min();
                            }
                            if (size.max() < Integer.MAX_VALUE) {
                                fieldMapper.max = (long) size.max();
                            }
                            break;

                        case "javax.persistence.Column":
                            Column column = (Column) annotation;
                            if (column.length() != 255) {
                                fieldMapper.length = column.length();
                            }
                            if (column.scale() > 0) {
                                fieldMapper.scale = column.scale();
                            }
                            if (column.precision() > 0) {
                                fieldMapper.precision = column.precision();
                            }

                            if (!column.nullable()) {
                                fieldMapper.required = true;
                            }
                            break;
                        }

                        String fname = ObjectUtil.getName(annotation);
                        if (fname != null) {
                            names.add(fname);
                        }
                    }
                }

                // 10. Apply annotations from Oson
                if (fieldMapperAnnotation != null) {
                    fieldMapper = overwriteBy(fieldMapper, fieldMapperAnnotation, classMapper);
                }
            }

            if (ignored) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                continue;
            }

            // 11. Apply Java configuration for this particular field
            if (javaFieldMapper != null && javaFieldMapper.isDeserializing()) {
                fieldMapper = overwriteBy(fieldMapper, javaFieldMapper);
            }

            if (fieldMapper.ignore != null && fieldMapper.ignore) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                continue;
            }

            // in the ignored list
            if (ObjectUtil.inSet(name, classMapper.jsonIgnoreProperties)) {
                nameKeys.remove(name);
                continue;
            }

            if (fieldMapper.useAttribute != null && !fieldMapper.useAttribute) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                continue;
            }

            if (fieldMapper.jsonAnySetter != null && fieldMapper.jsonAnySetter && setter != null) {
                setters.remove(lcfieldName);
                otherMethods.put(lcfieldName, setter);
                continue;
            }

            if (fieldMapper.since != null && fieldMapper.since > getVersion()) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                continue;
            } else if (fieldMapper.until != null && fieldMapper.until <= getVersion()) {
                nameKeys.remove(name);
                nameKeys.remove(fieldMapper.json);
                continue;
            }

            // get value for name in map
            Object value = null;
            boolean jnameFixed = false;
            String json = fieldMapper.json;
            if (json == null) {
                continue;

            } else if (!json.equals(name)) {
                name = json;
                value = getMapValue(map, name, nameKeys);
                jnameFixed = true;
            }

            if (!jnameFixed) {
                for (String jsoname : names) {
                    if (!name.equals(jsoname) && !StringUtil.isEmpty(jsoname)) {
                        name = jsoname;
                        value = getMapValue(map, name, nameKeys);
                        jnameFixed = true;
                        break;
                    }
                }
            }

            if (!jnameFixed) {
                value = getMapValue(map, name, nameKeys);
                jnameFixed = true;
            }

            fieldMapper.java = fieldName;
            fieldMapper.json = name;

            if (value != null) {

                FieldData fieldData = new FieldData(obj, null, value, returnType, true, fieldMapper,
                        objectDTO.level, objectDTO.set);
                fieldData.setter = setter;
                Class fieldType = guessComponentType(fieldData);

                value = json2Object(fieldData);

                if (StringUtil.isNull(value)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_NULL
                            || classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                            || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;

                    }

                } else if (StringUtil.isEmpty(value)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                            || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;
                    }

                } else if (DefaultValue.isDefault(value, returnType)) {
                    if (classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                        continue;
                    }
                }

                ObjectUtil.setMethodValue(obj, setter, value);

                nameKeys.remove(name);
            }
        }

        if (annotationSupport) {
            //@JsonAnySetter
            if (nameKeys.size() > 0) {
                for (Entry<String, Method> entry : otherMethods.entrySet()) {
                    Method method = entry.getValue();

                    if (ignoreModifiers(method.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                        continue;
                    }

                    if (method.isAnnotationPresent(JsonAnySetter.class)) {
                        if (ignoreField(JsonAnySetter.class, classMapper.ignoreFieldsWithAnnotations)) {
                            continue;
                        }

                        jsonAnySetterMethod = method;

                    } else if (method.isAnnotationPresent(org.codehaus.jackson.annotate.JsonAnySetter.class)) {
                        if (ignoreField(org.codehaus.jackson.annotate.JsonAnySetter.class,
                                classMapper.ignoreFieldsWithAnnotations)) {
                            continue;
                        }

                        jsonAnySetterMethod = method;

                    } else if (method.isAnnotationPresent(ca.oson.json.annotation.FieldMapper.class)) {
                        ca.oson.json.annotation.FieldMapper annotation = (ca.oson.json.annotation.FieldMapper) method
                                .getAnnotation(ca.oson.json.annotation.FieldMapper.class);
                        if (annotation.jsonAnySetter() == BOOLEAN.TRUE) {
                            jsonAnySetterMethod = method;
                            break;
                        }
                    }
                }
            }
        }

        if (jsonAnySetterMethod != null) {
            Parameter[] parameters = jsonAnySetterMethod.getParameters();
            if (parameters != null && parameters.length == 2) {
                for (String name : nameKeys) {
                    Object value = map.get(name);

                    // json to java, check if this name is allowed or changed
                    String java = json2Java(name);

                    if (value != null && !StringUtil.isEmpty(java)) {
                        ObjectUtil.setMethodValue(obj, jsonAnySetterMethod, java, value);
                    }

                }
            }
        }

        return obj;

        // | InvocationTargetException
    } catch (IllegalArgumentException e) {
        e.printStackTrace();
    }

    return null;
}

From source file:ca.oson.json.Oson.java

private <E, R> String object2Serialize(FieldData objectDTO) {
    E obj = (E) objectDTO.valueToProcess;

    Class<R> valueType = objectDTO.returnType;

    if (obj == null) {
        return null;
    }/*w  w  w  .j av  a 2s .c om*/

    // it is possible the same object shared by multiple variables inside the same enclosing object
    int hash = ObjectUtil.hashCode(obj, valueType);
    if (!objectDTO.goAhead(hash)) {
        return "{}";
    }

    ClassMapper classMapper = objectDTO.classMapper;
    // first build up the class-level processing rules
    // || (objectDTO.level == 0 && objectDTO.fieldMapper == null)
    //if (classMapper == null) {
    // 1. Create a blank class mapper instance
    classMapper = new ClassMapper(valueType);

    // 2. Globalize it
    classMapper = globalize(classMapper);
    objectDTO.classMapper = classMapper;
    //}

    if (objectDTO.fieldMapper != null && isInheritMapping()) {
        classMapper = overwriteBy(classMapper, objectDTO.fieldMapper);
    }

    FIELD_NAMING format = getFieldNaming();

    String repeated = getPrettyIndentationln(objectDTO.level), pretty = getPrettySpace();
    objectDTO.incrLevel();
    String repeatedItem = getPrettyIndentationln(objectDTO.level);

    // @Expose
    Set<String> exposed = null;
    if (isUseGsonExpose()) {
        exposed = new HashSet<>();
    }

    boolean annotationSupport = getAnnotationSupport();
    Annotation[] annotations = null;

    if (annotationSupport) {
        annotations = valueType.getAnnotations();

        ca.oson.json.annotation.ClassMapper classMapperAnnotation = null;

        // 3. Apply annotations from other sources
        for (Annotation annotation : annotations) {
            if (ignoreClass(annotation)) {
                return null;
            }

            switch (annotation.annotationType().getName()) {
            case "ca.oson.json.annotation.ClassMapper":
                classMapperAnnotation = (ca.oson.json.annotation.ClassMapper) annotation;
                if (!(classMapperAnnotation.serialize() == BOOLEAN.BOTH
                        || classMapperAnnotation.serialize() == BOOLEAN.TRUE)) {
                    classMapperAnnotation = null;
                }
                break;

            case "ca.oson.json.annotation.ClassMappers":
                ca.oson.json.annotation.ClassMappers classMapperAnnotations = (ca.oson.json.annotation.ClassMappers) annotation;
                for (ca.oson.json.annotation.ClassMapper ann : classMapperAnnotations.value()) {
                    if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.TRUE) {
                        classMapperAnnotation = ann;
                        //break;
                    }
                }
                break;

            case "com.google.gson.annotations.Since":
                Since since = (Since) annotation;
                classMapper.since = since.value();
                break;

            case "com.google.gson.annotations.Until":
                Until until = (Until) annotation;
                classMapper.until = until.value();
                break;

            case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                String[] jsonnames = jsonIgnoreProperties.value();
                if (jsonnames != null && jsonnames.length > 0) {
                    if (classMapper.jsonIgnoreProperties == null) {
                        classMapper.jsonIgnoreProperties = new HashSet();
                    }

                    classMapper.jsonIgnoreProperties.addAll(Arrays.asList(jsonnames));
                }
                break;

            case "org.codehaus.jackson.annotate.JsonIgnoreProperties":
                org.codehaus.jackson.annotate.JsonIgnoreProperties jsonIgnoreProperties2 = (org.codehaus.jackson.annotate.JsonIgnoreProperties) annotation;
                String[] jsonnames2 = jsonIgnoreProperties2.value();
                if (jsonnames2 != null && jsonnames2.length > 0) {
                    if (classMapper.jsonIgnoreProperties == null) {
                        classMapper.jsonIgnoreProperties = new HashSet();
                    }

                    classMapper.jsonIgnoreProperties.addAll(Arrays.asList(jsonnames2));
                }
                break;

            case "com.fasterxml.jackson.annotation.JsonPropertyOrder":
                // first come first serve
                if (classMapper.propertyOrders == null) {
                    classMapper.propertyOrders = ((JsonPropertyOrder) annotation).value();
                }
                break;

            case "org.codehaus.jackson.annotate.JsonPropertyOrder":
                // first come first serve
                if (classMapper.propertyOrders == null) {
                    classMapper.propertyOrders = ((org.codehaus.jackson.annotate.JsonPropertyOrder) annotation)
                            .value();
                }
                break;

            case "com.fasterxml.jackson.annotation.JsonInclude":
                if (classMapper.defaultType == JSON_INCLUDE.NONE) {
                    JsonInclude jsonInclude = (JsonInclude) annotation;
                    switch (jsonInclude.content()) {
                    case ALWAYS:
                        classMapper.defaultType = JSON_INCLUDE.ALWAYS;
                        break;
                    case NON_NULL:
                        classMapper.defaultType = JSON_INCLUDE.NON_NULL;
                        break;
                    case NON_ABSENT:
                        classMapper.defaultType = JSON_INCLUDE.NON_NULL;
                        break;
                    case NON_EMPTY:
                        classMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                        break;
                    case NON_DEFAULT:
                        classMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                        break;
                    case USE_DEFAULTS:
                        classMapper.defaultType = JSON_INCLUDE.DEFAULT;
                        break;
                    }
                }
                break;

            case "com.fasterxml.jackson.annotation.JsonAutoDetect":
                JsonAutoDetect jsonAutoDetect = (JsonAutoDetect) annotation;
                if (jsonAutoDetect.fieldVisibility() == Visibility.NONE) {
                    classMapper.useField = false;
                }
                if (jsonAutoDetect.getterVisibility() == Visibility.NONE) {
                    classMapper.useAttribute = false;
                }
                break;

            case "org.codehaus.jackson.annotate.JsonAutoDetect":
                org.codehaus.jackson.annotate.JsonAutoDetect jsonAutoDetect2 = (org.codehaus.jackson.annotate.JsonAutoDetect) annotation;
                if (jsonAutoDetect2
                        .fieldVisibility() == org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE) {
                    classMapper.useField = false;
                }
                if (jsonAutoDetect2
                        .getterVisibility() == org.codehaus.jackson.annotate.JsonAutoDetect.Visibility.NONE) {
                    classMapper.useAttribute = false;
                }

                break;

            case "org.junit.Ignore":
                classMapper.ignore = true;
                break;
            }
        }

        // 4. Apply annotations from Oson
        if (classMapperAnnotation != null) {
            classMapper = overwriteBy(classMapper, classMapperAnnotation);
            exposed = null;
        }

    }

    // 5. Apply Java configuration for this particular class
    ClassMapper javaClassMapper = getClassMapper(valueType);
    if (javaClassMapper != null) {
        classMapper = overwriteBy(classMapper, javaClassMapper);
    }

    // now processing at the class level

    if (classMapper.ignore()) {
        return null;
    }

    if (classMapper.since != null && classMapper.since > getVersion()) {
        return null;
    } else if (classMapper.until != null && classMapper.until <= getVersion()) {
        return null;
    }

    Function function = classMapper.serializer; //getSerializer(valueType);
    if (function == null) {
        function = DeSerializerUtil.getSerializer(valueType.getName());
    }

    if (function != null) {
        try {
            Object returnValue = null;
            if (function instanceof DataMapper2JsonFunction) {
                DataMapper classData = new DataMapper(valueType, obj, classMapper, objectDTO.level,
                        getPrettyIndentation());
                objectDTO.jsonRawValue = false;
                DataMapper2JsonFunction f = (DataMapper2JsonFunction) function;

                return f.apply(classData);

            } else if (function instanceof FieldData2JsonFunction) {
                FieldData2JsonFunction f = (FieldData2JsonFunction) function;
                FieldData fieldData = objectDTO.clone();

                returnValue = f.apply(fieldData);

            } else {
                returnValue = function.apply(obj);
            }

            if (returnValue != null) {
                Class returnType = returnValue.getClass();

                if (returnType == String.class) {
                    return StringUtil.doublequote(returnValue, isEscapeHtml());

                } else if (returnType == valueType || valueType.isAssignableFrom(returnType)) {
                    // just continue to do the serializing
                } else {
                    objectDTO.valueToProcess = returnValue;
                    objectDTO.returnType = returnType;

                    return object2String(objectDTO);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    Set<Class> ignoreFieldsWithAnnotations = classMapper.ignoreFieldsWithAnnotations;

    Map<String, String> keyJsonStrings = new LinkedHashMap<>();
    // to hold relation between name and changed name
    Map<String, String> fieldNames = new LinkedHashMap<>();

    Set<String> processedNameSet = new HashSet<>();
    //StringBuffer sb = new StringBuffer();

    Map<String, Method> getters = null;
    Map<String, Method> setters = null;
    Map<String, Method> otherMethods = null;

    if (valueType.isInterface()) {
        valueType = (Class<R>) obj.getClass();
    } else if (Modifier.isAbstract(valueType.getModifiers())) {
        // valueType

    } else {
        //         Class objClass = obj.getClass();
        //         if (valueType.isAssignableFrom(objClass)) {
        //            valueType = objClass;
        //         }
    }

    //      if (valueType.isInterface()) {
    //         getters = getGetters(obj);
    //         setters = getSetters(obj);
    //         otherMethods = getOtherMethods(obj);
    //      } else {
    getters = getGetters(valueType);
    setters = getSetters(valueType);
    otherMethods = getOtherMethods(valueType);
    //      }

    Set<Method> jsonAnyGetterMethods = new HashSet<>();

    if (classMapper.isToStringAsSerializer()) {
        try {
            Method getter = valueType.getDeclaredMethod("toString", null);

            if (getter != null) {
                E getterValue = ObjectUtil.getMethodValue(obj, getter);

                if (getterValue != null) {
                    Class returnType = getterValue.getClass();

                    if (returnType == String.class) {
                        return StringUtil.doublequote(getterValue, isEscapeHtml());

                    } else if (returnType == valueType || valueType.isAssignableFrom(returnType)) {
                        // just continue to do the serializing
                    } else {
                        objectDTO.valueToProcess = getterValue;
                        objectDTO.returnType = returnType;

                        return object2String(objectDTO);
                    }
                }
            }

        } catch (NoSuchMethodException | SecurityException e) {
            // e.printStackTrace();
        }
    }

    //if (getters != null && getters.size() > 0) {
    boolean isJsonRawValue = false;
    String jsonValueFieldName = DeSerializerUtil.getJsonValueFieldName(valueType.getName());
    //         if (jsonValueFieldName == null) {
    //            // get all fieldmappers for this class?
    //            Set<FieldMapper> fieldMappers = getFieldMappers(valueType);
    //            // looking for the method
    //            for (FieldMapper fieldMapper: fieldMappers) {
    //               if (fieldMapper.jsonValue != null && fieldMapper.jsonValue) {
    //                  jsonValueFieldName = fieldMapper.java;
    //                  isJsonRawValue = fieldMapper.isJsonRawValue();
    //                  break;
    //               }
    //            }
    //         }
    if (jsonValueFieldName == null) {
        jsonValueFieldName = classMapper.getJsonValueFieldName();
    }

    if (jsonValueFieldName != null) {
        String lcjava = jsonValueFieldName.toLowerCase();
        Method getter = null;
        if (getters != null && getters.containsKey(lcjava)) {
            getter = getters.get(lcjava);

        } else {
            try {
                getter = valueType.getMethod(jsonValueFieldName);
            } catch (NoSuchMethodException | SecurityException e) {
                // e.printStackTrace();
            }

            if (getter == null) {
                try {
                    getter = valueType.getMethod("get" + StringUtil.capitalize(jsonValueFieldName));
                } catch (NoSuchMethodException | SecurityException e) {
                    //e.printStackTrace();
                }
            }
        }

        if (getter != null) {
            E getterValue = ObjectUtil.getMethodValue(obj, getter);

            if (getterValue != null) {
                Class returnType = getterValue.getClass();

                if (returnType == String.class) {
                    if (isJsonRawValue) {
                        return getterValue.toString();

                    } else if (StringUtil.parenthesized(getterValue.toString())) {
                        return getterValue.toString();

                    } else {
                        return StringUtil.doublequote(getterValue, isEscapeHtml());
                    }

                } else if (returnType == valueType || valueType.isAssignableFrom(returnType)) {
                    // just continue to do the serializing
                } else {
                    objectDTO.valueToProcess = getterValue;
                    objectDTO.returnType = returnType;
                    objectDTO.jsonRawValue = isJsonRawValue;

                    return object2String(objectDTO);
                }
            }
        }
    }
    //}

    try {
        Field[] fields = null;
        //         if (valueType.isInterface()) {
        //            fields = getFields(obj);
        //         } else {
        fields = getFields(valueType);
        //         }

        for (Field f : fields) {
            f.setAccessible(true);

            String name = f.getName();
            String fieldName = name;
            String lcfieldName = fieldName.toLowerCase();

            if (Modifier.isFinal(f.getModifiers()) && Modifier.isStatic(f.getModifiers())) {
                getters.remove(lcfieldName);
                continue;
            }

            // 6. Create a blank field mapper instance
            FieldMapper fieldMapper = new FieldMapper(name, name, valueType);

            Class<?> returnType = f.getType(); // value.getClass();

            // 7. get the class mapper of returnType
            ClassMapper fieldClassMapper = getClassMapper(returnType);

            // 8. Classify this field mapper with returnType
            fieldMapper = classifyFieldMapper(fieldMapper, fieldClassMapper);

            // 9. Classify this field mapper
            fieldMapper = classifyFieldMapper(fieldMapper, classMapper);

            FieldMapper javaFieldMapper = getFieldMapper(name, null, valueType);

            // getter and setter methods
            Method getter = getters.get(lcfieldName);
            Method setter = setters.get(lcfieldName);

            if (getter != null) {
                getter.setAccessible(true);
            }

            // control by visibility is not always a good idea
            // here consider the visibility of field and related getter method together
            if (ignoreModifiers(f.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                if (getter != null) {
                    if (ignoreModifiers(getter.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                        getters.remove(lcfieldName);
                        continue;
                    }
                } else {
                    continue;
                }
            }

            boolean ignored = false;
            Set<String> names = new HashSet<>();

            if (annotationSupport) {
                annotations = f.getDeclaredAnnotations();//.getAnnotations();

                // field and getter should be treated the same way, if allowed in the class level
                // might not be 100% correct, as the useAttribute as not be applied from annotations yet
                //  && ((javaFieldMapper == null || javaFieldMapper.useAttribute == null) && (fieldMapper.useAttribute == null || fieldMapper.useAttribute))
                // || (javaFieldMapper != null && javaFieldMapper.useAttribute != null && javaFieldMapper.useAttribute)
                // annotations might apply to method only, not the field, so need to get them, regardless using attribute or not
                if (getter != null) {
                    annotations = Stream
                            .concat(Arrays.stream(annotations), Arrays.stream(getter.getDeclaredAnnotations()))
                            .toArray(Annotation[]::new);

                    // no annotations, then try set method
                    if ((annotations == null || annotations.length == 0) && setter != null) {
                        annotations = setter.getDeclaredAnnotations();
                    }
                }

                ca.oson.json.annotation.FieldMapper fieldMapperAnnotation = null;

                for (Annotation annotation : annotations) {
                    if (ignoreField(annotation, ignoreFieldsWithAnnotations)) {
                        ignored = true;
                        break;

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                        fieldMapperAnnotation = (ca.oson.json.annotation.FieldMapper) annotation;
                        if (!(fieldMapperAnnotation.serialize() == BOOLEAN.BOTH
                                || fieldMapperAnnotation.serialize() == BOOLEAN.TRUE)) {
                            fieldMapperAnnotation = null;
                        }

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMappers) {
                        ca.oson.json.annotation.FieldMappers fieldMapperAnnotations = (ca.oson.json.annotation.FieldMappers) annotation;
                        for (ca.oson.json.annotation.FieldMapper ann : fieldMapperAnnotations.value()) {
                            if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.TRUE) {
                                fieldMapperAnnotation = ann;
                                //break;
                            }
                        }

                    } else {
                        // to improve performance, using swith on string
                        switch (annotation.annotationType().getName()) {

                        case "com.fasterxml.jackson.annotation.JsonAnyGetter":
                        case "org.codehaus.jackson.annotate.JsonAnyGetter":
                            fieldMapper.jsonAnyGetter = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnore":
                        case "org.codehaus.jackson.annotate.JsonIgnore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.persistence.Transient":
                            ignored = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                            JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                            if (!jsonIgnoreProperties.allowGetters()) {
                                fieldMapper.ignore = true;
                            } else {
                                fieldMapper.ignore = false;
                                classMapper.jsonIgnoreProperties.remove(name);
                            }
                            break;

                        case "com.google.gson.annotations.Expose":
                            Expose expose = (Expose) annotation;
                            if (!expose.serialize()) {
                                fieldMapper.ignore = true;
                            } else if (exposed != null) {
                                exposed.add(lcfieldName);
                            }
                            break;

                        case "com.google.gson.annotations.Since":
                            Since since = (Since) annotation;
                            fieldMapper.since = since.value();
                            break;

                        case "com.google.gson.annotations.Until":
                            Until until = (Until) annotation;
                            fieldMapper.until = until.value();
                            break;

                        case "com.fasterxml.jackson.annotation.JsonInclude":
                            if (fieldMapper.defaultType == JSON_INCLUDE.NONE) {
                                JsonInclude jsonInclude = (JsonInclude) annotation;

                                switch (jsonInclude.content()) {
                                case ALWAYS:
                                    fieldMapper.defaultType = JSON_INCLUDE.ALWAYS;
                                    break;
                                case NON_NULL:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_ABSENT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_EMPTY:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                                    break;
                                case NON_DEFAULT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                                    break;
                                case USE_DEFAULTS:
                                    fieldMapper.defaultType = JSON_INCLUDE.DEFAULT;
                                    break;
                                }
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonRawValue":
                            if (((JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.codehaus.jackson.annotate.JsonRawValue":
                            if (((org.codehaus.jackson.annotate.JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonValue":
                        case "org.codehaus.jackson.annotate.JsonValue":
                            fieldMapper.jsonValue = true;
                            break;

                        case "org.junit.Ignore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.persistence.Enumerated":
                            fieldMapper.enumType = ((Enumerated) annotation).value();
                            break;

                        //                  case "javax.persistence.MapKeyEnumerated":
                        //                     mapper.enumType = ((javax.persistence.MapKeyEnumerated) annotation).value();
                        //                     break;

                        case "javax.validation.constraints.NotNull":
                            fieldMapper.required = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonProperty":
                            JsonProperty jsonProperty = (JsonProperty) annotation;
                            Access access = jsonProperty.access();
                            if (access == Access.WRITE_ONLY) {
                                fieldMapper.ignore = true;
                                break;
                            }

                            if (jsonProperty.required()) {
                                fieldMapper.required = true;
                            }

                            if (jsonProperty.defaultValue() != null
                                    && jsonProperty.defaultValue().length() > 0) {
                                fieldMapper.defaultValue = jsonProperty.defaultValue();
                            }
                            break;

                        case "javax.validation.constraints.Size":
                            Size size = (Size) annotation;
                            if (size.min() > 0) {
                                fieldMapper.min = (long) size.min();
                            }
                            if (size.max() < Integer.MAX_VALUE) {
                                fieldMapper.max = (long) size.max();
                            }
                            break;

                        case "javax.persistence.Column":
                            Column column = (Column) annotation;
                            if (column.length() != 255) {
                                fieldMapper.length = column.length();
                            }
                            if (column.scale() > 0) {
                                fieldMapper.scale = column.scale();
                            }

                            if (column.precision() > 0) {
                                fieldMapper.precision = column.precision();
                            }

                            if (!column.nullable()) {
                                fieldMapper.required = true;
                            }

                            break;
                        }

                        String fname = ObjectUtil.getName(annotation);
                        if (!StringUtil.isEmpty(fname)) {
                            names.add(fname);
                        }
                    }
                }

                // 10. Apply annotations from Oson
                // special name to handle
                if (fieldMapperAnnotation != null) {
                    fieldMapper = overwriteBy(fieldMapper, fieldMapperAnnotation, classMapper);
                    exposed = null;
                }
            }

            if (ignored) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            // 11. Apply Java configuration for this particular field
            if (javaFieldMapper != null && javaFieldMapper.isSerializing()) {
                fieldMapper = overwriteBy(fieldMapper, javaFieldMapper);
            }

            if (fieldMapper.ignore != null && fieldMapper.ignore) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            // in the ignored list
            if (ObjectUtil.inSet(name, classMapper.jsonIgnoreProperties)) {
                getters.remove(lcfieldName);
                continue;
            }

            if (fieldMapper.jsonAnyGetter != null && fieldMapper.jsonAnyGetter && getter != null) {
                getters.remove(lcfieldName);
                jsonAnyGetterMethods.add(getter);
                continue;
            }

            if (fieldMapper.useField != null && !fieldMapper.useField) {
                // both should not be used, just like ignore
                if (fieldMapper.useAttribute != null && !fieldMapper.useAttribute) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            if (fieldMapper.since != null && fieldMapper.since > getVersion()) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            } else if (fieldMapper.until != null && fieldMapper.until <= getVersion()) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            //jsonIgnoreProperties

            // handling name now
            boolean jnameFixed = false;
            String json = fieldMapper.json;
            if (StringUtil.isEmpty(json)) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;

            } else if (!json.equals(name)) {
                name = json;
                jnameFixed = true;
            }

            if (!jnameFixed) {
                for (String jsoname : names) {
                    if (!name.equals(jsoname) && !StringUtil.isEmpty(jsoname)) {
                        name = jsoname;
                        jnameFixed = true;
                        break;
                    }
                }
            }

            // only if the name is still the same as the field name
            // format it based on the naming settings
            // otherwise, it is set on purpose
            if (fieldName.equals(name)) {
                name = StringUtil.formatName(name, format);
                jnameFixed = true;
            }

            fieldMapper.java = fieldName;
            fieldMapper.json = name;

            // field valuie
            E value = null;
            try {
                value = (E) f.get(obj);// ObjectUtil.unwraponce(f.get(obj));
            } catch (Exception e) {
            }

            if (value != null) {
                Class vtype = value.getClass();
                if (returnType.isAssignableFrom(vtype)) {
                    returnType = vtype;
                }
            }

            // value from getter
            E getterValue = null;

            if (getter != null) {
                if (fieldMapper.useAttribute == null || fieldMapper.useAttribute) {
                    getterValue = ObjectUtil.getMethodValue(obj, getter);
                    //getterValue = ObjectUtil.unwraponce(getterValue);
                }

                getters.remove(lcfieldName);
            }

            // determine which value to use
            if (getterValue != null) {
                if (getterValue.equals(value) || StringUtil.isEmpty(value)) {
                    value = getterValue;

                } else if (DefaultValue.isDefault(value, returnType)
                        && !DefaultValue.isDefault(getterValue, returnType)) {
                    value = getterValue;
                }
                //               else if (getterValue.toString().length() > value.toString().length()) {
                //                  value = getterValue;
                //               }
            }

            String str;

            FieldData fieldData = new FieldData(obj, f, value, returnType, false, fieldMapper, objectDTO.level,
                    objectDTO.set);

            str = object2Json(fieldData);

            if (fieldMapper.jsonValue != null && fieldMapper.jsonValue) {
                if (fieldMapper.isJsonRawValue()) {
                    return StringUtil.unquote(str, isEscapeHtml());
                } else {
                    return StringUtil.doublequote(str, isEscapeHtml());
                }
            }

            if (StringUtil.isNull(str)) {
                if (fieldMapper.defaultType == JSON_INCLUDE.NON_NULL
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                    continue;

                } else {
                    str = "null";
                }

            } else if (StringUtil.isEmpty(str)) {
                if (fieldMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                    continue;
                }

                str = "\"\"";

            } else if (fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT
                    && DefaultValue.isDefault(str, returnType)) {
                continue;
            }

            StringBuffer sb = new StringBuffer();
            sb.append(repeatedItem);
            if (fieldMapper.jsonNoName == null || !fieldMapper.jsonNoName) {
                sb.append("\"" + name + "\":" + pretty);
            }
            sb.append(str);
            sb.append(",");

            keyJsonStrings.put(lcfieldName, sb.toString());
            processedNameSet.add(name);
            fieldNames.put(lcfieldName, name.toLowerCase());
        }

        // now process get methods
        for (Entry<String, Method> entry : getters.entrySet()) {
            String lcfieldName = entry.getKey();
            Method getter = entry.getValue();

            if (ignoreModifiers(getter.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                continue;
            }
            if (Modifier.isFinal(getter.getModifiers()) && Modifier.isStatic(getter.getModifiers())) {
                continue;
            }

            String name = getter.getName();
            if (name.substring(3).equalsIgnoreCase(lcfieldName)) {
                name = StringUtil.uncapitalize(name.substring(3));
            }

            // just use field name, even it might not be a field
            String fieldName = name;

            if (processedNameSet.contains(name) || fieldNames.containsKey(lcfieldName)) {
                continue;
            }

            getter.setAccessible(true);

            Method setter = setters.get(lcfieldName);

            // 6. Create a blank field mapper instance
            FieldMapper fieldMapper = new FieldMapper(name, name, valueType);

            Class<?> returnType = getter.getReturnType();

            // 7. get the class mapper of returnType
            ClassMapper fieldClassMapper = getClassMapper(returnType);

            // 8. Classify this field mapper with returnType
            fieldMapper = classifyFieldMapper(fieldMapper, fieldClassMapper);

            // 9. Classify this field mapper
            fieldMapper = classifyFieldMapper(fieldMapper, classMapper);

            FieldMapper javaFieldMapper = getFieldMapper(name, null, valueType);

            boolean ignored = false;
            Set<String> names = new HashSet<>();

            if (annotationSupport) {
                annotations = getter.getDeclaredAnnotations();//.getAnnotations();

                // no annotations, then try set method
                if ((annotations == null || annotations.length == 0) && setter != null) {
                    annotations = setter.getDeclaredAnnotations();
                }

                ca.oson.json.annotation.FieldMapper fieldMapperAnnotation = null;

                for (Annotation annotation : annotations) {
                    if (ignoreField(annotation, ignoreFieldsWithAnnotations)) {
                        ignored = true;
                        break;

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                        fieldMapperAnnotation = (ca.oson.json.annotation.FieldMapper) annotation;
                        if (!(fieldMapperAnnotation.serialize() == BOOLEAN.BOTH
                                || fieldMapperAnnotation.serialize() == BOOLEAN.TRUE)) {
                            fieldMapperAnnotation = null;
                        }

                    } else if (annotation instanceof ca.oson.json.annotation.FieldMappers) {
                        ca.oson.json.annotation.FieldMappers fieldMapperAnnotations = (ca.oson.json.annotation.FieldMappers) annotation;
                        for (ca.oson.json.annotation.FieldMapper ann : fieldMapperAnnotations.value()) {
                            if (ann.serialize() == BOOLEAN.BOTH || ann.serialize() == BOOLEAN.TRUE) {
                                fieldMapperAnnotation = ann;
                                //break;
                            }
                        }

                    } else {
                        // to improve performance, using swith on string
                        switch (annotation.annotationType().getName()) {
                        case "com.fasterxml.jackson.annotation.JsonAnyGetter":
                        case "org.codehaus.jackson.annotate.JsonAnyGetter":
                            fieldMapper.jsonAnyGetter = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnore":
                        case "org.codehaus.jackson.annotate.JsonIgnore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.persistence.Transient":
                            ignored = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonIgnoreProperties":
                            JsonIgnoreProperties jsonIgnoreProperties = (JsonIgnoreProperties) annotation;
                            if (!jsonIgnoreProperties.allowGetters()) {
                                fieldMapper.ignore = true;
                            } else {
                                fieldMapper.ignore = false;
                                classMapper.jsonIgnoreProperties.remove(name);
                            }
                            break;

                        case "com.google.gson.annotations.Expose":
                            Expose expose = (Expose) annotation;
                            if (!expose.serialize()) {
                                fieldMapper.ignore = true;
                            } else if (exposed != null) {
                                exposed.add(lcfieldName);
                            }
                            break;

                        case "com.google.gson.annotations.Since":
                            Since since = (Since) annotation;
                            fieldMapper.since = since.value();
                            break;

                        case "com.google.gson.annotations.Until":
                            Until until = (Until) annotation;
                            fieldMapper.until = until.value();
                            break;

                        case "com.fasterxml.jackson.annotation.JsonInclude":
                            if (fieldMapper.defaultType == JSON_INCLUDE.NONE) {
                                JsonInclude jsonInclude = (JsonInclude) annotation;

                                switch (jsonInclude.content()) {
                                case ALWAYS:
                                    fieldMapper.defaultType = JSON_INCLUDE.ALWAYS;
                                    break;
                                case NON_NULL:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_ABSENT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_NULL;
                                    break;
                                case NON_EMPTY:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_EMPTY;
                                    break;
                                case NON_DEFAULT:
                                    fieldMapper.defaultType = JSON_INCLUDE.NON_DEFAULT;
                                    break;
                                case USE_DEFAULTS:
                                    fieldMapper.defaultType = JSON_INCLUDE.DEFAULT;
                                    break;
                                }
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonRawValue":
                            if (((JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "org.codehaus.jackson.annotate.JsonRawValue":
                            if (((org.codehaus.jackson.annotate.JsonRawValue) annotation).value()) {
                                fieldMapper.jsonRawValue = true;
                            }
                            break;

                        case "com.fasterxml.jackson.annotation.JsonValue":
                        case "org.codehaus.jackson.annotate.JsonValue":
                            fieldMapper.jsonValue = true;
                            break;

                        case "javax.persistence.Enumerated":
                            fieldMapper.enumType = ((Enumerated) annotation).value();
                            break;

                        //                  case "javax.persistence.MapKeyEnumerated":
                        //                     mapper.enumType = ((javax.persistence.MapKeyEnumerated) annotation).value();
                        //                     break;

                        case "javax.validation.constraints.NotNull":
                            fieldMapper.required = true;
                            break;

                        case "com.fasterxml.jackson.annotation.JsonProperty":
                            JsonProperty jsonProperty = (JsonProperty) annotation;
                            Access access = jsonProperty.access();
                            if (access == Access.WRITE_ONLY) {
                                fieldMapper.ignore = true;
                                break;
                            }

                            if (jsonProperty.required()) {
                                fieldMapper.required = true;
                            }

                            if (jsonProperty.defaultValue() != null
                                    && jsonProperty.defaultValue().length() > 0) {
                                fieldMapper.defaultValue = jsonProperty.defaultValue();
                            }
                            break;

                        case "org.junit.Ignore":
                            fieldMapper.ignore = true;
                            break;

                        case "javax.validation.constraints.Size":
                            Size size = (Size) annotation;
                            if (size.min() > 0) {
                                fieldMapper.min = (long) size.min();
                            }
                            if (size.max() < Integer.MAX_VALUE) {
                                fieldMapper.max = (long) size.max();
                            }
                            break;

                        case "javax.persistence.Column":
                            Column column = (Column) annotation;
                            if (column.length() != 255) {
                                fieldMapper.length = column.length();
                            }
                            if (column.scale() > 0) {
                                fieldMapper.scale = column.scale();
                            }

                            if (column.precision() > 0) {
                                fieldMapper.precision = column.precision();
                            }

                            if (!column.nullable()) {
                                fieldMapper.required = true;
                            }

                            break;
                        }

                        String fname = ObjectUtil.getName(annotation);
                        if (fname != null) {
                            names.add(fname);
                        }
                    }
                }

                // 10. Apply annotations from Oson
                // special name to handle
                if (fieldMapperAnnotation != null) {
                    fieldMapper = overwriteBy(fieldMapper, fieldMapperAnnotation, classMapper);
                    exposed = null;
                }
            }

            if (ignored) {
                continue;
            }

            // 11. Apply Java configuration for this particular field
            if (javaFieldMapper != null && javaFieldMapper.isSerializing()) {
                fieldMapper = overwriteBy(fieldMapper, javaFieldMapper);
            }

            if (fieldMapper.ignore != null && fieldMapper.ignore) {
                continue;
            }

            // in the ignored list
            if (ObjectUtil.inSet(name, classMapper.jsonIgnoreProperties)) {
                continue;
            }

            if (fieldMapper.jsonAnyGetter != null && fieldMapper.jsonAnyGetter) {
                jsonAnyGetterMethods.add(getter);
                continue;
            }

            if (fieldMapper.useAttribute != null && !fieldMapper.useAttribute) {
                continue;
            }

            if (fieldMapper.since != null && fieldMapper.since > getVersion()) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            } else if (fieldMapper.until != null && fieldMapper.until <= getVersion()) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;
            }

            // handling name now
            boolean jnameFixed = false;
            String json = fieldMapper.json;
            if (StringUtil.isEmpty(json)) {
                if (getter != null) {
                    getters.remove(lcfieldName);
                }
                continue;

            } else if (!json.equals(name)) {
                name = json;
                jnameFixed = true;
            }

            if (!jnameFixed) {
                for (String jsoname : names) {
                    if (!name.equals(jsoname) && !StringUtil.isEmpty(jsoname)) {
                        name = jsoname;
                        jnameFixed = true;
                        break;
                    }
                }
            }

            // only if the name is still the same as the field name
            // format it based on the naming settings
            // otherwise, it is set on purpose
            if (fieldName.equals(name)) {
                name = StringUtil.formatName(name, format);
                jnameFixed = true;
            }

            fieldMapper.java = fieldName;
            fieldMapper.json = name;

            // get value
            E value = ObjectUtil.getMethodValue(obj, getter);

            if (fieldMapper.jsonValue != null && fieldMapper.jsonValue) {
                if (value != null) {
                    if (fieldMapper.isJsonRawValue()) {
                        return value.toString();
                    } else {
                        return StringUtil.doublequote(value, isEscapeHtml());
                    }
                }
            }

            if (returnType == Class.class) {
                if (value != null && returnType != value.getClass()) {
                    returnType = value.getClass();
                } else {
                    continue;
                }
            }

            String str = null;

            //if (returnType != valueType) {
            FieldData fieldData = new FieldData(obj, null, value, returnType, false, fieldMapper,
                    objectDTO.level, objectDTO.set);
            objectDTO.getter = getter;
            str = object2Json(fieldData);
            //}

            if (StringUtil.isNull(str)) {
                if (fieldMapper.defaultType == JSON_INCLUDE.NON_NULL
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                    continue;

                } else {
                    str = "null";
                }

            } else if (StringUtil.isEmpty(str)) {
                if (fieldMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                        || fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                    continue;
                }

                str = "null";

            } else if (fieldMapper.defaultType == JSON_INCLUDE.NON_DEFAULT
                    && DefaultValue.isDefault(str, returnType)) {
                continue;
            }

            StringBuffer sb = new StringBuffer();
            sb.append(repeatedItem);
            if (fieldMapper.jsonNoName == null || !fieldMapper.jsonNoName) {
                sb.append("\"" + name + "\":" + pretty);
            }
            sb.append(str);
            sb.append(",");

            keyJsonStrings.put(lcfieldName, sb.toString());
            processedNameSet.add(name);
            fieldNames.put(lcfieldName, name.toLowerCase());
        }

        // handle @JsonAnyGetter
        if (annotationSupport) {
            for (Entry<String, Method> entry : otherMethods.entrySet()) {
                Method method = entry.getValue();
                if (ignoreModifiers(method.getModifiers(), classMapper.includeFieldsWithModifiers)) {
                    continue;
                }

                for (Annotation annotation : method.getAnnotations()) {
                    if (ignoreField(annotation, ignoreFieldsWithAnnotations)) {
                        continue;
                    }

                    if (annotation instanceof JsonValue
                            || annotation instanceof org.codehaus.jackson.annotate.JsonValue) {
                        Object mvalue = ObjectUtil.getMethodValue(obj, method);
                        if (mvalue != null) {
                            return StringUtil.doublequote(mvalue, isEscapeHtml());
                        }

                    } else if (annotation instanceof JsonAnyGetter
                            || annotation instanceof org.codehaus.jackson.annotate.JsonAnyGetter
                            || annotation instanceof ca.oson.json.annotation.FieldMapper) {

                        if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                            ca.oson.json.annotation.FieldMapper fieldMapper = (ca.oson.json.annotation.FieldMapper) annotation;

                            if (fieldMapper.jsonAnyGetter() == BOOLEAN.FALSE) {
                                continue;
                            }
                        }

                        jsonAnyGetterMethods.add(method);
                    }
                }
            }
        }

        for (Method method : jsonAnyGetterMethods) {
            if (method != null) {
                Object allValues = ObjectUtil.getMethodValue(obj, method);

                if (allValues != null && allValues instanceof Map) {
                    Map<String, Object> map = (Map) allValues;
                    String str;
                    for (String name : map.keySet()) {
                        Object value = map.get(name);

                        // java to json, check if this name is allowed or changed
                        name = java2Json(name);

                        if (!StringUtil.isEmpty(name)) {

                            FieldData newFieldData = new FieldData(value, value.getClass(), false,
                                    objectDTO.level, objectDTO.set);
                            newFieldData.defaultType = classMapper.defaultType;
                            str = object2Json(newFieldData);

                            if (StringUtil.isNull(str)) {
                                if (classMapper.defaultType == JSON_INCLUDE.NON_NULL
                                        || classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                                        || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                                    continue;

                                } else {
                                    str = "null";
                                }

                            } else if (StringUtil.isEmpty(str)) {
                                if (classMapper.defaultType == JSON_INCLUDE.NON_EMPTY
                                        || classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                                    continue;
                                }

                                str = "null";

                            } else if (DefaultValue.isDefault(str, value.getClass())) {
                                if (classMapper.defaultType == JSON_INCLUDE.NON_DEFAULT) {
                                    continue;
                                }
                            }

                            StringBuffer sb = new StringBuffer();
                            sb.append(repeatedItem);
                            sb.append("\"" + name + "\":" + pretty);
                            sb.append(str);
                            sb.append(",");
                            keyJsonStrings.put(name, sb.toString());
                        }
                    }
                }
            }
        }

        int size = keyJsonStrings.size();
        if (size == 0) {
            return "{}"; // ""

        } else {
            String includeClassType = "";
            if (classMapper.includeClassTypeInJson) { //getIncludeClassTypeInJson()
                includeClassType = repeatedItem + "\"@class\":" + pretty + "\"" + valueType.getName() + "\",";
            }

            if (exposed != null && exposed.size() > 0) {
                Map<String, String> map = new LinkedHashMap<>();

                for (String key : keyJsonStrings.keySet()) {
                    if (exposed.contains(key)) {
                        map.put(key, keyJsonStrings.get(key));
                    }
                }

                keyJsonStrings = map;
            }

            if (keyJsonStrings.size() == 1 && this.isValueOnly()) {
                for (Map.Entry<String, String> entry : keyJsonStrings.entrySet()) {
                    if (entry.getKey().toLowerCase().equals("value")) {
                        String value = entry.getValue();
                        String[] values = value.split(":");
                        value = null;
                        if (values.length == 1) {
                            value = values[0];
                        } else if (values.length == 2) {
                            value = values[1];
                        }
                        if (value != null && value.length() > 1) {
                            return value.substring(0, value.length() - 1);
                        }
                    }
                }
            }

            // based on sorting requirements
            StringBuffer sb = new StringBuffer();
            if (classMapper.propertyOrders != null) {
                for (String property : classMapper.propertyOrders) {
                    property = property.toLowerCase();
                    String jsonText = keyJsonStrings.get(property);
                    if (jsonText != null) {
                        sb.append(jsonText);
                        keyJsonStrings.remove(property);
                    } else {
                        property = fieldNames.get(property);
                        if (property != null && keyJsonStrings.containsKey(property)) {
                            sb.append(keyJsonStrings.get(property));
                            keyJsonStrings.remove(property);
                        }
                    }
                }
            }

            List<String> properties = new ArrayList(keyJsonStrings.keySet());
            if (classMapper.orderByKeyAndProperties) {
                Collections.sort(properties);
            }

            for (String property : properties) {
                sb.append(keyJsonStrings.get(property));
            }

            String text = sb.toString();
            size = text.length();
            if (size == 0) {
                return "{}";
            } else {
                return "{" + includeClassType + text.substring(0, size - 1) + repeated + "}";
            }
        }

    } catch (IllegalArgumentException | SecurityException e) {
        e.printStackTrace();
        throw new RuntimeException(e);
        // } catch (InvocationTargetException e) {
    }
}