程式扎記: [ GroovyGN ] Tuple Constructor Creation

標籤

2015年1月30日 星期五

[ GroovyGN ] Tuple Constructor Creation

Source From Here
Preface
Groovy 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 Creation
If you run below code, you will raise Exception=groovy.lang.GroovyRuntimeException: Could not find matching constructor:
  1. import groovy.transform.TupleConstructor  
  2.   
  3. //@TupleConstructor()  
  4. class Person {  
  5.     String name  
  6.     List likes  
  7.     private boolean active = false  
  8. }  
  9.   
  10. def person = new Person('mrhaki', ['Groovy''Java'])  
  11.   
  12. assert person.name == 'mrhaki'  
  13. assert person.likes == ['Groovy''Java']  
  14.   
  15. person = new Person('mrhaki')  
  16.   
  17. assert person.name == 'mrhaki'  
  18. 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.
  1. @TupleConstructor(includeFields=true)  
  2. class Person {  
  3.     String name  
  4.     List likes  
  5.     private boolean active = false  
  6.   
  7.     boolean isActivated() { active }  
  8. }  
  9.   
  10. def person = new Person('mrhaki', ['Groovy''Java'], true)  
  11.   
  12. assert person.name == 'mrhaki'  
  13. assert person.likes == ['Groovy''Java']  
  14. assert person.activated  
  15.   
  16. def classArgs = ["a", [], true]  
  17. def originalMapConstructor = Person.metaClass.retrieveConstructor(classArgs.toArray())  
  18. 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.
  1. // use force attribute to force creation of constructor  
  2. // even if we define our own constructors.  
  3. import groovy.transform.TupleConstructor  
  4.   
  5. @TupleConstructor(force=true)  
  6. class Person {  
  7.     String name  
  8.     List likes  
  9.     private boolean active = false  
  10.   
  11.     // Our customized constructor  
  12.     Person(boolean active) {  
  13.         this.active = active  
  14.     }  
  15.   
  16.     boolean isActivated() { active }  
  17. }  
  18.   
  19. def person = new Person('mrhaki', ['Groovy''Java'])  
  20.   
  21. assert person.name == 'mrhaki'  
  22. assert person.likes == ['Groovy''Java']  
  23. assert !person.activated  
  24.   
  25. person = new Person(true)  
  26.   
  27. 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 andincludeSuperFields. 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.
  1. // include properties and fields from super class.  
  2. import groovy.transform.TupleConstructor  
  3.   
  4. @TupleConstructor(includeFields=true)  
  5. class Person {  
  6.     String name  
  7.     List likes  
  8.     private boolean active = false  
  9.   
  10.     boolean isActivated() { active }  
  11. }  
  12.   
  13. @TupleConstructor(callSuper=true, includeSuperProperties=true, includeSuperFields=true)  
  14. class Student extends Person {  
  15.     List courses  
  16. }  
  17.   
  18. def student = new Student('mrhaki', ['Groovy''Java'], true, ['IT'])  
  19.   
  20. assert student.name == 'mrhaki'  
  21. assert student.likes == ['Groovy''Java']  
  22. assert student.activated  
  23. assert student.courses == ['IT']  
  24.   
  25. printf("\t[Info] List all constructors of class Student:\n")  
  26. for(Constructor cstr in Student.class.getDeclaredConstructors())  
  27. {  
  28.     printf("\t%s\n", cstr)  
  29. }  
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...


沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!