org.unitils.objectvalidation.EqualsHashCodeValidator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of unitils-objectvalidation Show documentation
Show all versions of unitils-objectvalidation Show documentation
Unitils module to validate objects.
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;
}
}