<commit_before>/*
 *
 *  * Copyright 2010,  Unitils.org
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *     http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */
package org.unitils.mock.core.proxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.unitils.core.UnitilsException;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;

import static java.lang.reflect.Modifier.isStatic;
import static java.lang.reflect.Modifier.isTransient;
import static org.unitils.mock.core.proxy.ProxyUtils.isProxy;

/**
 * Utility class for deep cloning objects.
 * In a deep clone, not only the object itself is cloned, but also all the inner objects.
 *
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */
public class CloneUtil {

    /* The logger instance for this class */
    private static Log logger = LogFactory.getLog(CloneUtil.class);

    /* Objenesis instance for creating new instances of types */
    private static Objenesis objenesis = new ObjenesisStd(true);


    /**
     * Creates a deep clone of the given object. If for some reason, the clone cannot be made, a warning is logged
     * and the object itself will be returned. This is also true for all inner objects. If an inner object
     * cannot be cloned, the object itself is used instead.
     *
     * @param object The object to clone
     * @return The cloned instance
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T createDeepClone(T object) {
        try {
            return (T) cloneObject(object, new IdentityHashMap<Object, Object>());

        } catch (Throwable e) {
            throw new UnitilsException("Unexpected exception during cloning of " + object, e);
        }
    }


    /**
     * Actual implementation of the cloning.
     *
     * It will try several ways to clone the object. First it will look for the simple cases: null, primitives,
     * immutables... If not it will check whether it's an array and clone it using the {@link #cloneArray} method.
     * Finally it will see whether the object is cloneable and the clone method can be used. If not, Objenisis is
     * used to create the instance. The last step is to recursively do the same operation for the inner fields.
     *
     * An object is cloned once. All created clones are put in a cache and if an object is to be cloned a second time,
     * the cached instance is used. This way the object graph is preserved.
     *
     * @param instanceToClone The instance, not null
     * @param cloneCache      The cached clones, not null
     * @return The clone, the instance to clone if the clone could not be made
     */
    protected static Object cloneObject(Object instanceToClone, Map<Object, Object> cloneCache) throws Throwable {
        if (instanceToClone == null) {
            return null;
        }
        // check whether the instance was already cloned, this will preserve the object graph
        if (cloneCache.containsKey(instanceToClone)) {
            return cloneCache.get(instanceToClone);
        }
        // if the value is immutable, return the instance itself
        if (isImmutable(instanceToClone)) {
            return instanceToClone;
        }
        // check for arrays
        if (instanceToClone.getClass().isArray()) {
            return cloneArray(instanceToClone, cloneCache);
        }
        // if the instance is cloneable, try to clone it
        if (instanceToClone instanceof Cloneable) {
            return createInstanceUsingClone(instanceToClone);
        }
        // don't clone java classes (unless they are cloneable)
        if (isJdkClass(instanceToClone)) {
            return instanceToClone;
        }
        // don't clone proxies
        if (isProxy(instanceToClone)) {
            return instanceToClone;
        }
        // try to clone it ourselves
        Object clonedInstance = createInstanceUsingObjenesis(instanceToClone);

        // Unable to create an instance
        if (clonedInstance == null) {
            logger.warn("Could not create an instance of class " + instanceToClone.getClass() + " using objenesis");
            return instanceToClone;
        }
        // cache the clone
        cloneCache.put(instanceToClone, clonedInstance);

        // recursively do the same for all inner fields
        cloneFields(instanceToClone.getClass(), instanceToClone, clonedInstance, cloneCache);
        return clonedInstance;
    }


    /**
     * @param instanceToClone The instance, not null
     * @return True if the instance is immutable, e.g. a primitive
     */
    protected static boolean isImmutable(Object instanceToClone) {
        Class<?> clazz = instanceToClone.getClass();

        if (clazz.isPrimitive() || clazz.isEnum() || clazz.isAnnotation()) {
            return true;
        }
        if (instanceToClone instanceof Number || instanceToClone instanceof String || instanceToClone instanceof Character || instanceToClone instanceof Boolean) {
            return true;
        }
        return false;
    }

    /**<commit_msg>Support for Guava immutable collections<commit_after>/*
 *
 *  * Copyright 2010,  Unitils.org
 *  *
 *  * Licensed under the Apache License, Version 2.0 (the "License");
 *  * you may not use this file except in compliance with the License.
 *  * You may obtain a copy of the License at
 *  *
 *  *     http://www.apache.org/licenses/LICENSE-2.0
 *  *
 *  * Unless required by applicable law or agreed to in writing, software
 *  * distributed under the License is distributed on an "AS IS" BASIS,
 *  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  * See the License for the specific language governing permissions and
 *  * limitations under the License.
 *
 */
package org.unitils.mock.core.proxy;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import org.unitils.core.UnitilsException;

import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.Map;

import static java.lang.reflect.Modifier.isStatic;
import static java.lang.reflect.Modifier.isTransient;
import static org.unitils.mock.core.proxy.ProxyUtils.isProxy;

/**
 * Utility class for deep cloning objects.
 * In a deep clone, not only the object itself is cloned, but also all the inner objects.
 *
 * @author <NAME>
 * @author <NAME>
 * @author <NAME>
 */
public class CloneUtil {

    /* The logger instance for this class */
    private static Log logger = LogFactory.getLog(CloneUtil.class);

    /* Objenesis instance for creating new instances of types */
    private static Objenesis objenesis = new ObjenesisStd(true);


    /**
     * Creates a deep clone of the given object. If for some reason, the clone cannot be made, a warning is logged
     * and the object itself will be returned. This is also true for all inner objects. If an inner object
     * cannot be cloned, the object itself is used instead.
     *
     * @param object The object to clone
     * @return The cloned instance
     */
    @SuppressWarnings({"unchecked"})
    public static <T> T createDeepClone(T object) {
        try {
            return (T) cloneObject(object, new IdentityHashMap<Object, Object>());

        } catch (Throwable e) {
            throw new UnitilsException("Unexpected exception during cloning of " + object, e);
        }
    }


    /**
     * Actual implementation of the cloning.
     *
     * It will try several ways to clone the object. First it will look for the simple cases: null, primitives,
     * immutables... If not it will check whether it's an array and clone it using the {@link #cloneArray} method.
     * Finally it will see whether the object is cloneable and the clone method can be used. If not, Objenisis is
     * used to create the instance. The last step is to recursively do the same operation for the inner fields.
     *
     * An object is cloned once. All created clones are put in a cache and if an object is to be cloned a second time,
     * the cached instance is used. This way the object graph is preserved.
     *
     * @param instanceToClone The instance, not null
     * @param cloneCache      The cached clones, not null
     * @return The clone, the instance to clone if the clone could not be made
     */
    protected static Object cloneObject(Object instanceToClone, Map<Object, Object> cloneCache) throws Throwable {
        if (instanceToClone == null) {
            return null;
        }
        // check whether the instance was already cloned, this will preserve the object graph
        if (cloneCache.containsKey(instanceToClone)) {
            return cloneCache.get(instanceToClone);
        }
        // if the value is immutable, return the instance itself
        if (isImmutable(instanceToClone)) {
            return instanceToClone;
        }
        // check for arrays
        if (instanceToClone.getClass().isArray()) {
            return cloneArray(instanceToClone, cloneCache);
        }
        // if the instance is cloneable, try to clone it
        if (instanceToClone instanceof Cloneable) {
            return createInstanceUsingClone(instanceToClone);
        }
        // don't clone java classes (unless they are cloneable)
        if (isJdkClass(instanceToClone)) {
            return instanceToClone;
        }
        // don't clone proxies
        if (isProxy(instanceToClone)) {
            return instanceToClone;
        }
        // try to clone it ourselves
        Object clonedInstance = createInstanceUsingObjenesis(instanceToClone);

        // Unable to create an instance
        if (clonedInstance == null) {
            logger.warn("Could not create an instance of class " + instanceToClone.getClass() + " using objenesis");
            return instanceToClone;
        }
        // cache the clone
        cloneCache.put(instanceToClone, clonedInstance);

        // recursively do the same for all inner fields
        cloneFields(instanceToClone.getClass(), instanceToClone, clonedInstance, cloneCache);
        return clonedInstance;
    }


    /**
     * @param instanceToClone The instance, not null
     * @return True if the instance is immutable, e.g. a primitive
     */
    protected static boolean isImmutable(Object instanceToClone) {
        Class<?> clazz = instanceToClone.getClass();

        if (clazz.isPrimitive() || clazz.isEnum() || clazz.isAnnotation()) {
            return true;
        }
        if (instanceToClone instanceof Number || instanceToClone instanceof String || instanceToClone instanceof Character || instanceToClone instanceof Boolean) {
            return true;
        }
        if (clazz.getName().startsWith("com.google.common.collect") && clazz.getName().contains("Immutable")) {
            return true;
        }

        return false;
    }

    /**
{'fraction_non_alphanumeric': 0.08149030282408982, 'fraction_numerical': 0.0013610071452875127, 'mean_word_length': 2.724105163129553, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1374095', 'n_tokens_mistral': 3082, 'n_tokens_neox': 3085, 'n_words': 1181}