All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.unitils.objectvalidation.objectcreator.ObjectCreatorMockedFieldsImpl Maven / Gradle / Ivy

There is a newer version: 1.1.9
Show newest version
package org.unitils.objectvalidation.objectcreator;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easymock.classextension.internal.objenesis.ObjenesisStd;
import org.unitils.objectvalidation.ObjectCreator;
import org.unitils.objectvalidation.objectcreator.generator.Generator;
import org.unitils.objectvalidation.objectcreator.generator.helper.GeneratorHelper;
import org.unitils.objectvalidation.utils.ObjectCreatorTypeWrapper;
import org.unitils.objectvalidation.utils.TreeNode;
import org.unitils.util.ReflectionUtils;

/**
 * @author Matthieu Mestrez, Willemijn Wouters
 * @since 07/04/14.
 */
public class ObjectCreatorMockedFieldsImpl extends BaseObjectCreator implements ObjectCreator {
    private static final Log LOGGER = LogFactory.getLog(ObjectCreatorMockedFieldsImpl.class);
    private int instances = 0;

    public ObjectCreatorMockedFieldsImpl() {
        super();
    }


    /**
     * @param generators
     */
    public ObjectCreatorMockedFieldsImpl(Generator... generators) {
        super(generators);
    }


    @Override
    public Object createRandomObject(Type type) {

        Object randomObject = null;

        ObjectCreatorTypeWrapper typeWrapper = new ObjectCreatorTypeWrapper(type);
        if (typeWrapper.isPrimitive() || typeWrapper.isString()  || typeWrapper.getWrappedType().getClass().isEnum()) {
            try {
                return getGenerator().generateObject(typeWrapper.getClassOfType(), new ArrayList(), new ArrayList>(), new ArrayList());
            } catch (Exception e) {
                LOGGER.error("The " + getClass().getSimpleName() + " couldn't generate the following class: " + typeWrapper.getClassOfType(), e);
            }
        }
        if (typeWrapper.isFinal() && !typeWrapper.isArray()) {
            return new ObjenesisStd().getInstantiatorOf(typeWrapper.getClassOfType()).newInstance();
        }
        if (instances == 0 ) {
            instances++;
            if (checkForCreatingAnInstance(typeWrapper)) {
                randomObject = createInstance(typeWrapper);
                for (Field field : ReflectionUtils.getAllFields(typeWrapper.getClassOfType())) {
                    if (!isConstant(field)) {
                        field.setAccessible(true);
                        List genericSubTypes = GeneratorHelper.createTreenodes(field);
                        Object generatedObject = createObject(genericSubTypes);
                        ReflectionUtils.setFieldValue(randomObject, field, generatedObject);
                    }
                }
            } else {
                randomObject = createObject(type);
            }
            instances--;
        } else {
                randomObject = createObject(type);
        }

        return randomObject;
    }

    protected boolean checkForCreatingAnInstance(ObjectCreatorTypeWrapper wrapper) {
        return (wrapper.isClassType() || wrapper.isInterface()) && !wrapper.isPrimitive() && !wrapper.isString() && !wrapper.isEnum() && !wrapper.isParameterizedType() && !wrapper.isArray();
    }

    protected Object createObject(Type type) {
        return createObject(GeneratorHelper.createNodes(type));
    }
    protected Object createObject(List nodes) {
        try {
            return getGenerator().generateObject(nodes.get(0).getValue(), new ArrayList(), new ArrayList>(), nodes);
        } catch (Exception e) {
            LOGGER.error("Something went wrong with creating " + nodes.get(0).getValue(), e);
        }
        return null;
    }

    @Override
    public Object createRandomObject(TreeNode bean) {
        return createRandomObject(bean.getType());

    }

    /**
     * Creates an object/mock of a specific class
     *
     * @param typeWrapper
     * @return {@link Object}
     */
    Object createInstance(ObjectCreatorTypeWrapper typeWrapper) {
        Constructor constructor = getConstructor(typeWrapper.getClassOfType());

        if (constructorNotEmpty(constructor)) {
            constructor.setAccessible(true);
            int i = 0;
            Class[] classes = (Class[]) Array.newInstance(Class.class, constructor.getGenericParameterTypes().length);
            Object[] values = (Object[]) Array.newInstance(Object.class, constructor.getGenericParameterTypes().length);
            for (Type parameterType : constructor.getGenericParameterTypes()) {
                ObjectCreatorTypeWrapper type = new ObjectCreatorTypeWrapper(parameterType);
                classes[i] = type.getClassOfType();
                values[i] = createObject(type.getWrappedType());
                i++;
            }
            return ReflectionUtils.createInstanceOfType(typeWrapper.getClassOfType(), true, classes, values);
        } else if (isDefaultConstructor(constructor)) {
            return ReflectionUtils.createInstanceOfType(typeWrapper.getClassOfType(), true);
        }

        return null;
    }

    /**
     * This method checks if this constructor is the default constructor.
     *
     * @param constructor
     * @return boolean
     */
    protected boolean constructorNotEmpty(Constructor constructor) {
        return constructor != null && constructor.getParameterTypes().length > 0;
    }

    /**
     * Returns true if this is the default constructor.
     *
     * @param constructor
     * @return {@link Boolean}
     */
    protected boolean isDefaultConstructor(Constructor constructor) {
        return constructor != null && constructor.getParameterTypes().length == 0;
    }

    /**
     * This method gets the first constructor that isn't generated by the compiler.
     *
     * @param clzz
     * @return {@link Constructor}
     */
    protected Constructor getConstructor(Class clzz) {
        for (Constructor constructor : clzz.getConstructors()) {
            if (!constructor.isSynthetic()) {
                return constructor;
            }
        }

        return null;
    }

    /**
     * This method checks if the wrapper is a primitive.
     *
     * @param wrapper
     * @return boolean
     */
    protected boolean isPrimitive(ObjectCreatorTypeWrapper wrapper) {
        return wrapper.isPrimitive() || wrapper.isString();
    }

    protected boolean isConstant(Field field) {
        return Modifier.isFinal(field.getModifiers()) && Modifier.isStatic(field.getModifiers());
    }


}