AutoClone (Groovy 5.0.7)

Package: groovy.transform

## [Java] Annotation Type AutoClone

- groovy.transform.AutoClone

-     @Documented
      @Retention(RetentionPolicy.SOURCE)
      @Target(ElementType.TYPE)
      @GroovyASTTransformationClass("org.codehaus.groovy.transform.AutoCloneASTTransformation")
      public @interface AutoClone

  Class annotation used to assist in the creation of `Cloneable` classes. The `@AutoClone` annotation instructs the compiler to execute an AST transformation which adds a public `clone()` method and adds `Cloneable` 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, the `clone()` method will call `super.clone()` before calling `clone()` on each `Cloneable` property of the class.

  Example usage:

       import groovy.transform.AutoClone
       @AutoClone
       class Person {
         String first, last
         List favItems
         Date since
       }

  Which will create a class equivalent to the following:

       class Person implements Cloneable {
         ...
         public Person clone() throws CloneNotSupportedException {
           Person result = (Person) super.clone()
           result.favItems = favItems instanceof Cloneable ? (List) favItems.clone() : favItems
           result.since = (Date) 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 calls `clone()` from `java.lang.Object`. This does a bit-wise copy of all the properties (references and primitive values). Properties like `first` has type `String` which is not `Cloneable` so it is left as the bit-wise copy. Both `Date` and `ArrayList` are `Cloneable` so the `clone()` method on each of those properties will be called. For the list, a shallow copy is made during its `clone()` method.

  If your classes require deep cloning, it is up to you to provide the appropriate deep cloning logic in the respective `clone()` 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 a `CloneNotSupportedException` may occur at runtime.

  Another popular cloning strategy is known as the copy constructor pattern. If any of your fields are `final` and `Cloneable` you should set `style=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.*
       @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
       }

  Which will create classes equivalent to the following:

       class Person implements Cloneable {
         ...
         protected Person(Person other) throws CloneNotSupportedException {
           first = other.first
           last = other.last
           birthday = (Date) other.birthday.clone()
         }
         public Person 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 instanceof Cloneable ? (List) other.favItems.clone() : other.favItems
         }
         public Customer 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 the `Cloneable` fields of your class can be final. When using the copy constructor style, you can provide your own custom constructor by hand if you wish. If you do so, it is up to you to correctly copy, clone or deep clone the properties of your class.

  As a variation of the last two styles, if you set `style=SIMPLE` then the no-arg constructor will be called followed by setting the individual properties (and/or fields) calling `clone()` if the property/field implements `Cloneable`. Here is an example:

       import groovy.transform.AutoClone
       import static groovy.transform.AutoCloneStyle.*
       @AutoClone(style=SIMPLE)
       class Person {
         final String first, last
         final Date birthday
       }
       @AutoClone(style=SIMPLE)
       class Customer {
         final List favItems
       }

  Which will create classes equivalent to the following:

       class Person implements Cloneable {
         ...
         public Person clone() throws CloneNotSupportedException {
           def result = new Person()
           copyOrCloneMembers(result)
           return result
         }
         protected void copyOrCloneMembers(Person other) {
           other.first = first
           other.last = last
           other.birthday = (Date) birthday.clone()
         }
         ...
       }
       class Customer extends Person {
         ...
         public Customer clone() throws CloneNotSupportedException {
           def result = new Customer()
           copyOrCloneMembers(result)
           return result
         }
         protected void copyOrCloneMembers(Customer other) {
           super.copyOrCloneMembers(other)
           other.favItems = favItems instanceof Cloneable ? (List) favItems.clone() : favItems
         }
         ...
       }

  You would typically use this style only for base classes where you didn't want the normal `Object` `clone()` method to be called and you would typically need to use the `SIMPLE` style for any child classes.

  As a final example, if your class already implements the `Serializable` or `Externalizable` interface, you can choose the following cloning style:

       @AutoClone(style=SERIALIZATION)
       class Person implements Serializable {
         String first, last
         Date birthday
       }

  which outputs a class with the following form:

       class Person implements Cloneable, Serializable {
         ...
         Person clone() throws CloneNotSupportedException {
           def baos = new ByteArrayOutputStream()
           baos.withObjectOutputStream{ it.writeObject(this) }
           def bais = new ByteArrayInputStream(baos.toByteArray())
           bais.withObjectInputStream(getClass().classLoader){ (Person) it.readObject() }
         }
         ...
       }

  This will output an error if your class doesn't implement one of `Serializable` or `Externalizable`, 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:

  - http://www.codeguru.com/java/tij/tij0128.shtml
  - http://www.artima.com/objectsandjava/webuscript/ClonCollInner1.html
  - http://courses.dce.harvard.edu/~cscie160/JDCTipsCloning
  - http://www.agiledeveloper.com/articles/cloning072002.htm
  See Also:
    AutoCloneStyle
    ExternalizeMethods
  Since:
    1.8.0

- - ### Element Summary

    Optional Element Summary
    Type | Name and Description
    --- | ---
    `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.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Element Detail

    - #### public String[] excludes

      Comma separated list of property (and/or field) names to exclude from cloning. For convenience, a String with comma separated names can be used in addition to an array (using Groovy's literal list notation) of String values.

      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 provided `clone()` implementation by selecting which Cloneable properties (and/or fields) will have a subsequent call to their `clone()` method. If you have immutable properties (and/or fields) this can be useful as the extra `clone()` 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:
        {}

    - #### public 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 provided `clone()` implementation will also subsequently call `clone()` for each `Cloneable` 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

    - #### public AutoCloneStyle style

      Style to use when cloning.

      Default:
        AutoCloneStyle.CLONE