Source From HerePrefaceGroovy 1.8 adds the
@TupleConstructor annotation. With this annotation we can
automatically create a tuple constructor at compile time. So the constructor can be found in the compiled class. For each property in the class a parameter in the constructor is created with a default value. The order of the properties defined in the class also defines the order of parameters in the constructor. Because the parameters have default values we can use Groovy syntax and leave parameters at the end of the parameter list out when we use the constructor.
Tuple Constructor CreationIf you run below code, you will raise Exception=
groovy.lang.GroovyRuntimeException: Could not find matching constructor:
- import groovy.transform.TupleConstructor
-
-
- class Person {
- String name
- List likes
- private boolean active = false
- }
-
- def person = new Person('mrhaki', ['Groovy', 'Java'])
-
- assert person.name == 'mrhaki'
- assert person.likes == ['Groovy', 'Java']
-
- person = new Person('mrhaki')
-
- assert person.name == 'mrhaki'
- assert !person.likes
If you uncomment the "
@TupleConstructor", the code will run correctly!
We can also include fields as constructor parameters. We use the annotation attribute
includeFields=true to activate this.
- @TupleConstructor(includeFields=true)
- class Person {
- String name
- List likes
- private boolean active = false
-
- boolean isActivated() { active }
- }
-
- def person = new Person('mrhaki', ['Groovy', 'Java'], true)
-
- assert person.name == 'mrhaki'
- assert person.likes == ['Groovy', 'Java']
- assert person.activated
-
- def classArgs = ["a", [], true]
- def originalMapConstructor = Person.metaClass.retrieveConstructor(classArgs.toArray())
- assert originalMapConstructor!=null
This time you can observe the input parameters of constructor including private field
actived!
If we define our constructors in the class, then the @TupleConstructor annotation will not create extra constructors. But we can override this behaviour with the attribute value
force=true. We have to make sure we don't have constructor conflicts ourselves, because now the annotation will create the extra constructors.
-
-
- import groovy.transform.TupleConstructor
-
- @TupleConstructor(force=true)
- class Person {
- String name
- List likes
- private boolean active = false
-
-
- Person(boolean active) {
- this.active = active
- }
-
- boolean isActivated() { active }
- }
-
- def person = new Person('mrhaki', ['Groovy', 'Java'])
-
- assert person.name == 'mrhaki'
- assert person.likes == ['Groovy', 'Java']
- assert !person.activated
-
- person = new Person(true)
-
- assert person.activated
If our class extends another class and we want to include the properties or fields of the super class we can use the attributes
includeSuperProperties and
includeSuperFields. We can even instruct the annotation to create code in the constructor to call the super constructor of the super class with setting the annotation attribute
callSuper=true to make this happen.
-
- import groovy.transform.TupleConstructor
-
- @TupleConstructor(includeFields=true)
- class Person {
- String name
- List likes
- private boolean active = false
-
- boolean isActivated() { active }
- }
-
- @TupleConstructor(callSuper=true, includeSuperProperties=true, includeSuperFields=true)
- class Student extends Person {
- List courses
- }
-
- def student = new Student('mrhaki', ['Groovy', 'Java'], true, ['IT'])
-
- assert student.name == 'mrhaki'
- assert student.likes == ['Groovy', 'Java']
- assert student.activated
- assert student.courses == ['IT']
-
- printf("\t[Info] List all constructors of class Student:\n")
- for(Constructor cstr in Student.class.getDeclaredConstructors())
- {
- printf("\t%s\n", cstr)
- }
Execution result:
[Info] List all constructors of class Student:
public Student()
public Student(java.lang.String)
public Student(java.lang.String,java.util.List)
public Student(java.lang.String,java.util.List,boolean)
public Student(java.lang.String,java.util.List,boolean,java.util.List)
Supplement*
Overriding Groovy constructors
It’s rare to create parameterized constructors in Groovy since the Map constructor that’s added to all classes reduces the need for “real” constructors. There’sstill a case for defining constructors to enforce business rules, for example if an instance requires certain fields to be set in order for it to be valid. But in general we tend to just use the Map constructor...
*
Finding Constructors
A constructor declaration includes the name, modifiers, parameters, and list of throwable exceptions. The
java.lang.reflect.Constructor class provides a way to obtain this information...