@Documented
 @Retention(value=RUNTIME)
 @Target(value={ANNOTATION_TYPE,TYPE})
public @interface AnnotationCollector
          import groovy.transform.*
          @AnnotationCollector([ToString, EqualsAndHashCode, Immutable])
          @interface Alias {}
          @Alias(excludes=["a"])
          class Foo {
              Integer a, b
          }
          assert Foo.class.annotations.size()==3 
          assert new Foo(1,2).toString() == "Foo(2)"
 
 In the example above we have Alias as the alias annotation and an argument
 excludes which will be mapped to ToString and EqualsAndHashCode. Immutable 
 doesn't have excludes, thus nothing will be done there.
 import groovy.transform.*
 @ToString(excludes=["a"])
 @EqualsAndHashCode
 @Immutable
 @AnnotationCollector
 @interface Alias {}
 @Alias
 class Foo {
     Integer a, b
 }
 assert Foo.class.annotations.size()==3
 assert new Foo(1,2).toString() == "Foo(2)"
 
 In the example above we have again Alias as the alias annotation, but
 this time the argument is part of the alias. Instead of mapping excludes to
 ToString as well as EqualsAndHashCode, only ToString will have the excludes.
 Again the alias can have an argument excludes, which would overwrite the 
 excludes given in from the definition and be mapped to ToString as well as
 EqualsAndHashCode.
 If both ways are combined, then the list overwrites annotation usage.
 NOTE: The aliasing does not support aliasing of aliased annotations. 
 More examples:
 //--------------------------------------------------------------------------
 import groovy.transform.*
 @AnnotationCollector([EqualsAndHashCode, ToString])
 @interface Simple {}
 @Simple
 class User {
     String username
     int age
 }
 def user = new User(username: 'mrhaki', age: 39)
 assert user.toString() == 'User(mrhaki, 39)'
 // We still have 2 annotations:
 assert User.class.annotations.size() == 2
 // We can use the attributes from the 
 // grouped annotations.
 @Simple(excludes = 'street')
 class Address {
     String street, town
 }
 def address = new Address(street: 'Evergreen Terrace', town: 'Springfield') 
 assert address.toString() == 'Address(Springfield)'
 
 
 //--------------------------------------------------------------------------
 // Use a custom processor to handle attributes.
 import org.codehaus.groovy.transform.*
 import org.codehaus.groovy.ast.*
 import org.codehaus.groovy.control.*
 class SimpleProcessor extends AnnotationCollectorTransform {
     public List<AnnotationNode> visit(AnnotationNode collector, 
                                       AnnotationNode aliasAnnotationUsage, 
                                       AnnotatedNode aliasAnnotated, 
                                       SourceUnit source) {
         // Get attributes and attribute value for dontUse.
         def attributes = aliasAnnotationUsage.getMembers()
         def dontUse = attributes.get('dontUse')
         attributes.remove('dontUse')
         if (dontUse) {
             // Assign value of dontUse to excludes attributes.
             aliasAnnotationUsage.addMember("excludes", dontUse)
         }
         super.visit(collector, aliasAnnotationUsage, aliasAnnotated, source)
     }
 }
 new GroovyShell(this.class.classLoader).evaluate '''
 import groovy.transform.*
 @AnnotationCollector(value = [EqualsAndHashCode, ToString], processor = 'SimpleProcessor')
 @interface Simple {}
 @Simple(dontUse = 'age')
 class User {
     String username
     int age
 }
 def user = new User(username: 'mrhaki', age: 39)
 assert user.toString() == 'User(mrhaki)'
 '''
 
 
 //--------------------------------------------------------------------------
 // Use AnnotationCollector as last annotation to group the
 // previous annotations.
 import groovy.transform.*
 @EqualsAndHashCode
 @ToString
 @AnnotationCollector
 @interface Simple {}
 @Simple
 class User {
     String username
 }
 def user = new User(username: 'mrhaki')
 assert user.toString() == 'User(mrhaki)'
 AnnotationCollectorTransformpublic abstract java.lang.String processor