Example usage for java.lang.reflect Method getModifiers

List of usage examples for java.lang.reflect Method getModifiers

Introduction

In this page you can find the example usage for java.lang.reflect Method getModifiers.

Prototype

@Override
public int getModifiers() 

Source Link

Usage

From source file:edu.ku.brc.specify.tasks.subpane.wb.wbuploader.UploadTable.java

private Vector<Method> getGetters() {
    Method[] methods = tblClass.getMethods();
    Vector<Method> result = new Vector<Method>();
    for (Method m : methods) {
        if (m.getName().startsWith("get") && m.getParameterTypes().length == 0
                && m.getReturnType() != void.class && Modifier.isPublic(m.getModifiers())
                && !Modifier.isTransient(m.getModifiers()) && !Modifier.isStatic(m.getModifiers())
                && !Modifier.isAbstract(m.getModifiers())) {
            Annotation jc = m.getAnnotation(javax.persistence.Column.class);
            Annotation c = m.getAnnotation(javax.persistence.JoinColumn.class);
            Annotation otm = m.getAnnotation(javax.persistence.OneToMany.class);
            if (otm == null && (jc != null || c != null || m.getName().equalsIgnoreCase("getId"))) {
                result.add(m);//from   ww  w  .j  ava2  s.  c o  m
            }

        }
    }
    return result;
}

From source file:gov.nih.nci.security.dao.AuthorizationDAOImpl.java

public Object secureObject(String userName, Object obj) throws CSException {
    Object o = null;//from   w  w w  . jav a 2 s  .  c o  m
    if (StringUtilities.isBlank(userName)) {
        throw new CSException("No user name have been supplied!");
    }
    if (obj == null) {
        return obj;
    }
    Field[] fields = obj.getClass().getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
        if (fields[i].getType().isPrimitive())
            throw new CSException("The Object to be secured does not follow Java Bean Specification");
    }
    try {

        Class cl = obj.getClass();
        log.debug(cl.getName());
        ObjectAccessMap accessMap = this.getObjectAccessMap(cl.getName(), userName, "READ");

        log.debug(accessMap.toString());

        o = cl.newInstance();
        Method methods[] = cl.getDeclaredMethods();

        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];

            String name = m.getName();
            //log.debug("Name from outer block"+name);
            //log.debug("Para type"+m.getParameterTypes());
            if (name.startsWith("set") && (m.getModifiers() == Modifier.PUBLIC)) {
                String att = name.substring(3, name.length());
                String methodName = "get" + att;
                //log.debug(methodName);
                Method m2 = cl.getMethod(methodName, (Class[]) null);
                //log.debug("Method Name m2"+m2.getName());
                //log.debug(m2.invoke(obj,null));
                if (!accessMap.hasAccess(att)) {
                    m.invoke(o, new Object[] { null });
                } else {
                    m.invoke(o, new Object[] { m2.invoke(obj, (Object[]) null) });
                }
            }
        }

    } catch (Exception ex) {
        if (log.isDebugEnabled())
            log.debug("Authorization||" + userName + "|secureObject|Failure|Error in Secure Object|"
                    + ex.getMessage());

        throw new CSException("Failed to secure the object:" + ex.getMessage(), ex);
    }

    return o;

}

From source file:gov.nih.nci.security.dao.AuthorizationDAOImpl.java

public Collection secureCollection(String userName, Collection collection) throws CSException {
    ArrayList result = new ArrayList();
    if (collection.size() == 0) {
        return collection;
    }//ww w .jav a2s . c o  m
    if (StringUtilities.isBlank(userName)) {
        throw new CSException("No userName have been supplied!");
    }
    try {
        Iterator it = collection.iterator();
        List l = (List) collection;
        Object obj_ = (Object) l.get(0);

        Class cl = obj_.getClass();
        log.debug(cl.getName());
        ObjectAccessMap accessMap = this.getObjectAccessMap(cl.getName(), userName, "READ");
        while (it.hasNext()) {
            Object obj = (Object) it.next();
            Object o = cl.newInstance();
            Method methods[] = cl.getDeclaredMethods();

            for (int i = 0; i < methods.length; i++) {
                Method m = methods[i];

                String name = m.getName();
                //log.debug("Name from outer block"+name);
                //log.debug("Para type"+m.getParameterTypes());
                if (name.startsWith("set") && (m.getModifiers() == Modifier.PUBLIC)) {
                    String att = name.substring(3, name.length());
                    String methodName = "get" + att;
                    //log.debug(methodName);
                    Method m2 = cl.getMethod(methodName, (Class[]) null);
                    //log.debug("Method Name m2"+m2.getName());
                    //log.debug(m2.invoke(obj,null));
                    if (!accessMap.hasAccess(att)) {
                        m.invoke(o, new Object[] { null });
                    } else {
                        m.invoke(o, new Object[] { m2.invoke(obj, (Object[]) null) });
                    }
                }
            }
            result.add(o);
        }

    } catch (Exception ex) {
        if (log.isDebugEnabled())
            log.debug("Authorization||" + userName + "|secureCollection|Failure|Error in Secure Collection|"
                    + ex.getMessage());

        throw new CSException("Failed to secure Collection:" + ex.getMessage(), ex);
    }

    return result;

}

From source file:gov.nih.nci.security.dao.AuthorizationDAOImpl.java

public Object secureUpdate(String userName, Object originalObject, Object mutatedObject) throws CSException {
    //Object o = null;
    if (StringUtilities.isBlank(userName)) {
        throw new CSException("No user name have been supplied!");
    }//  w  ww .ja  v  a  2 s  .c om
    if (originalObject == null || mutatedObject == null) {
        return originalObject;
    }
    try {

        Class cl = originalObject.getClass();
        log.debug(cl.getName());
        ObjectAccessMap accessMap = this.getObjectAccessMap(cl.getName(), userName, "UPDATE");

        //o = cl.newInstance();
        Method methods[] = cl.getDeclaredMethods();

        for (int i = 0; i < methods.length; i++) {
            Method m = methods[i];

            String name = m.getName();
            log.debug("Method is: " + name);
            //log.debug("Name from outer block"+name);
            //log.debug("Para type"+m.getParameterTypes());
            if (name.startsWith("set") && (m.getModifiers() == Modifier.PUBLIC)) {
                String att = name.substring(3, name.length());
                log.debug("Attribute is: " + att);
                String methodName = "get" + att;
                //log.debug(methodName);
                Method m2 = cl.getMethod(methodName, (Class[]) null);
                //log.debug("Method Name m2"+m2.getName());
                //log.debug(m2.invoke(obj,null));
                if (!accessMap.hasAccess(att)) {
                    log.debug("No Access to update attribute: " + att);
                    Object origValue = m2.invoke(originalObject, (Object[]) null);
                    if (origValue != null) {
                        log.debug("Original value is: " + origValue.toString());
                    }
                    m.invoke(mutatedObject, new Object[] { origValue });
                } else {
                    log.debug("Access permitted to update attribute: " + att);
                }
            }
        }

    } catch (Exception ex) {
        log.error("Error Securing object", ex);
        if (log.isDebugEnabled())
            log.debug("Authorization||" + userName + "|secureUpdate|Failure|Error in Secure Update|"
                    + ex.getMessage());

        throw new CSException("Failed to secure update the object:" + ex.getMessage(), ex);
    }

    return mutatedObject;

}

From source file:org.apache.openjpa.enhance.PCEnhancer.java

/**
 * Adds the <code>pcCopyKeyFieldsFromObjectId</code> methods
 * to classes using application identity.
 *///from w  ww .j  a v a  2  s. c  o m
private void addCopyKeyFieldsFromObjectIdMethod(boolean fieldManager) throws NoSuchMethodException {
    // public void pcCopyKeyFieldsFromObjectId (ObjectIdFieldConsumer fc,
    //   Object oid)
    String[] args = (fieldManager) ? new String[] { OIDFCTYPE.getName(), Object.class.getName() }
            : new String[] { Object.class.getName() };
    BCMethod method = _pc.declareMethod(PRE + "CopyKeyFieldsFromObjectId", void.class.getName(), args);
    Code code = method.getCode(true);

    // call superclass method
    if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
        loadManagedInstance(code, false);
        for (int i = 0; i < args.length; i++)
            code.aload().setParam(i);
        code.invokespecial().setMethod(getType(_meta.getPCSuperclassMetaData()).getName(),
                PRE + "CopyKeyFieldsFromObjectId", void.class.getName(), args);
    }

    if (fieldManager)
        code.aload().setParam(1);
    else
        code.aload().setParam(0);

    if (!_meta.isOpenJPAIdentity() && _meta.isObjectIdTypeShared()) {
        // oid = ((ObjectId) id).getId ();
        code.checkcast().setType(ObjectId.class);
        code.invokevirtual().setMethod(ObjectId.class, "getId", Object.class, null);
    }

    // <oid type> cast = (<oid type>) oid;
    int id = code.getNextLocalsIndex();
    Class oidType = _meta.getObjectIdType();
    code.checkcast().setType(oidType);
    code.astore().setLocal(id);

    // fs.store<type>Field (<index>, id.<field>); or...
    // this.<field> = id.<field>
    // or for single field identity: id.getId ()
    FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields() : _meta.getDeclaredFields();
    String name;
    Class type;
    Class unwrapped;
    Field field;
    Method getter;
    for (int i = 0; i < fmds.length; i++) {
        if (!fmds[i].isPrimaryKey())
            continue;

        name = fmds[i].getName();
        type = fmds[i].getObjectIdFieldType();
        if (!fieldManager && fmds[i].getDeclaredTypeCode() == JavaTypes.PC) {
            // if (sm == null) return;
            loadManagedInstance(code, false);
            code.getfield().setField(SM, SMTYPE);
            JumpInstruction ifins = code.ifnonnull();
            code.vreturn();
            // sm.getPCPrimaryKey(oid, i + pcInheritedFieldCount); 
            ifins.setTarget(loadManagedInstance(code, false));
            code.dup(); // leave orig on stack to set value into
            code.getfield().setField(SM, SMTYPE);
            code.aload().setLocal(id);
            code.constant().setValue(i);
            code.getstatic().setField(INHERIT, int.class);
            code.iadd();
            code.invokeinterface().setMethod(StateManager.class, "getPCPrimaryKey", Object.class,
                    new Class[] { Object.class, int.class });
            code.checkcast().setType(fmds[i].getDeclaredType());
        } else {
            unwrapped = (fmds[i].getDeclaredTypeCode() == JavaTypes.PC) ? type
                    : unwrapSingleFieldIdentity(fmds[i]);
            if (fieldManager) {
                code.aload().setParam(0);
                code.constant().setValue(i);
                code.getstatic().setField(INHERIT, int.class);
                code.iadd();
            } else
                loadManagedInstance(code, false);

            if (unwrapped != type) {
                code.anew().setType(type);
                code.dup();
            }
            code.aload().setLocal(id);
            if (_meta.isOpenJPAIdentity()) {
                if (oidType == ObjectId.class) {
                    code.invokevirtual().setMethod(oidType, "getId", Object.class, null);
                    if (!fieldManager && type != Object.class)
                        code.checkcast().setType(fmds[i].getDeclaredType());
                } else if (oidType == DateId.class) {
                    code.invokevirtual().setMethod(oidType, "getId", Date.class, null);
                    if (!fieldManager && type != Date.class)
                        code.checkcast().setType(fmds[i].getDeclaredType());
                } else {
                    code.invokevirtual().setMethod(oidType, "getId", unwrapped, null);
                    if (unwrapped != type)
                        code.invokespecial().setMethod(type, "<init>", void.class, new Class[] { unwrapped });
                }
            } else if (isFieldAccess(fmds[i])) {
                field = Reflection.findField(oidType, name, true);
                if (Modifier.isPublic(field.getModifiers()))
                    code.getfield().setField(field);
                else {
                    boolean usedFastOid = false;
                    if (_optimizeIdCopy) {
                        // If fastOids, ignore access type and try to use a public getter
                        getter = Reflection.findGetter(oidType, name, false);
                        if (getter != null && Modifier.isPublic(getter.getModifiers())) {
                            usedFastOid = true;
                            code.invokevirtual().setMethod(getter);
                        }
                    }
                    if (!usedFastOid) {
                        // Reflection.getXXX(oid, Reflection.findField(...));
                        code.classconstant().setClass(oidType);
                        code.constant().setValue(name);
                        code.constant().setValue(true);
                        code.invokestatic().setMethod(Reflection.class, "findField", Field.class,
                                new Class[] { Class.class, String.class, boolean.class });
                        code.invokestatic().setMethod(getReflectionGetterMethod(type, Field.class));
                        if (!type.isPrimitive() && type != Object.class)
                            code.checkcast().setType(type);
                    }
                }
            } else {
                getter = Reflection.findGetter(oidType, name, true);
                if (Modifier.isPublic(getter.getModifiers()))
                    code.invokevirtual().setMethod(getter);
                else {
                    // Reflection.getXXX(oid, Reflection.findGetter(...));
                    code.classconstant().setClass(oidType);
                    code.constant().setValue(name);
                    code.constant().setValue(true);
                    code.invokestatic().setMethod(Reflection.class, "findGetter", Method.class,
                            new Class[] { Class.class, String.class, boolean.class });
                    code.invokestatic().setMethod(getReflectionGetterMethod(type, Method.class));
                    if (!type.isPrimitive() && type != Object.class)
                        code.checkcast().setType(type);
                }
            }
        }

        if (fieldManager)
            code.invokeinterface().setMethod(getFieldConsumerMethod(type));
        else
            addSetManagedValueCode(code, fmds[i]);
    }
    code.vreturn();

    code.calculateMaxStack();
    code.calculateMaxLocals();
}

From source file:org.apache.openjpa.enhance.PCEnhancer.java

/**
 * Adds the <code>pcCopyKeyFieldsToObjectId</code> methods
 * to classes using application identity.
 *//*from   ww w .ja va 2 s.c o m*/
private void addCopyKeyFieldsToObjectIdMethod(boolean fieldManager) throws NoSuchMethodException {
    // public void pcCopyKeyFieldsToObjectId (ObjectIdFieldSupplier fs,
    //   Object oid)
    String[] args = (fieldManager) ? new String[] { OIDFSTYPE.getName(), Object.class.getName() }
            : new String[] { Object.class.getName() };
    BCMethod method = _pc.declareMethod(PRE + "CopyKeyFieldsToObjectId", void.class.getName(), args);
    Code code = method.getCode(true);

    // single field identity always throws exception
    if (_meta.isOpenJPAIdentity()) {
        throwException(code, INTERNEXCEP);

        code.calculateMaxStack();
        code.calculateMaxLocals();
        return;
    }

    // call superclass method
    if (_meta.getPCSuperclass() != null && !getCreateSubclass()) {
        loadManagedInstance(code, false);
        for (int i = 0; i < args.length; i++)
            code.aload().setParam(i);
        code.invokespecial().setMethod(getType(_meta.getPCSuperclassMetaData()).getName(),
                PRE + "CopyKeyFieldsToObjectId", void.class.getName(), args);
    }

    // Object id = oid;
    if (fieldManager)
        code.aload().setParam(1);
    else
        code.aload().setParam(0);

    if (_meta.isObjectIdTypeShared()) {
        // oid = ((ObjectId) id).getId ();
        code.checkcast().setType(ObjectId.class);
        code.invokevirtual().setMethod(ObjectId.class, "getId", Object.class, null);
    }

    // <oid type> id = (<oid type>) oid;
    int id = code.getNextLocalsIndex();
    Class oidType = _meta.getObjectIdType();
    code.checkcast().setType(oidType);
    code.astore().setLocal(id);

    // int inherited = pcInheritedFieldCount;
    int inherited = 0;
    if (fieldManager) {
        code.getstatic().setField(INHERIT, int.class);
        inherited = code.getNextLocalsIndex();
        code.istore().setLocal(inherited);
    }

    // id.<field> = fs.fetch<type>Field (<index>); or...
    // id.<field> = pc.<field>;
    FieldMetaData[] fmds = getCreateSubclass() ? _meta.getFields() : _meta.getDeclaredFields();
    Class<?> type;
    String name;
    Field field;
    Method setter;
    boolean reflect;
    // If optimizeIdCopy is enabled and not a field manager method, try to
    // optimize the copyTo by using a public constructor instead of reflection
    if (_optimizeIdCopy) {
        ArrayList<Integer> pkfields = optimizeIdCopy(oidType, fmds);
        if (pkfields != null) {
            // search for a constructor on the IdClass that can be used
            // to construct the IdClass
            int parmOrder[] = getIdClassConstructorParmOrder(oidType, pkfields, fmds);
            if (parmOrder != null) {
                // If using a field manager, values must be loaded into locals so they can be properly ordered
                // as constructor parameters.
                int[] localIndexes = new int[fmds.length];
                if (fieldManager) {
                    for (int k = 0; k < fmds.length; k++) {
                        if (!fmds[k].isPrimaryKey())
                            continue;
                        code.aload().setParam(0);
                        code.constant().setValue(k);
                        code.iload().setLocal(inherited);
                        code.iadd();
                        code.invokeinterface()
                                .setMethod(getFieldSupplierMethod(fmds[k].getObjectIdFieldType()));
                        localIndexes[k] = code.getNextLocalsIndex();
                        storeLocalValue(code, localIndexes[k], fmds[k].getObjectIdFieldTypeCode());
                    }
                }

                // found a matching constructor.  parm array is constructor parm order
                code.anew().setType(oidType);
                code.dup();
                // build the parm list in order
                Class<?>[] clsArgs = new Class<?>[parmOrder.length];
                for (int i = 0; i < clsArgs.length; i++) {
                    int parmIndex = parmOrder[i];
                    clsArgs[i] = fmds[parmIndex].getObjectIdFieldType();
                    if (!fieldManager) {
                        loadManagedInstance(code, false);
                        addGetManagedValueCode(code, fmds[parmIndex]);
                    } else {
                        // Load constructor parameters in appropriate order
                        loadLocalValue(code, localIndexes[parmIndex],
                                fmds[parmIndex].getObjectIdFieldTypeCode());
                        if (fmds[parmIndex].getObjectIdFieldTypeCode() == JavaTypes.OBJECT
                                && !fmds[parmIndex].getDeclaredType().isEnum()) {
                            code.checkcast().setType(ObjectId.class);
                            code.invokevirtual().setMethod(ObjectId.class, "getId", Object.class, null);
                        }
                        // if the type of this field meta data is
                        // non-primitive and non-string, be sure to cast
                        // to the appropriate type.
                        if (!clsArgs[i].isPrimitive() && !clsArgs[i].getName().equals(String.class.getName()))
                            code.checkcast().setType(clsArgs[i]);
                    }
                }
                // invoke the public constructor to create a new local id
                code.invokespecial().setMethod(oidType, "<init>", void.class, clsArgs);
                int ret = code.getNextLocalsIndex();
                code.astore().setLocal(ret);

                // swap out the app id with the new one
                code.aload().setLocal(fieldManager ? 2 : 1);
                code.checkcast().setType(ObjectId.class);
                code.aload().setLocal(ret);
                code.invokestatic().setMethod(ApplicationIds.class, "setAppId", void.class,
                        new Class[] { ObjectId.class, Object.class });
                code.vreturn();

                code.calculateMaxStack();
                code.calculateMaxLocals();
                return;
            }
        }
    }

    for (int i = 0; i < fmds.length; i++) {
        if (!fmds[i].isPrimaryKey())
            continue;
        code.aload().setLocal(id);

        name = fmds[i].getName();
        type = fmds[i].getObjectIdFieldType();
        if (isFieldAccess(fmds[i])) {
            setter = null;
            field = Reflection.findField(oidType, name, true);
            reflect = !Modifier.isPublic(field.getModifiers());
            if (reflect) {
                code.classconstant().setClass(oidType);
                code.constant().setValue(name);
                code.constant().setValue(true);
                code.invokestatic().setMethod(Reflection.class, "findField", Field.class,
                        new Class[] { Class.class, String.class, boolean.class });
            }
        } else {
            field = null;
            setter = Reflection.findSetter(oidType, name, type, true);
            reflect = !Modifier.isPublic(setter.getModifiers());
            if (reflect) {
                code.classconstant().setClass(oidType);
                code.constant().setValue(name);
                code.classconstant().setClass(type);
                code.constant().setValue(true);
                code.invokestatic().setMethod(Reflection.class, "findSetter", Method.class,
                        new Class[] { Class.class, String.class, Class.class, boolean.class });
            }
        }

        if (fieldManager) {
            code.aload().setParam(0);
            code.constant().setValue(i);
            code.iload().setLocal(inherited);
            code.iadd();
            code.invokeinterface().setMethod(getFieldSupplierMethod(type));
            if (fmds[i].getObjectIdFieldTypeCode() == JavaTypes.OBJECT && !fmds[i].getDeclaredType().isEnum()) {
                code.checkcast().setType(ObjectId.class);
                code.invokevirtual().setMethod(ObjectId.class, "getId", Object.class, null);
            }

            // if the type of this field meta data is
            // non-primitive and non-string, be sure to cast
            // to the appropriate type.
            if (!reflect && !type.isPrimitive() && !type.getName().equals(String.class.getName()))
                code.checkcast().setType(type);
        } else {
            loadManagedInstance(code, false);
            addGetManagedValueCode(code, fmds[i]);

            // get id/pk from pc instance
            if (fmds[i].getDeclaredTypeCode() == JavaTypes.PC)
                addExtractObjectIdFieldValueCode(code, fmds[i]);
        }

        if (reflect && field != null) {
            code.invokestatic().setMethod(Reflection.class, "set", void.class,
                    new Class[] { Object.class, Field.class, (type.isPrimitive()) ? type : Object.class });
        } else if (reflect) {
            code.invokestatic().setMethod(Reflection.class, "set", void.class,
                    new Class[] { Object.class, Method.class, (type.isPrimitive()) ? type : Object.class });
        } else if (field != null)
            code.putfield().setField(field);
        else
            code.invokevirtual().setMethod(setter);
    }
    code.vreturn();

    code.calculateMaxStack();
    code.calculateMaxLocals();
}

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

<T> T newInstance(Map<String, Object> map, Class<T> valueType) {
    InstanceCreator creator = getTypeAdapter(valueType);

    if (creator != null) {
        return (T) creator.createInstance(valueType);
    }/* w ww  . j  a  va2 s. c o m*/

    T obj = null;

    if (valueType != null) {
        obj = (T) getDefaultValue(valueType);
        if (obj != null) {
            return obj;
        }
    }

    if (map == null) {
        return null;
    }

    // @JsonTypeInfo(use = JsonTypeInfo.Id.MINIMAL_CLASS, include = As.PROPERTY, property = "@class")
    //@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")
    String JsonClassType = null;

    if (valueType != null) {
        if (getAnnotationSupport()) {
            for (Annotation annotation : valueType.getAnnotations()) {
                if (annotation instanceof JsonTypeInfo) {
                    JsonTypeInfo jsonTypeInfo = (JsonTypeInfo) annotation;
                    JsonTypeInfo.Id use = jsonTypeInfo.use();
                    JsonTypeInfo.As as = jsonTypeInfo.include();
                    if ((use == JsonTypeInfo.Id.MINIMAL_CLASS || use == JsonTypeInfo.Id.CLASS)
                            && as == As.PROPERTY) {
                        JsonClassType = jsonTypeInfo.property();
                    }
                }
            }
        }
    }
    if (JsonClassType == null) {
        JsonClassType = getJsonClassType();
    }

    String className = null;
    if (map.containsKey(JsonClassType)) {
        className = map.get(JsonClassType).toString();
    }

    Class<T> classType = getClassType(className);

    //  && (valueType == null || valueType.isAssignableFrom(classType) || Map.class.isAssignableFrom(valueType))
    if (classType != null) {
        valueType = classType;
    }

    if (valueType == null) {
        return (T) map; // or null, which is better?
    }

    Constructor<?>[] constructors = null;

    Class implClass = null;
    if (valueType.isInterface() || Modifier.isAbstract(valueType.getModifiers())) {
        implClass = DeSerializerUtil.implementingClass(valueType.getName());
    }

    if (implClass != null) {
        constructors = implClass.getDeclaredConstructors();
    } else {
        constructors = valueType.getDeclaredConstructors();//.getConstructors();
    }

    Object singleMapValue = null;
    Class singleMapValueType = null;
    if (map.size() == 1) {
        singleMapValue = map.get(valueType.getName());

        if (singleMapValue != null) {
            singleMapValueType = singleMapValue.getClass();

            if (singleMapValueType == String.class) {
                singleMapValue = StringUtil.unquote(singleMapValue.toString(), isEscapeHtml());
            }

            try {
                if (valueType == Locale.class) {
                    Constructor constructor = null;
                    String[] parts = ((String) singleMapValue).split("_");
                    if (parts.length == 1) {
                        constructor = valueType.getConstructor(String.class);
                        constructor.setAccessible(true);
                        obj = (T) constructor.newInstance(singleMapValue);
                    } else if (parts.length == 2) {
                        constructor = valueType.getConstructor(String.class, String.class);
                        constructor.setAccessible(true);
                        obj = (T) constructor.newInstance(parts);
                    } else if (parts.length == 3) {
                        constructor = valueType.getConstructor(String.class, String.class, String.class);
                        constructor.setAccessible(true);
                        obj = (T) constructor.newInstance(parts);
                    }

                    if (obj != null) {
                        return obj;
                    }
                }
            } catch (Exception e) {
            }

            Map<Class, Constructor> cmaps = new HashMap<>();
            for (Constructor constructor : constructors) {
                //Class[] parameterTypes = constructor.getParameterTypes();

                int parameterCount = constructor.getParameterCount();
                if (parameterCount == 1) {

                    Class[] types = constructor.getParameterTypes();

                    cmaps.put(types[0], constructor);
                }
            }

            if (cmaps.size() > 0) {
                Constructor constructor = null;

                if ((cmaps.containsKey(Boolean.class) || cmaps.containsKey(boolean.class))
                        && BooleanUtil.isBoolean(singleMapValue.toString())) {
                    constructor = cmaps.get(Boolean.class);
                    if (constructor == null) {
                        constructor = cmaps.get(boolean.class);
                    }
                    if (constructor != null) {
                        try {
                            constructor.setAccessible(true);
                            obj = (T) constructor
                                    .newInstance(BooleanUtil.string2Boolean(singleMapValue.toString()));

                            if (obj != null) {
                                return obj;
                            }
                        } catch (Exception e) {
                        }
                    }

                } else if (StringUtil.isNumeric(singleMapValue.toString())) {

                    Class[] classes = new Class[] { int.class, Integer.class, long.class, Long.class,
                            double.class, Double.class, Byte.class, byte.class, Short.class, short.class,
                            Float.class, float.class, BigDecimal.class, BigInteger.class, AtomicInteger.class,
                            AtomicLong.class, Number.class };

                    for (Class cls : classes) {
                        constructor = cmaps.get(cls);

                        if (constructor != null) {
                            try {
                                obj = (T) constructor.newInstance(NumberUtil.getNumber(singleMapValue, cls));

                                if (obj != null) {
                                    return obj;
                                }
                            } catch (Exception e) {
                            }
                        }
                    }

                } else if (StringUtil.isArrayOrList(singleMapValue.toString())
                        || singleMapValue.getClass().isArray()
                        || Collection.class.isAssignableFrom(singleMapValue.getClass())) {
                    for (Entry<Class, Constructor> entry : cmaps.entrySet()) {
                        Class cls = entry.getKey();
                        constructor = entry.getValue();

                        if (cls.isArray() || Collection.class.isAssignableFrom(cls)) {
                            Object listObject = null;
                            if (singleMapValue instanceof String) {
                                JSONArray objArray = new JSONArray(singleMapValue.toString());
                                listObject = (List) fromJsonMap(objArray);
                            } else {
                                listObject = singleMapValue;
                            }

                            FieldData objectDTO = new FieldData(listObject, cls, true);
                            listObject = json2Object(objectDTO);
                            if (listObject != null) {
                                try {
                                    obj = (T) constructor.newInstance(listObject);
                                    if (obj != null) {
                                        return obj;
                                    }
                                } catch (Exception e) {
                                }
                            }
                        }

                    }

                }

                for (Entry<Class, Constructor> entry : cmaps.entrySet()) {
                    Class cls = entry.getKey();
                    constructor = entry.getValue();
                    try {
                        obj = (T) constructor.newInstance(singleMapValue);
                        if (obj != null) {
                            return obj;
                        }
                    } catch (Exception e) {
                    }
                }

            }

        }
    }

    if (implClass != null) {
        valueType = implClass;
    }

    try {
        obj = valueType.newInstance();

        if (obj != null) {
            return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
        }

    } catch (InstantiationException | IllegalAccessException e) {
        //e.printStackTrace();
    }

    ///*
    for (Constructor constructor : constructors) {
        //Class[] parameterTypes = constructor.getParameterTypes();

        int parameterCount = constructor.getParameterCount();
        if (parameterCount > 0) {
            constructor.setAccessible(true);

            Annotation[] annotations = constructor.getDeclaredAnnotations(); // getAnnotations();

            for (Annotation annotation : annotations) {
                boolean isJsonCreator = false;
                if (annotation instanceof JsonCreator) {
                    isJsonCreator = true;
                } else if (annotation instanceof ca.oson.json.annotation.FieldMapper) {
                    ca.oson.json.annotation.FieldMapper fieldMapper = (ca.oson.json.annotation.FieldMapper) annotation;

                    if (fieldMapper.jsonCreator() == BOOLEAN.TRUE) {
                        isJsonCreator = true;
                    }
                }

                if (isJsonCreator) {
                    Parameter[] parameters = constructor.getParameters();
                    String[] parameterNames = ObjectUtil.getParameterNames(parameters);

                    //parameterCount = parameters.length;
                    Object[] parameterValues = new Object[parameterCount];
                    int i = 0;
                    for (String parameterName : parameterNames) {
                        parameterValues[i] = getParameterValue(map, valueType, parameterName,
                                parameters[i].getType());
                        i++;
                    }

                    try {
                        obj = (T) constructor.newInstance(parameterValues);

                        if (obj != null) {
                            return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                        }

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

        } else {
            try {
                constructor.setAccessible(true);
                obj = (T) constructor.newInstance();

                if (obj != null) {
                    return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                }

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

        }
    }
    //*/

    // try again
    for (Constructor constructor : constructors) {
        int parameterCount = constructor.getParameterCount();
        if (parameterCount > 0) {
            constructor.setAccessible(true);

            try {
                List<String> parameterNames = ObjectUtil.getParameterNames(constructor);

                if (parameterNames != null && parameterNames.size() > 0) {
                    Class[] parameterTypes = constructor.getParameterTypes();

                    int length = parameterTypes.length;
                    if (length == parameterNames.size()) {
                        Object[] parameterValues = new Object[length];
                        Object parameterValue;
                        for (int i = 0; i < length; i++) {
                            parameterValues[i] = getParameterValue(map, valueType, parameterNames.get(i),
                                    parameterTypes[i]);
                        }

                        try {
                            obj = (T) constructor.newInstance(parameterValues);
                            if (obj != null) {
                                return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                            }

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

                    }
                }

            } catch (IOException e1) {
                // e1.printStackTrace();
            }
        }
    }

    // try more
    for (Constructor constructor : constructors) {
        int parameterCount = constructor.getParameterCount();
        if (parameterCount > 0) {
            constructor.setAccessible(true);

            Class[] parameterTypes = constructor.getParameterTypes();
            List<String> parameterNames;
            try {
                parameterNames = ObjectUtil.getParameterNames(constructor);

                if (parameterNames != null) {
                    int length = parameterTypes.length;

                    if (length > parameterNames.size()) {
                        length = parameterNames.size();
                    }

                    Object[] parameterValues = new Object[length];
                    for (int i = 0; i < length; i++) {
                        parameterValues[i] = getParameterValue(map, valueType, parameterNames.get(i),
                                parameterTypes[i]);
                    }

                    obj = (T) constructor.newInstance(parameterValues);
                    if (obj != null) {
                        return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                    }
                }

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

    // try more
    try {
        Method[] methods = valueType.getMethods(); // .getMethod("getInstance", null);

        List<Method> methodList = new ArrayList<>();

        if (methods != null) {
            for (Method method : methods) {
                String methodName = method.getName();

                if (methodName.equals("getInstance") || methodName.equals("newInstance")
                        || methodName.equals("createInstance") || methodName.equals("factory")) {
                    Class returnType = method.getReturnType();

                    if (valueType.isAssignableFrom(returnType) && Modifier.isStatic(method.getModifiers())) {
                        int parameterCount = method.getParameterCount();
                        if (parameterCount == 0) {
                            try {
                                obj = ObjectUtil.getMethodValue(null, method);
                                if (obj != null) {
                                    return setSingleMapValue(obj, valueType, singleMapValue,
                                            singleMapValueType);
                                }

                            } catch (IllegalArgumentException e) {
                                // TODO Auto-generated catch block
                                //e.printStackTrace();
                            }

                        } else {
                            methodList.add(method);
                        }

                    }
                }
            }

            for (Method method : methodList) {
                try {
                    int parameterCount = method.getParameterCount();
                    Object[] parameterValues = new Object[parameterCount];
                    Object parameterValue;
                    int i = 0;
                    Class[] parameterTypes = method.getParameterTypes();

                    String[] parameterNames = ObjectUtil.getParameterNames(method);

                    if (parameterCount == 1 && valueType != null && singleMapValue != null
                            && singleMapValueType != null) {

                        if (ObjectUtil.isSameDataType(parameterTypes[0], singleMapValueType)) {
                            try {
                                obj = ObjectUtil.getMethodValue(null, method, singleMapValue);
                                if (obj != null) {
                                    return obj;
                                }

                            } catch (IllegalArgumentException ex) {
                                //ex.printStackTrace();
                            }

                        }

                    } else if (parameterNames != null && parameterNames.length == parameterCount) {
                        for (String parameterName : ObjectUtil.getParameterNames(method)) {
                            parameterValues[i] = getParameterValue(map, valueType, parameterName,
                                    parameterTypes[i]);
                            i++;
                        }

                    } else {
                        // try annotation
                        Parameter[] parameters = method.getParameters();
                        parameterNames = ObjectUtil.getParameterNames(parameters);
                        parameterCount = parameters.length;
                        parameterValues = new Object[parameterCount];
                        i = 0;
                        for (String parameterName : parameterNames) {
                            parameterValues[i] = getParameterValue(map, valueType, parameterName,
                                    parameterTypes[i]);
                            i++;
                        }
                    }

                    obj = ObjectUtil.getMethodValue(null, method, parameterValues);

                    if (obj != null) {
                        return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                    }

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

        }

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

    // try all static methods, if the return type is correct, get it as the final object
    Method[] methods = valueType.getDeclaredMethods();
    for (Method method : methods) {
        if (Modifier.isStatic(method.getModifiers())) {
            Class returnType = method.getReturnType();

            if (valueType.isAssignableFrom(returnType)) {
                try {
                    Object[] parameterValues = null;

                    int parameterCount = method.getParameterCount();
                    if (parameterCount > 0) {
                        if (parameterCount == 1 && map.size() == 1 && singleMapValue != null
                                && singleMapValueType != null) {
                            if (ObjectUtil.isSameDataType(method.getParameterTypes()[0], singleMapValueType)) {
                                obj = ObjectUtil.getMethodValue(null, method, singleMapValueType);
                                if (obj != null) {
                                    return obj;
                                }
                            }
                        }

                        parameterValues = new Object[parameterCount];
                        Object parameterValue;
                        int i = 0;
                        Class[] parameterTypes = method.getParameterTypes();

                        String[] parameterNames = ObjectUtil.getParameterNames(method);
                        if (parameterNames != null && parameterNames.length == parameterCount) {
                            for (String parameterName : ObjectUtil.getParameterNames(method)) {
                                parameterValues[i] = getParameterValue(map, valueType, parameterName,
                                        parameterTypes[i]);
                                i++;
                            }

                        } else {
                            // try annotation
                            Parameter[] parameters = method.getParameters();
                            parameterNames = ObjectUtil.getParameterNames(parameters);
                            parameterCount = parameters.length;
                            parameterValues = new Object[parameterCount];
                            i = 0;
                            for (String parameterName : parameterNames) {
                                parameterValues[i] = getParameterValue(map, valueType, parameterName,
                                        parameterTypes[i]);
                                i++;
                            }
                        }
                    }

                    obj = ObjectUtil.getMethodValue(obj, method, parameterValues);
                    if (obj != null) {
                        return setSingleMapValue(obj, valueType, singleMapValue, singleMapValueType);
                    }

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

            }
        }

    }

    return null;
}

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 {/*from www .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;
    }/*from  w w  w .j av a  2  s . c o  m*/

    // 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) {
    }
}