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:
 The generated@Canonical(includeNames=true, excludes='c')@ToString(excludes='a,b') class MyClass { ... }
toString will include property names and exclude the a and b properties.
 
 A class created using @Canonical has the following characteristics:
 
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)'