: : I believe this code shows some promise ;-)
: : It also suggests that my original plan - of implementing hashCode using
: : a similar techniques - is going to be extremely simple. The entire
: : object is in a byte array at one point - so calculating a CRC should
: : not be difficult.
: : Lastly, equals() is also apparently an attractive target using this
: : approach ;-)
: Well, here we go:
: This code is totally untested.
Here's a refactored, cleaned up, debugged - and more tested version
(suggestions are - of course - still welcome).
It seems to work OK. I'm reasonably happy with what it does
when encountering a non-serializable class.
Deep copying, deep equality testing and deep hash code computation
are rather fundamental Java programming problems.
They ought really to be solved in the JDK.
There's copy/deepCopy in Smalltalk, Clone in C#, copy.copy in
Python and deep_clone in Eiffel - but there's nothing built-in
in Java.
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.i
bjectInputStream;
import java.i
bjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.zip.CRC32;
import java.util.zip.Checksum;
public class ObjectUtilities implements Cloneable, Serializable {
/**
* Deep clone an object
*
* To use this - use code such as:
*
* public Object clone() {
* return ObjectUtilities.clone(this);
* }
*
* @param object - object to be copied
* @return - a copy of the object
*/
public static Object clone(Object object) {
byte[] ba = serializeToByteArray(object);
try {
ByteArrayInputStream bais = new ByteArrayInputStream(ba);
ObjectInputStream ois = new ObjectInputStream(bais);
object = ois.readObject();
ois.close();
} catch (IOException e) {
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
return object;
}
/**
* Deep test for equality
* Note: all objects must be serializable
*
* To use this - use code such as:
*
* public boolean equals(Object object) {
* return ObjectUtilities.equals(this, object);
* }
*
* @param object1 - the first object
* @param object2 - the second object
* @return - true iff the two objects have equal contents
*/
public static boolean equals(Object object1, Object object2) {
return equals(serializeToByteArray(object1), serializeToByteArray(object2));
}
/**
* Deep hash code
* Note: all objects must be serializable
*
* To use this - use code such as:
*
* public int hashCode(Object object) {
* return ObjectUtilities.hashCode(this);
* }
*
* @param object - the object to be hashed
* @return - the hash code
*/
public static int hashCode(Object object) {
return hashCode(object, new CRC32());
}
/**
* Deep hash code
* Note: all objects must be serializable
*
* To use this - use code such as:
*
* public int hashCode(Object object) {
* return ObjectUtilities.hashCode(this, new CRC32());
* }
*
* @param object - the object to be hashed
* @param checksum - java.util.zip.Checksum instance to be used to compute the hash
* @return - the hash code
*/
public static int hashCode(Object object, Checksum checksum) {
byte[] bytes = serializeToByteArray(object);
checksum.update(bytes, 0, bytes.length);
return (int) checksum.getValue();
}
private static byte[] serializeToByteArray(Object object) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
oos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
return baos.toByteArray();
}
private static boolean equals(byte[] bytes1, byte[] bytes2) {
int length = bytes1.length;
if (length != bytes2.length) {
return false;
}
for (int i = length; --i >= 0
{
if (bytes1
!= bytes2) {
return false;
}
}
return true;
}
}