org.vulpe.commons.util.VulpeReflectUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.vulpe.commons.util.VulpeReflectUtil.java

Source

/**
 * Vulpe Framework - Quick and Smart ;)
 * Copyright (C) 2011 Active Thread
 *
 * Este programa  software livre; voc pode redistribu-lo e/ou
 * modific-lo sob os termos da Licena Pblica Geral GNU, conforme
 * publicada pela Free Software Foundation; tanto a verso 2 da
 * Licena como (a seu critrio) qualquer verso mais nova.
 *
 * Este programa  distribudo na expectativa de ser til, mas SEM
 * QUALQUER GARANTIA; sem mesmo a garantia implcita de
 * COMERCIALIZAO ou de ADEQUAO A QUALQUER PROPSITO EM
 * PARTICULAR. Consulte a Licena Pblica Geral GNU para obter mais
 * detalhes.
 *
 * Voc deve ter recebido uma cpia da Licena Pblica Geral GNU
 * junto com este programa; se no, escreva para a Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
 */
/**
 * Vulpe Framework - Quick and Smart ;)
 * Copyright (C) 2011 Active Thread
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package org.vulpe.commons.util;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vulpe.commons.helper.VulpeCacheHelper;
import org.vulpe.exception.VulpeSystemException;
import org.vulpe.model.entity.VulpeEntity;

@SuppressWarnings({ "unchecked", "rawtypes" })
public class VulpeReflectUtil {

    private static final Logger LOG = LoggerFactory.getLogger(VulpeReflectUtil.class);

    protected VulpeReflectUtil() {
        // default constructor
    }

    /**
     * Returns list of fields in class or superclass.
     *
     * @param clazz
     * @return
     */
    public static List<Field> getFields(final Class<?> clazz) {
        if (VulpeCacheHelper.getInstance().contains(clazz.getName().concat(".fields"))) {
            return VulpeCacheHelper.getInstance().get(clazz.getName().concat(".fields"));
        }
        Class<?> baseClass = clazz;
        final List<Field> list = new ArrayList<Field>();
        while (!baseClass.equals(Object.class)) {
            for (Field field : baseClass.getDeclaredFields()) {
                if (!Modifier.isStatic(field.getModifiers()) && !field.isSynthetic()) {
                    list.add(field);
                }
            }
            baseClass = baseClass.getSuperclass();
        }
        VulpeCacheHelper.getInstance().put(clazz.getName().concat(".fields"), list);
        return list;
    }

    /**
     * Returns list of fields noted by <code>annotationClass</code>.
     *
     * @param clazz
     * @param annotationClass
     * @return
     */
    public static List<Field> getFieldsWithAnnotation(final Class<?> clazz,
            final Class<? extends Annotation> annotationClass) {
        final List<Field> filtredFields = new ArrayList<Field>();
        final List<Field> fields = getFields(clazz);
        for (Field field : fields) {
            if (isAnnotationInField(annotationClass, clazz, field)) {
                filtredFields.add(field);
            }
        }
        return filtredFields;
    }

    /**
     * Returns field of class or superclass.
     *
     * @param clazz
     * @param fieldName
     * @return
     */
    public static Field getField(final Class<?> clazz, final String fieldName) {
        Map<String, Field> fieldMap = new HashMap<String, Field>();
        if (VulpeCacheHelper.getInstance().contains(clazz.getName().concat(".fieldMap"))) {
            fieldMap = VulpeCacheHelper.getInstance().get(clazz.getName().concat(".fieldMap"));
        } else {
            final List<Field> fields = getFields(clazz);
            for (Field field : fields) {
                fieldMap.put(field.getName(), field);
            }
            VulpeCacheHelper.getInstance().put(clazz.getName().concat(".fieldMap"), fieldMap);
        }
        return fieldMap.get(fieldName);
    }

    public static Class<?> getFieldClass(final Class<?> clazz, final String fieldName) {
        final Field field = getField(clazz, fieldName);
        return field == null ? null : getDeclaredType(clazz, field.getGenericType()).getType();
    }

    /**
     * Copy attributes from <code>origin</code> to <code>destination</code>.
     *
     * @param destination
     * @param origin
     */
    public static void copy(final Object destination, final Object origin) {
        copy(destination, origin, false);
    }

    /**
     * Copy attributes from <code>origin</code> to <code>destination</code>.
     *
     * @param destination
     * @param origin
     * @param ignoreTransient
     */
    public static void copy(final Object destination, final Object origin, boolean ignoreTransient) {
        final List<Field> fields = getFields(origin.getClass());
        for (final Field field : fields) {
            if (ignoreTransient && Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            try {
                final Object value = PropertyUtils.getProperty(origin, field.getName());
                if (Collection.class.isAssignableFrom(field.getType())) {
                    final Collection valueDes = (Collection) PropertyUtils.getProperty(destination,
                            field.getName());
                    if (value == null) {
                        if (valueDes != null) {
                            valueDes.clear();
                        }
                    } else {
                        if (valueDes == null) {
                            PropertyUtils.setProperty(destination, field.getName(), value);
                        } else {
                            valueDes.clear();
                            valueDes.addAll((Collection) value);
                        }
                    }
                } else {
                    PropertyUtils.setProperty(destination, field.getName(), value);
                }
            } catch (NoSuchMethodException e) {
                LOG.debug("Method not found.", e);
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
        }
    }

    /**
     * Copy transient attributes from <code>origin</code> to
     * <code>destination</code>.
     *
     * @param destination
     * @param origin
     */
    public static void copyOnlyTransient(final Object destination, final Object origin) {
        final List<Field> fields = getFields(origin.getClass());
        for (final Field field : fields) {
            if (!Modifier.isTransient(field.getModifiers())) {
                continue;
            }
            try {
                final Object value = PropertyUtils.getProperty(origin, field.getName());
                if (Collection.class.isAssignableFrom(field.getType())) {
                    final Collection valueDes = (Collection) PropertyUtils.getProperty(destination,
                            field.getName());
                    if (value == null) {
                        if (valueDes != null) {
                            valueDes.clear();
                        }
                    } else {
                        if (valueDes == null) {
                            PropertyUtils.setProperty(destination, field.getName(), value);
                        } else {
                            valueDes.clear();
                            valueDes.addAll((Collection) value);
                        }
                    }
                } else {
                    PropertyUtils.setProperty(destination, field.getName(), value);
                }
            } catch (NoSuchMethodException e) {
                LOG.debug("Method not found.", e);
            } catch (Exception e) {
                throw new VulpeSystemException(e);
            }
        }
    }

    /**
     * Returns list of methods in class or superclass.
     *
     * @param clazz
     * @return
     */
    public static List<Method> getMethods(final Class<?> clazz) {
        if (VulpeCacheHelper.getInstance().contains(clazz.getName().concat(".methods"))) {
            return VulpeCacheHelper.getInstance().get(clazz.getName().concat(".methods"));
        }
        Class<?> baseClass = clazz;
        final List<Method> list = new ArrayList<Method>();
        while (!baseClass.equals(Object.class)) {
            for (Method method : baseClass.getDeclaredMethods()) {
                if (!method.isSynthetic() && !method.isBridge() && !Modifier.isStatic(method.getModifiers())) {
                    list.add(method);
                }
            }
            baseClass = baseClass.getSuperclass();
        }
        VulpeCacheHelper.getInstance().put(clazz.getName().concat(".methods"), list);
        return list;
    }

    /**
     * Returns method of class or superclass.
     *
     * @param clazz
     * @param methodName
     * @param typeParams
     * @return
     */
    public static Method getMethod(final Class<?> clazz, final String methodName, final Class<?>... typeParams) {
        final List<Method> methods = getMethods(clazz);
        Method methodFirst = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                if ((typeParams == null && method.getParameterTypes() == null)
                        || (typeParams != null && method.getParameterTypes() != null
                                && Arrays.equals(typeParams, method.getParameterTypes()))) {
                    return method;
                }
                if (typeParams == null && methodFirst == null) {
                    methodFirst = method;
                }
            }
        }
        return methodFirst;
    }

    /**
     * Returns class of Type.
     *
     * @param clazz
     * @param type
     * @return
     */
    public static DeclaredType getDeclaredType(final Class<?> clazz, final Type type) {
        if (type == null) {
            return null;
        }

        DeclaredType declaredType = null;
        if (type instanceof Class) {
            declaredType = new DeclaredType();
            declaredType.setType((Class<?>) type);
        } else if (type instanceof ParameterizedType) {
            declaredType = new DeclaredType();
            final ParameterizedType parameterizedType = (ParameterizedType) type;
            final DeclaredType rawType = getDeclaredType(clazz, parameterizedType.getRawType());
            declaredType.setType(rawType.getType());
            for (int i = 0; i < parameterizedType.getActualTypeArguments().length; i++) {
                declaredType.getItems().add(getDeclaredType(clazz, parameterizedType.getActualTypeArguments()[i]));
            }
        } else if (type instanceof TypeVariable) {
            return getDeclaredTypeVariable(clazz, (TypeVariable<?>) type);
        } else if (type instanceof WildcardType) {
            declaredType = new DeclaredType();
            final WildcardType wildcardType = (WildcardType) type;
            if (wildcardType.getLowerBounds().length > 0) {
                declaredType.setType(getDeclaredType(clazz, wildcardType.getLowerBounds()[0]).getType());
            } else {
                declaredType.setType(null);
            }

            for (int i = 0; i < wildcardType.getUpperBounds().length; i++) {
                declaredType.getTypeItems().add(getDeclaredType(clazz, wildcardType.getUpperBounds()[i]));
            }

            return declaredType;
        }
        return declaredType;
    }

    /**
     * Returns class of TypeVariable.
     *
     * @param clazz
     * @param typeVariable
     * @return
     */
    private static DeclaredType getDeclaredTypeVariable(final Class<?> clazz, final TypeVariable<?> typeVariable) {
        final int index = getIndexTypeVariable(typeVariable);
        final VariableInfo info = new VariableInfo(index);
        DeclaredType declaredType = getDeclaredTypeVariableDeclared(clazz, clazz.getSuperclass(), typeVariable,
                info);
        if (declaredType == null) {
            if (info.isInSuperclass()) {
                final ParameterizedType pType = (ParameterizedType) info.getFirstClass().getGenericSuperclass();
                final Type type = pType.getActualTypeArguments()[info.getIndex()];
                if (type instanceof TypeVariable) {
                    declaredType = getDeclaredType(clazz, ((TypeVariable<?>) type).getBounds()[0]);
                } else {
                    declaredType = getDeclaredType(clazz, type);
                }
            } else {
                declaredType = getDeclaredType(clazz,
                        info.getFirstClass().getTypeParameters()[info.getIndex()].getBounds()[0]);
            }
            return declaredType;
        }
        return declaredType;
    }

    /**
     * Returns class of TypeVariable.
     *
     * @param clazz
     * @param superClass
     * @param typeVariable
     * @param info
     * @return
     */
    private static DeclaredType getDeclaredTypeVariableDeclared(final Class<?> clazz, final Class<?> superClass,
            final TypeVariable<?> typeVariable, final VariableInfo info) {
        if (clazz.equals(Object.class)) {
            return null;
        }

        if (typeVariable.getGenericDeclaration().equals(superClass)
                || typeVariable.getGenericDeclaration().equals(clazz)) {
            final int index = getIndexTypeVariable(typeVariable);
            if (typeVariable.getGenericDeclaration().equals(clazz)) {
                info.setIndex(index);
                info.setFirstClass((Class<?>) typeVariable.getGenericDeclaration());
                info.setInSuperclass(false);
                return null;
            } else {
                final ParameterizedType pType = (ParameterizedType) clazz.getGenericSuperclass();
                final Type type = pType.getActualTypeArguments()[index];
                if (type instanceof TypeVariable) {
                    info.setIndex(getIndexTypeVariable((TypeVariable<?>) type));
                    info.setFirstClass(clazz);
                    info.setInSuperclass(true);
                    return null;
                }
                return getDeclaredType(clazz, type);
            }
        } else {
            final DeclaredType declaredType = getDeclaredTypeVariableDeclared(clazz.getSuperclass(),
                    superClass.getSuperclass(), typeVariable, info);
            if (declaredType == null) {
                ParameterizedType parameterizedType = null;
                if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
                    parameterizedType = (ParameterizedType) clazz.getGenericSuperclass();
                    info.setInSuperclass(true);
                    info.setFirstClass(clazz);
                } else {
                    parameterizedType = (ParameterizedType) superClass.getGenericSuperclass();
                    info.setInSuperclass(false);
                    info.setFirstClass(superClass);
                }
                final Type type = parameterizedType.getActualTypeArguments()[info.getIndex()];
                if (type instanceof TypeVariable) {
                    info.setIndex(getIndexTypeVariable((TypeVariable<?>) type));
                    return null;
                }
                return getDeclaredType(clazz, type);
            } else {
                return declaredType;
            }
        }
    }

    /**
     * Returns position of TypeVariable in list of getTypeParameters on class.
     *
     * @param typeVariable
     * @return
     */
    private static int getIndexTypeVariable(final TypeVariable<?> typeVariable) {
        int index = -1;
        for (final TypeVariable<?> typeVariable2 : typeVariable.getGenericDeclaration().getTypeParameters()) {
            ++index;
            if (typeVariable.getName().equals(typeVariable2.getName())) {
                break;
            }
        }
        return index;
    }

    /**
     * Auxiliary Class to locate class of TypeVariable
     */
    private static class VariableInfo {

        private int index;
        private boolean inSuperclass;
        private Class<?> firstClass;

        public Class<?> getFirstClass() {
            return firstClass;
        }

        public void setFirstClass(final Class<?> firstClass) {
            this.firstClass = firstClass;
        }

        public VariableInfo(final int index) {
            this.index = index;
        }

        public int getIndex() {
            return index;
        }

        public void setIndex(final int index) {
            this.index = index;
        }

        public boolean isInSuperclass() {
            return inSuperclass;
        }

        public void setInSuperclass(final boolean inSuperclass) {
            this.inSuperclass = inSuperclass;
        }
    }

    /**
     * Class to store info of Type
     */
    public static class DeclaredType {
        /**
         * Generic items classes
         */
        private List<DeclaredType> items = new ArrayList<DeclaredType>();
        /**
         * Class of Type
         */
        private Class<?> type;

        private List<DeclaredType> typeItems = new ArrayList<DeclaredType>();

        public DeclaredType() {
            // default constructor
        }

        public DeclaredType(final Class<?> type) {
            this.type = type;
        }

        public String getAssign() {
            final StringBuilder stringBuilder = new StringBuilder();
            if (isTypeItems()) {
                stringBuilder.append("? extends ");
                for (int i = 0; i < getTypeItems().size(); i++) {
                    stringBuilder.append(getTypeItems().get(i).getAssign());
                    if (i + 1 < getTypeItems().size()) {
                        stringBuilder.append("& ");
                    }
                }
            } else {
                stringBuilder.append(getType().getName());
            }

            if (getItems() != null && !getItems().isEmpty()) {
                stringBuilder.append("<");
                for (int i = 0; i < getItems().size(); i++) {
                    final DeclaredType item = getItems().get(i);
                    stringBuilder.append(item.getAssign());

                    if (i + 1 < getItems().size()) {
                        stringBuilder.append(",");
                    }
                }
                stringBuilder.append(">");
            }
            return stringBuilder.toString();
        }

        public Class<?> getType() {
            return type;
        }

        public void setType(final Class<?> type) {
            this.type = type;
        }

        public List<DeclaredType> getItems() {
            return items;
        }

        public void setItems(final List<DeclaredType> item) {
            this.items = item;
        }

        public List<DeclaredType> getTypeItems() {
            return typeItems;
        }

        public void setTypeItems(final List<DeclaredType> typeItems) {
            this.typeItems = typeItems;
        }

        public boolean isTypeItems() {
            return (getTypeItems() != null && getTypeItems().size() > 0);
        }

        @Override
        public String toString() {
            return getAssign();
        }
    }

    /**
     * Returns class on index in the parameterized type on <code>clazz</code> or
     * <code>super</code>.
     *
     * @param clazz
     * @param index
     * @return
     */
    public static Class<?> getIndexClass(final Class<?> clazz, final int index) {
        if (clazz.getGenericSuperclass() instanceof ParameterizedType) {
            final ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass();
            DeclaredType declaredType = null;
            if (type.getActualTypeArguments().length > index + 1) {
                declaredType = getDeclaredType(clazz, type.getActualTypeArguments()[index]);
            } else {
                declaredType = getDeclaredType(clazz,
                        type.getActualTypeArguments()[type.getActualTypeArguments().length - 1]);
            }
            return (Class<?>) declaredType.getType();
        } else if (clazz.getGenericSuperclass() instanceof Class) {
            return getIndexClass(clazz.getSuperclass(), index);
        } else {
            return null;
        }
    }

    /**
     * Checks if class is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @return
     */
    public static <T extends Annotation> T getAnnotationInClass(final Class<T> annotationClass,
            final Class<?> clazz) {
        Class<?> baseClass = clazz;
        while (baseClass != null && !baseClass.equals(Object.class)) {
            if (baseClass.isAnnotationPresent(annotationClass)) {
                return baseClass.getAnnotation(annotationClass);
            }

            for (Class<?> iClass : baseClass.getInterfaces()) {
                final T tAnnotation = getAnnotationInClass(annotationClass, iClass);
                if (tAnnotation != null) {
                    return tAnnotation;
                }
            }

            baseClass = baseClass.getSuperclass();
        }

        return null;
    }

    /**
     * Checks if class is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @return
     */
    public static <T extends Annotation> boolean isAnnotationInClass(final Class<T> annotationClass,
            final Class<?> clazz) {
        return getAnnotationInClass(annotationClass, clazz) != null;
    }

    /**
     * Checks if field is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @param fieldName
     * @return
     */
    public static <T extends Annotation> T getAnnotationInField(final Class<T> annotationClass,
            final Class<?> clazz, final String fieldName) {
        final Field field = getField(clazz, fieldName);
        if (field != null && field.isAnnotationPresent(annotationClass)) {
            return field.getAnnotation(annotationClass);
        }
        final String name = VulpeStringUtil.upperCaseFirst(fieldName);
        Method method = getMethod(clazz, "get".concat(name));
        if (method != null && method.isAnnotationPresent(annotationClass)) {
            return method.getAnnotation(annotationClass);
        }
        method = getMethod(clazz, "set".concat(name));
        if (method != null && method.isAnnotationPresent(annotationClass)) {
            return method.getAnnotation(annotationClass);
        }
        return null;
    }

    /**
     * Checks if field is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @param field
     * @return
     */
    public static <T extends Annotation> T getAnnotationInField(final Class<T> annotationClass,
            final Class<?> clazz, final Field field) {
        if (field.isAnnotationPresent(annotationClass)) {
            return field.getAnnotation(annotationClass);
        }
        final String name = VulpeStringUtil.upperCaseFirst(field.getName());
        Method method = getMethod(clazz, "get".concat(name));
        if (method != null && method.isAnnotationPresent(annotationClass)) {
            return method.getAnnotation(annotationClass);
        }
        method = getMethod(clazz, "set".concat(name));
        if (method != null && method.isAnnotationPresent(annotationClass)) {
            return method.getAnnotation(annotationClass);
        }
        return null;
    }

    /**
     * Checks if field is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @param fieldName
     * @return
     */
    public static <T extends Annotation> boolean isAnnotationInField(final Class<T> annotationClass,
            final Class<?> clazz, final String fieldName) {
        return getAnnotationInField(annotationClass, clazz, fieldName) != null;
    }

    /**
     * Checks if field is noted by <code>annotationClass</code>.
     *
     * @param <T>
     * @param annotationClass
     * @param clazz
     * @param field
     * @return
     */
    public static <T extends Annotation> boolean isAnnotationInField(final Class<T> annotationClass,
            final Class<?> clazz, final Field field) {
        return getAnnotationInField(annotationClass, clazz, field) != null;
    }

    /**
     * Sets field value in object.
     *
     * @param object
     * @param fieldName
     * @param value
     */
    public static void setFieldValue(final Object object, final String fieldName, final Object value) {
        try {
            final String name = VulpeStringUtil.upperCaseFirst(fieldName);
            Method method = null;
            Class<?> classField = (value == null ? getFieldClass(object.getClass(), fieldName) : value.getClass());
            while (classField != null && !classField.equals(Object.class)) {
                method = getMethod(object.getClass(), "set".concat(name), classField);
                if (method != null) {
                    break;
                }
                classField = classField.getSuperclass();
            }
            if (method != null) {
                synchronized (method) {
                    boolean setted = false;
                    if (!method.isAccessible()) {
                        method.setAccessible(true);
                        setted = true;
                    }
                    try {
                        method.invoke(object, value);
                    } catch (Exception e) {
                        LOG.error(e.getMessage());
                    } finally {
                        if (setted) {
                            method.setAccessible(false);
                        }
                    }
                }
            } else {
                final Field field = getField(object.getClass(), fieldName);
                if (field != null) {
                    synchronized (field) {
                        boolean setted = false;
                        if (!field.isAccessible()) {
                            field.setAccessible(true);
                            setted = true;
                        }
                        try {
                            if (field.getType().isAssignableFrom(value.getClass())) {
                                field.set(object, value);
                            } else {
                                Object newValue = value;
                                if (Long.class.isAssignableFrom(field.getType())) {
                                    newValue = new Long(value.toString());
                                }
                                field.set(object, newValue);
                            }
                        } finally {
                            if (setted) {
                                field.setAccessible(false);
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            throw new VulpeSystemException(e);
        }
    }

    /**
     * Checks if field exists in class.
     *
     * @param object
     * @param fieldName
     * @return
     */
    public static boolean fieldExists(final Class<?> clazz, final String fieldName) {
        boolean exists = false;
        final List<Method> methods = getMethods(clazz);
        for (Method method : methods) {
            final String name = VulpeStringUtil.upperCaseFirst(fieldName);
            if ("get".concat(name).equals(method.getName())) {
                exists = true;
                break;
            }
        }
        if (!exists) {
            final List<Field> fields = getFields(clazz);
            for (Field field : fields) {
                if (fieldName.equals(field.getName())) {
                    exists = true;
                    break;
                }
            }
        }
        return exists;
    }

    /**
     * Returns field value from object.
     *
     * @param <T>
     * @param object
     * @param fieldName
     * @return
     */
    public static <T> T getFieldValue(final Object object, final String fieldName) {
        try {
            final String name = VulpeStringUtil.upperCaseFirst(fieldName);
            final Method method = getMethod(object.getClass(), "get".concat(name));
            if (method != null) {
                synchronized (method) {
                    boolean setted = false;
                    if (!method.isAccessible()) {
                        method.setAccessible(true);
                        setted = true;
                    }
                    try {
                        return (T) method.invoke(object);
                    } catch (Exception e) {
                        LOG.error(e.getMessage());
                    } finally {
                        if (setted) {
                            method.setAccessible(false);
                        }
                    }
                }
            }
            final Field field = getField(object.getClass(), fieldName);
            if (field != null) {
                synchronized (field) {
                    boolean setted = false;
                    if (!field.isAccessible()) {
                        field.setAccessible(true);
                        setted = true;
                    }
                    try {
                        return (T) field.get(object);
                    } finally {
                        if (setted) {
                            field.setAccessible(false);
                        }
                    }
                }
            }
            return null;
        } catch (Exception e) {
            throw new VulpeSystemException(e);
        }
    }

    public static <T> T getExpressionValue(Object object, String expression) {
        final String[] expressionParts = expression.split("\\.");
        Object fieldValue = null;
        if (expressionParts.length > 1) {
            int count = 1;
            for (final String part : expressionParts) {
                if (count == expressionParts.length) {
                    fieldValue = getFieldValue(object, part);
                } else {
                    object = getFieldValue(object, part);
                }
                ++count;
            }
        } else {
            fieldValue = getFieldValue(object, expression);
        }
        return (T) fieldValue;
    }

    public static void instanciate(Object object, String expression, Object value) {
        final String[] expressionParts = expression.split("\\.");
        if (expressionParts.length > 1) {
            for (final String part : expressionParts) {
                Object fieldValue = getFieldValue(object, part);
                final Field field = getField(object.getClass(), part);
                if (fieldValue == null) {
                    try {
                        final Class<?> type = field.getType();
                        if (VulpeEntity.class.isAssignableFrom(type)) {
                            final Object instance = type.newInstance();
                            setFieldValue(object, part, instance);
                            object = instance;
                        } else {
                            setFieldValue(object, part, value);
                        }
                    } catch (InstantiationException e) {
                        LOG.error(e.getMessage());
                    } catch (IllegalAccessException e) {
                        LOG.error(e.getMessage());
                    }
                } else {
                    object = fieldValue;
                    final Class<?> type = field.getType();
                    if (!VulpeEntity.class.isAssignableFrom(type)) {
                        setFieldValue(object, part, value);
                    }
                }
            }
        } else {
            setFieldValue(object, expression, value);
        }
    }

    public static void fixToJson(Object object) {
        if (object instanceof Collection) {
            final List<?> list = (List<?>) object;
            for (final Object object2 : list) {
                fixObjectToJson(object2, null);
            }
        } else {
            fixObjectToJson(object, null);
        }
    }

    private static void fixObjectToJson(Object object, String parent) {
        final List<Field> fields = getFields(object.getClass());
        final String name = VulpeStringUtil.getAttributeName(object.getClass().getSimpleName());
        for (final Field field : fields) {
            final Class<?> type = field.getType();
            final Object value = getFieldValue(object, field.getName());
            if (value != null) {
                if (VulpeEntity.class.isAssignableFrom(type)) {
                    fixEntityToJson(value, parent == null ? name : parent);
                } else if (value instanceof Collection) {
                    final List<?> list = (List<?>) value;
                    for (final Object object2 : list) {
                        if (object2 != null) {
                            fixObjectToJson(object2, name);
                        }
                    }
                }
            }
        }
    }

    private static void fixEntityToJson(Object value, String name) {
        final List<Field> relationFields = getFields(value.getClass());
        for (final Field field : relationFields) {
            final String fieldName = field.getName();
            final Object fieldValue = getFieldValue(value, fieldName);
            if (fieldValue != null) {
                if (fieldName.startsWith(name) && fieldValue instanceof Collection) {
                    final List<?> list = (List<?>) fieldValue;
                    for (final Object object2 : list) {
                        if (object2 != null) {
                            fixEntityToJson(object2, name);
                        }
                    }
                } else if (fieldName.equals(name)) {
                    final VulpeEntity entity = getFieldValue(value, fieldName);
                    try {
                        final VulpeEntity simple = (VulpeEntity) entity.getClass().newInstance();
                        simple.setId(entity.getId());
                        setFieldValue(value, fieldName, simple);
                    } catch (Exception e) {
                        LOG.error(e.getMessage());
                    }
                    fixObjectToJson(value, VulpeStringUtil.getAttributeName(value.getClass().getSimpleName()));
                }
            }
        }
    }
}