Annotation Type AutoClone
-
@Documented @Retention(RUNTIME) @Target(TYPE) public @interface AutoClone
Note: This annotation is currently experimental! Use at your own risk! Class annotation used to assist in the creation ofCloneable
classes. The@AutoClone
annotation instructs the compiler to execute an AST transformation which adds a publicclone()
method and addsCloneable
to the list of interfaces which the class implements. Because the JVM doesn't have a one-size fits all cloning strategy, several customizations exist for the cloning implementation. By default, theclone()
method will callsuper.clone()
before callingclone()
on eachCloneable
property of the class. Example usage:import groovy.transform.AutoClone
Which will create a class of the following form:@AutoClone
class Person { String first, last List favItems Date since }class Person implements Cloneable { ... public Object clone() throws CloneNotSupportedException { Object result = super.clone() result.favItems = favItems.clone() result.since = since.clone() return result } ... }
Which can be used as follows:def p = new Person(first:'John', last:'Smith', favItems:['ipod', 'shiraz'], since:new Date()) def p2 = p.clone() assert p instanceof Cloneable assert p.favItems instanceof Cloneable assert p.since instanceof Cloneable assert !(p.first instanceof Cloneable) assert !p.is(p2) assert !p.favItems.is(p2.favItems) assert !p.since.is(p2.since) assert p.first.is(p2.first)
In the above example,super.clone()
is called which in this case callsclone()
fromjava.lang.Object
. This does a bit-wise copy of all the properties (references and primitive values). Properties likefirst
has typeString
which is notCloneable
so it is left as the bit-wise copy. BothDate
andArrayList
areCloneable
so theclone()
method on each of those properties will be called. For the list, a shallow copy is made during itsclone()
method. If your classes require deep cloning, it is up to you to provide the appropriate deep cloning logic in the respectiveclone()
method for your class. If one of your properties contains an object that doesn't support cloning or attempts deep copying of a data structure containing an object that doesn't support cloning, then aCloneNotSupportedException
may occur at runtime. Another popular cloning strategy is known as the copy constructor pattern. If any of your fields arefinal
andCloneable
you should setstyle=COPY_CONSTRUCTOR
which will then use the copy constructor pattern. Here is an example making use of the copy constructor pattern:import groovy.transform.AutoClone import static groovy.transform.AutoCloneStyle.*
Which will create classes of the following form:@AutoClone(style=COPY_CONSTRUCTOR)
class Person { final String first, last final Date birthday }@AutoClone(style=COPY_CONSTRUCTOR)
class Customer extends Person { final int numPurchases final List favItems }class Person implements Cloneable { ... protected Person(Person other) throws CloneNotSupportedException { first = other.first last = other.last birthday = other.birthday.clone() } public Object clone() throws CloneNotSupportedException { return new Person(this) } ... } class Customer extends Person { ... protected Customer(Customer other) throws CloneNotSupportedException { super(other) numPurchases = other.numPurchases favItems = other.favItems.clone() } public Object clone() throws CloneNotSupportedException { return new Customer(this) } ... }
If you use this style on a child class, the parent class must also have a copy constructor (created using this annotation or by hand). This approach can be slightly slower than the traditional cloning approach but theCloneable
fields of your class can be final. As a final example, if your class already implements theSerializable
orExternalizable
interface, you can choose the following cloning style:@AutoClone(style=SERIALIZATION)
class Person implements Serializable { String first, last Date birthday }class Person implements Cloneable, Serializable { ... Object clone() throws CloneNotSupportedException { def baos = new ByteArrayOutputStream() baos.withObjectOutputStream{ it.writeObject(this) } def bais = new ByteArrayInputStream(baos.toByteArray()) bais.withObjectInputStream(getClass().classLoader){ it.readObject() } } ... }
This will output an error if your class doesn't implement one ofSerializable
orExternalizable
, will typically be significantly slower than the other approaches, also doesn't allow fields to be final, will take up more memory as even immutable classes like String will be cloned but does have the advantage that it performs deep cloning automatically. Further references on cloning:- Since:
- 1.8.0
- Author:
- Paul King
- See Also:
AutoCloneStyle
,AutoExternalize
-
-
Optional Element Summary
Optional Elements Modifier and Type Optional Element Description java.lang.String
excludes
Comma separated list of property (and/or field) names to exclude from cloning.boolean
includeFields
Include fields as well as properties when cloning.AutoCloneStyle
style
Style to use when cloning
-
-
-
Element Detail
-
excludes
java.lang.String excludes
Comma separated list of property (and/or field) names to exclude from cloning.
NOTE: When using the CLONE style, property (and/or field) copying might occur as part of calling
super.clone()
which will ignore this list. You can then use this list to streamline the providedclone()
implementation by selecting which properties (and/or fields) will have a subsequent call to theirclone()
method. If you have immutable properties (and/or fields) this can be useful as the extraclone()
will not be necessary and cloning will be more efficient.NOTE: This doesn't affect property (and/or field) copying that might occur as part of serialization when using the SERIALIZATION style, i.e. this flag is ignored; instead adjust your serialization code to include or exclude the desired properties (and/or fields) which should carry over during cloning.
- Default:
- ""
-
-
-
includeFields
boolean includeFields
Include fields as well as properties when cloning.
NOTE: When using the CLONE style, field copying might occur as part of calling
super.clone()
and might be all you require; if you turn on this flag, the providedclone()
implementation will also subsequently callclone()
for each field which can be useful if you have mutable fields.NOTE: This doesn't affect field copying that might occur as part of serialization when using the SERIALIZATION style, i.e. this flag is ignored; instead adjust your serialization code to include or exclude your fields.
- Default:
- false
-
-
-
style
AutoCloneStyle style
Style to use when cloning- Default:
- groovy.transform.AutoCloneStyle.CLONE
-
-