Canonical (Groovy 5.0.6)

Package: groovy.transform

## [Groovy] Annotation Type Canonical

- groovy.transform.Canonical

- All Implemented Interfaces and Traits:
    Annotation

      @AnnotationCollector(value: [ToString, TupleConstructor, EqualsAndHashCode], mode: AnnotationCollectorMode.PREFER_EXPLICIT_MERGED)
      @Retention(value: RetentionPolicy.SOURCE)
      @Target(value: ElementType.TYPE)
      @interface Canonical

  The `@Canonical` meta-annotation combines the `@EqualsAndHashCode`, `@ToString` and `@TupleConstructor` annotations. It is used to assist in the creation of mutable classes. It instructs the compiler to execute AST transformations which add positional constructors, equals, hashCode and a pretty print toString to your class.

  You can write classes in this shortened form:

       import groovy.transform.Canonical
       @Canonical class Customer {
           String first, last
           int age
           Date since
           Collection favItems = ['Food']
           def object
       }
       def d = new Date()
       def anyObject = new Object()
       def c1 = new Customer(first:'Tom', last:'Jones', age:21, since:d, favItems:['Books', 'Games'], object: anyObject)
       def c2 = new Customer('Tom', 'Jones', 21, d, ['Books', 'Games'], anyObject)
       assert c1 == c2

  You don't need to provide all arguments in constructor calls. If using named parameters, any property names not referenced will be given their default value (as per Java's default unless an explicit initialization constant is provided when defining the property). If using a tuple constructor, parameters are supplied in the order in which the properties are defined. Supplied parameters fill the tuple from the left. Any parameters missing on the right are given their default value.

       def c3 = new Customer(last: 'Jones', age: 21)
       def c4 = new Customer('Tom', 'Jones')

       assert null == c3.since
       assert 0 == c4.age
       assert c3.favItems == ['Food'] && c4.favItems == ['Food']

  If you don't need all of the functionality of `@Canonical`, you can simply directly use one or more of the individual annotations which `@Canonical` aggregates. In addition, you can use `@Canonical` in combination with explicit use one or more of the individual annotations in cases where you need to further customize the annotation attributes. Any applicable annotation attributes from `@Canonical` missing from the explicit annotation will be merged but any existing annotation attributes within the explicit annotation take precedence. So, for example in this case here:

       @Canonical(includeNames=true, excludes='c')
       @ToString(excludes='a,b')
       class MyClass { ... }

  The generated `toString` will include property names and exclude the `a` and `b` properties.

  A class created using `@Canonical` has the following characteristics:

  - A no-arg constructor is provided which allows you to set properties by name using Groovy's normal bean conventions.
  - Tuple-style constructors are provided which allow you to set properties in the same order as they are defined.
  - Default `equals`, `hashCode` and `toString` methods are provided based on the property values. See the GroovyDoc for the individual annotations for more details.

    If you want similar functionality to what this annotation provides but also require immutability, see the `@`Immutable annotation.

    More examples:

         import groovy.transform.*

         @Canonical
         class Building {
             String name
             int floors
             boolean officeSpace
         }

         // Constructors are added.
         def officeSpace = new Building('Initech office', 1, true)

         // toString() added.
         assert officeSpace.toString() == 'Building(Initech office, 1, true)'

         // Default values are used if constructor
         // arguments are not assigned.
         def theOffice = new Building('Wernham Hogg Paper Company')
         assert theOffice.floors == 0
         theOffice.officeSpace = true

         def anotherOfficeSpace = new Building(name: 'Initech office', floors: 1, officeSpace: true)

         // equals() method is added.
         assert anotherOfficeSpace == officeSpace

         // equals() and hashCode() are added, so duplicate is not in Set.
         def offices = [officeSpace, anotherOfficeSpace, theOffice] as Set
         assert offices.size() == 2
         assert offices.name.join(',') == 'Initech office,Wernham Hogg Paper Company'

         @Canonical
         @ToString(excludes='age')  // Customize one of the transformations.
         class Person {
             String name
             int age
         }

         def mrhaki = new Person('mrhaki', 37)
         assert mrhaki.toString() == 'Person(mrhaki)'

    See Also:
      EqualsAndHashCode
      ToString
      TupleConstructor
      Immutable
    Since:
      1.8.0

- - ### Inherited Methods Summary

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