@ -37,6 +37,8 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method ;
import java.lang.reflect.Method ;
import java.util.HashMap ;
import java.util.HashMap ;
import java.util.IdentityHashMap ;
import java.util.IdentityHashMap ;
import java.util.logging.Logger ;
import java.util.logging.Level ;
import java.util.Map ;
import java.util.Map ;
import java.util.concurrent.ConcurrentHashMap ;
import java.util.concurrent.ConcurrentHashMap ;
@ -97,6 +99,8 @@ import java.util.concurrent.ConcurrentHashMap;
* /
* /
public class Cloner {
public class Cloner {
static Logger log = Logger . getLogger ( Cloner . class . getName ( ) ) ;
/ * *
/ * *
* Keeps track of the objects that have been cloned so far .
* Keeps track of the objects that have been cloned so far .
* /
* /
@ -190,14 +194,24 @@ public class Cloner {
* method called .
* method called .
* /
* /
public < T > T clone ( T object , boolean useFunctions ) {
public < T > T clone ( T object , boolean useFunctions ) {
if ( object = = null ) {
if ( object = = null ) {
return null ;
return null ;
}
}
if ( log . isLoggable ( Level . FINER ) ) {
log . finer ( "cloning:" + object . getClass ( ) + "@" + System . identityHashCode ( object ) ) ;
}
Class < T > type = objectClass ( object ) ;
Class < T > type = objectClass ( object ) ;
// Check the index to see if we already have it
// Check the index to see if we already have it
Object clone = index . get ( object ) ;
Object clone = index . get ( object ) ;
if ( clone ! = null ) {
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 ) ;
return type . cast ( clone ) ;
}
}
@ -213,6 +227,15 @@ public class Cloner {
// Now call the function again to deep clone the fields
// Now call the function again to deep clone the fields
f . cloneFields ( this , result , object ) ;
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 ;
return result ;
}
}
@ -246,6 +269,10 @@ public class Cloner {
throw new IllegalArgumentException ( "Object is not cloneable, type:" + type ) ;
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 ) ;
return type . cast ( clone ) ;
}
}
@ -272,6 +299,27 @@ public class Cloner {
return ( CloneFunction < T > ) functions . get ( type ) ;
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
* Clears the object index allowing the cloner to be reused for a brand new
* cloning operation .
* cloning operation .