Added 'finer' logging for the clone() method to provide visibility for
debugging. Added a setClonedValue() method to force uncloned or precloned references in some specific use-cases. Added an isCloned() method to tell if an object has already been cloned in this cloner's 'session'.
This commit is contained in:
parent
c6aac78f42
commit
2028f3b3f8
@ -37,6 +37,8 @@ import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.logging.Logger;
|
||||
import java.util.logging.Level;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
@ -97,6 +99,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||
*/
|
||||
public class Cloner {
|
||||
|
||||
static Logger log = Logger.getLogger(Cloner.class.getName());
|
||||
|
||||
/**
|
||||
* Keeps track of the objects that have been cloned so far.
|
||||
*/
|
||||
@ -190,14 +194,24 @@ public class Cloner {
|
||||
* method called.
|
||||
*/
|
||||
public <T> T clone( T object, boolean useFunctions ) {
|
||||
|
||||
if( object == null ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if( log.isLoggable(Level.FINER) ) {
|
||||
log.finer("cloning:" + object.getClass() + "@" + System.identityHashCode(object));
|
||||
}
|
||||
|
||||
Class<T> type = objectClass(object);
|
||||
|
||||
// Check the index to see if we already have it
|
||||
Object clone = index.get(object);
|
||||
if( clone != null ) {
|
||||
if( log.isLoggable(Level.FINER) ) {
|
||||
log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object)
|
||||
+ " as cached:" + clone.getClass() + "@" + System.identityHashCode(clone));
|
||||
}
|
||||
return type.cast(clone);
|
||||
}
|
||||
|
||||
@ -213,6 +227,15 @@ public class Cloner {
|
||||
// Now call the function again to deep clone the fields
|
||||
f.cloneFields(this, result, object);
|
||||
|
||||
if( log.isLoggable(Level.FINER) ) {
|
||||
if( result == null ) {
|
||||
log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object)
|
||||
+ " as transformed:null");
|
||||
} else {
|
||||
log.finer("clone:" + object.getClass() + "@" + System.identityHashCode(object)
|
||||
+ " as transformed:" + result.getClass() + "@" + System.identityHashCode(result));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -246,6 +269,10 @@ public class Cloner {
|
||||
throw new IllegalArgumentException("Object is not cloneable, type:" + type);
|
||||
}
|
||||
|
||||
if( log.isLoggable(Level.FINER) ) {
|
||||
log.finer("cloned:" + object.getClass() + "@" + System.identityHashCode(object)
|
||||
+ " as " + clone.getClass() + "@" + System.identityHashCode(clone));
|
||||
}
|
||||
return type.cast(clone);
|
||||
}
|
||||
|
||||
@ -272,6 +299,27 @@ public class Cloner {
|
||||
return (CloneFunction<T>)functions.get(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Forces an object to be added to the indexing cache such that attempts
|
||||
* to clone the 'original' will always result in the 'clone' being returned.
|
||||
* This can be used to stub out specific values from being cloned or to
|
||||
* force global shared instances to be used even if the object is cloneable
|
||||
* normally.
|
||||
*/
|
||||
public <T> void setClonedValue( T original, T clone ) {
|
||||
index.put(original, clone);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the specified object has already been cloned
|
||||
* by this cloner during this session. Cloned objects are cached
|
||||
* for later use and it's sometimes convenient to know if some
|
||||
* objects have already been cloned.
|
||||
*/
|
||||
public boolean isCloned( Object o ) {
|
||||
return index.containsKey(o);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears the object index allowing the cloner to be reused for a brand new
|
||||
* cloning operation.
|
||||
|
Loading…
x
Reference in New Issue
Block a user