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

org.unitils.objectvalidation.EqualsHashCodeValidator Maven / Gradle / Ivy

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

import static java.lang.reflect.Modifier.isStatic;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.unitils.util.ReflectionUtils.getFieldValue;
import static org.unitils.util.ReflectionUtils.setFieldValue;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;



/**
 * Validate the equals and hashCode method.
 * 
 * This validator is created through the process of validation of an object : {@link ObjectValidator}.validate()
 * It has to receive a specific class and the list of fields that are in the equals and hashCode method.
 * 
 * It will generate a different object per field and compare them all to check if they are not equals.
 * 
 * @author Matthieu Mestrez
 * @since Oct 31, 2013
 */
public class EqualsHashCodeValidator {
    
    private static final Logger LOGGER = Logger.getLogger("org.unitils.objectvalidation");

    private ObjectCreator objectCreator;
    private ObjectCloner objectCloner;

    public EqualsHashCodeValidator(ObjectCreator objectCreator, ObjectCloner objectCloner) {
        this.objectCreator = objectCreator;
        this.objectCloner = objectCloner;
    }

    void validate(Class classToValidate, List fields) {
        Object randomObject = objectCreator.createRandomObject(classToValidate);
        Object copy = objectCloner.deepClone(randomObject);
        
        assertEquals("The object and its clone are expected to be equals", randomObject, copy);
        assertEquals("The object and its clone hashCodes are expected to be equals", randomObject.hashCode(), copy.hashCode());
        
        for (Field field : fields) {
            
            if (!isStatic(field.getModifiers())) {
        
                Object object = createDifferentObjectThan(field, randomObject);
                
                assertFalse("Objects were supposed to be different when changing field " + classToValidate.getName() + "." + field.getName() + " to another value : \nObject 1 : " + randomObject + " \nObject 2 : " + object, randomObject.equals(object));
                
                if (!field.getType().isPrimitive()) {
                    Object objectWithNullField = createObjectWithFieldNull(field, randomObject);
                    assertFalse("Objects were supposed to be different when changing field " + classToValidate.getName() + "." + field.getName() + " to null : \nObject 1 : " + randomObject + " \nObject 2 : " + objectWithNullField, randomObject.equals(objectWithNullField));
                }
            }
        }
        
    }
    
    private Object createDifferentObjectThan(Field field, Object randomObject) {
        Object randomField = objectCreator.createRandomObject(field.getGenericType());
        
        int maxSearchForRandom = 1000;
        Object differentObject = objectCloner.deepClone(randomObject);
        
        Object previousValue = getFieldValue(randomObject, field);
        while (sameValues(previousValue, randomField)) {
            randomField = objectCreator.createRandomObject(field.getGenericType());
            maxSearchForRandom--;
            if (maxSearchForRandom == 0) {
                fail("The validator was unable to create a different value for the field " + field.getName() + " of the class " + field.getDeclaringClass().getName() + " than " + randomField.toString());
            }
        }

        setFieldValue(differentObject, field, randomField);
        
        return differentObject;
    }
    
    private Object createObjectWithFieldNull(Field field, Object randomObject) {
        Object differentObject = objectCloner.deepClone(randomObject);
        
        setFieldValue(differentObject, field, null);
        
        return differentObject;
    }

    private boolean sameValues(Object previousValue, Object randomField) {
        return (primitiveEquals(previousValue, randomField)
            ||  arrayEquals(previousValue, randomField)
            || (previousValue.equals(randomField))) && randomField != null;
    }

    private boolean primitiveEquals(Object previousValue, Object randomField) {
        return previousValue.getClass().isPrimitive() && previousValue == randomField;
    }
    
    private boolean arrayEquals(Object previousValue, Object randomField) {
        if (previousValue.getClass().isArray()) {
            Class c = previousValue.getClass();
            if (!c.getComponentType().isPrimitive()) {
                c = Object[].class;
            }
            
            
            Method m;
            try {
                m = Arrays.class.getMethod("equals", c, c);
                return (Boolean) m.invoke(null, previousValue, randomField);
            } catch (SecurityException e) {
                LOGGER.log(Level.SEVERE, "SecurityException when trying to access Arrays.equals method", e);
            } catch (NoSuchMethodException e) {
                LOGGER.log(Level.SEVERE, "NoSuchMethodException when trying to access Arrays.equals method", e);
            } catch (IllegalArgumentException e) {
                LOGGER.log(Level.SEVERE, "Arguments when invoking Arrays.equals method are wrong", e);
            } catch (IllegalAccessException e) {
                LOGGER.log(Level.SEVERE, "IllegalAccessException when invoking Arrays.equals", e);
            } catch (InvocationTargetException e) {
                LOGGER.log(Level.SEVERE, "InvocationTargetException when invoking Arrays.equals", e);
            }
            
        }
        return false;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy