Augmentation property included in toString method in generated Builder classes.
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / BuilderTemplate.xtend
1 package org.opendaylight.yangtools.sal.java.api.generator\r
2 \r
3 import java.util.Arrays;\r
4 import java.util.LinkedHashSet\r
5 import java.util.List\r
6 import java.util.Map\r
7 import java.util.Set\r
8 import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl\r
9 import org.opendaylight.yangtools.binding.generator.util.Types\r
10 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl\r
11 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty\r
12 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject\r
13 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType\r
14 import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature\r
15 import org.opendaylight.yangtools.sal.binding.model.api.Type\r
16 import org.opendaylight.yangtools.yang.binding.Augmentable\r
17 import static org.opendaylight.yangtools.binding.generator.util.Types.*\r
18 import java.util.HashMap\r
19 import java.util.Collections\rimport org.opendaylight.yangtools.yang.binding.DataObject
20 import java.util.ArrayList
21 import java.util.HashSet
22 import java.util.Collection
23 import org.opendaylight.yangtools.yang.binding.Identifiable
24
25 /**\r
26  * Template for generating JAVA builder classes. \r
27  */\r
28 \r
29 class BuilderTemplate extends BaseTemplate {\r
30 \r
31     /**\r
32      * Constant with the name of the concrete method.\r
33      */\r
34     val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"\r
35 \r
36     /**\r
37      * Constant with the suffix for builder classes.\r
38      */\r
39     val static BUILDER = 'Builder'\r
40 \r
41     /**\r
42      * Constant with suffix for the classes which are generated from the builder classes.\r
43      */\r
44     val static IMPL = 'Impl'\r
45 \r
46     /**\r
47      * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME\r
48      */\r
49     var GeneratedProperty augmentField\r
50 \r
51     /**\r
52      * Set of class attributes (fields) which are derived from the getter methods names\r
53      */\r
54     val Set<GeneratedProperty> properties\r
55 \r
56     /**\r
57      * Constructs new instance of this class.\r
58      * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>\r
59      */\r
60     new(GeneratedType genType) {\r
61         super(genType)\r
62         this.properties = propertiesFromMethods(createMethods)\r
63     }\r
64 \r
65     /**\r
66      * Returns set of method signature instances which contains all the methods of the <code>genType</code>\r
67      * and all the methods of the implemented interfaces.\r
68      * \r
69      * @returns set of method signature instances\r
70      */\r
71     def private Set<MethodSignature> createMethods() {\r
72         val Set<MethodSignature> methods = new LinkedHashSet\r
73         methods.addAll(type.methodDefinitions)\r
74         collectImplementedMethods(methods, type.implements)\r
75         return methods\r
76     }\r
77 \r
78     /**\r
79      * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code> \r
80      * and recursivelly their implemented interfaces.\r
81      * \r
82      * @param methods set of method signatures\r
83      * @param implementedIfcs list of implemented interfaces\r
84      */\r
85     def private void collectImplementedMethods(Set<MethodSignature> methods, List<Type> implementedIfcs) {\r
86         if (implementedIfcs == null || implementedIfcs.empty) {\r
87             return\r
88         }\r
89         for (implementedIfc : implementedIfcs) {\r
90             if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {\r
91                 val ifc = implementedIfc as GeneratedType\r
92                 methods.addAll(ifc.methodDefinitions)\r
93                 collectImplementedMethods(methods, ifc.implements)\r
94             } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {\r
95                 for (m : Augmentable.methods) {\r
96                     if (m.name == GET_AUGMENTATION_METHOD_NAME) {\r
97                         val fullyQualifiedName = m.returnType.name\r
98                         val pkg = fullyQualifiedName.package\r
99                         val name = fullyQualifiedName.name\r
100                         val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)\r
101                         val refType = new ReferencedTypeImpl(pkg, name)\r
102                         val generic = new ReferencedTypeImpl(type.packageName, type.name)\r
103                         val parametrizedReturnType = Types.parameterizedTypeFor(refType, generic)\r
104                         tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)\r
105                         augmentField = tmpGenTO.toInstance.methodDefinitions.first.propertyFromGetter\r
106                     }\r
107                 }\r
108             }\r
109         }\r
110     }\r
111 \r
112     /**\r
113      * Returns the first element of the list <code>elements</code>.\r
114      * \r
115      * @param list of elements\r
116      */\r
117     def private <E> first(List<E> elements) {\r
118         elements.get(0)\r
119     }\r
120 \r
121     /**\r
122      * Returns the name of the package from <code>fullyQualifiedName</code>.\r
123      * \r
124      * @param fullyQualifiedName string with fully qualified type name (package + type)\r
125      * @return string with the package name\r
126      */\r
127     def private String getPackage(String fullyQualifiedName) {\r
128         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)\r
129         return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)\r
130     }\r
131 \r
132         /**\r
133          * Returns the name of tye type from <code>fullyQualifiedName</code>\r
134          * \r
135          * @param fullyQualifiedName string with fully qualified type name (package + type)\r
136          * @return string with the name of the type\r
137          */\r
138     def private String getName(String fullyQualifiedName) {\r
139         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)\r
140         return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)\r
141     }\r
142 \r
143     /**\r
144      * Creates set of generated property instances from getter <code>methods</code>.\r
145      * \r
146      * @param set of method signature instances which should be transformed to list of properties \r
147      * @return set of generated property instances which represents the getter <code>methods</code>\r
148      */\r
149     def private propertiesFromMethods(Set<MethodSignature> methods) {\r
150         if (methods == null || methods.isEmpty()) {\r
151             return Collections.emptySet\r
152         }\r
153         val Set<GeneratedProperty> result = new LinkedHashSet\r
154         for (m : methods) {\r
155             val createdField = m.propertyFromGetter\r
156             if (createdField != null) {\r
157                 result.add(createdField)\r
158             }\r
159         }\r
160         return result\r
161     }\r
162 \r
163     /**\r
164      * Creates generated property instance from the getter <code>method</code> name and return type.\r
165      * \r
166      * @param method method signature from which is the method name and return type obtained\r
167      * @return generated property instance for the getter <code>method</code>\r
168      * @throws IllegalArgumentException<ul>\r
169      *  <li>if the <code>method</code> equals <code>null</code></li>\r
170      *  <li>if the name of the <code>method</code> equals <code>null</code></li>\r
171      *  <li>if the name of the <code>method</code> is empty</li>\r
172      *  <li>if the return type of the <code>method</code> equals <code>null</code></li>\r
173      * </ul>\r
174      */\r
175     def private GeneratedProperty propertyFromGetter(MethodSignature method) {\r
176         if (method == null || method.name == null || method.name.empty || method.returnType == null) {\r
177             throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")\r
178         }\r
179         var prefix = "get";\r
180         if(BOOLEAN.equals(method.returnType)) {\r
181             prefix = "is";\r
182         } \r
183         if (method.name.startsWith(prefix)) {\r
184             val fieldName = method.getName().substring(prefix.length()).toFirstLower\r
185             val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")\r
186             tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)\r
187             return tmpGenTO.toInstance.properties.first\r
188         }\r
189     }\r
190 \r
191     /**\r
192      * Template method which generates JAVA class body for builder class and for IMPL class. \r
193      * \r
194      * @return string with JAVA source code\r
195      */\r
196     override body() '''\r
197 \r
198         public class «type.name»«BUILDER» {\r
199 \r
200             «generateFields(false)»\r
201 \r
202             «generateConstructorsFromIfcs(type)»\r
203 \r
204             «generateMethodFieldsFrom(type)»\r
205 \r
206             «generateGetters(false)»\r
207 \r
208             «generateSetters»\r
209 \r
210             public «type.name» build() {\r
211                 return new «type.name»«IMPL»(this);\r
212             }\r
213 \r
214             private static final class «type.name»«IMPL» implements «type.name» {\r
215 \r
216                 «implementedInterfaceGetter»\r
217 \r
218                 «generateFields(true)»\r
219 \r
220                 «generateConstructor»\r
221 \r
222                 «generateGetters(true)»\r
223 \r
224                 «generateHashCode()»\r
225 \r
226                 «generateEquals()»\r
227                 \r
228                 «generateToString(properties)»\r
229             }\r
230 \r
231         }\r
232     '''\r
233 \r
234     /**\r
235      * Generate default constructor and constructor for every implemented interface from uses statements.\r
236      */\r
237     def private generateConstructorsFromIfcs(Type type) '''\r
238         public «type.name»«BUILDER»() {\r
239         } \r
240         «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
241             «val ifc = type as GeneratedType»\r
242             «FOR impl : ifc.implements»\r
243                 «generateConstructorFromIfc(impl)»\r
244             «ENDFOR»\r
245         «ENDIF»\r
246     '''\r
247 \r
248     /**\r
249      * Generate constructor with argument of given type.\r
250      */\r
251     def private generateConstructorFromIfc(Type impl) '''\r
252         «IF (impl instanceof GeneratedType)»\r
253             «val implType = impl as GeneratedType»\r
254 \r
255             «IF !(implType.methodDefinitions.empty)»\r
256                 public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {\r
257                     «printConstructorPropertySetter(implType)»\r
258                 }\r
259             «ENDIF»\r
260             «FOR implTypeImplement : implType.implements»\r
261                 «generateConstructorFromIfc(implTypeImplement)»\r
262             «ENDFOR»\r
263         «ENDIF»\r
264     '''\r
265 \r
266     def private printConstructorPropertySetter(Type implementedIfc) '''\r
267         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
268             «val ifc = implementedIfc as GeneratedType»\r
269             «FOR getter : ifc.methodDefinitions»\r
270                 this._«getter.propertyNameFromGetter» = arg.«getter.name»();\r
271             «ENDFOR»\r
272             «FOR impl : ifc.implements»\r
273                 «printConstructorPropertySetter(impl)»\r
274             «ENDFOR»\r
275         «ENDIF»\r
276     '''\r
277 \r
278     /**\r
279      * Generate 'fieldsFrom' method to set builder properties based on type of given argument.\r
280      */\r
281     def private generateMethodFieldsFrom(Type type) '''\r
282         «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
283             «val ifc = type as GeneratedType»\r
284             «IF ifc.hasImplementsFromUses»\r
285                 «val List<Type> done = ifc.getBaseIfcs»\r
286                 «generateMethodFieldsFromComment(ifc)»\r
287                 public void fieldsFrom(«DataObject.importedName» arg) {\r
288                     boolean isValidArg = false;\r
289                     «FOR impl : ifc.getAllIfcs»\r
290                         «generateIfCheck(impl, done)»\r
291                     «ENDFOR»\r
292                     if (!isValidArg) {\r
293                         throw new IllegalArgumentException(\r
294                           "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +\r
295                           "but was: " + arg\r
296                         );\r
297                     }\r
298                 }\r
299             «ENDIF»\r
300         «ENDIF»\r
301     '''\r
302 \r
303     def private generateMethodFieldsFromComment(GeneratedType type) '''\r
304         /**\r
305          Set fields from given grouping argument. Valid argument is instance of one of following types:\r
306          * <ul>\r
307          «FOR impl : type.getAllIfcs»\r
308          * <li>«impl.fullyQualifiedName»</li>\r
309          «ENDFOR»\r
310          * </ul>\r
311          *\r
312          * @param arg grouping object\r
313          * @throws IllegalArgumentException if given argument is none of valid types\r
314         */\r
315     '''\r
316 \r
317     /**\r
318      * Method is used to find out if given type implements any interface from uses.\r
319      */\r
320     def boolean hasImplementsFromUses(GeneratedType type) {\r
321         var i = 0\r
322         for (impl : type.getAllIfcs) {\r
323             if ((impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)) {\r
324                 i = i + 1\r
325             }\r
326         }\r
327         return i > 0\r
328     }\r
329 \r
330     def private generateIfCheck(Type impl, List<Type> done) '''\r
331         «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
332             «val implType = impl as GeneratedType»\r
333             if (arg instanceof «implType.fullyQualifiedName») {\r
334                 «printPropertySetter(implType)»\r
335                 isValidArg = true;\r
336             }\r
337         «ENDIF»\r
338     '''\r
339 \r
340     def private printPropertySetter(Type implementedIfc) '''\r
341         «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
342         «val ifc = implementedIfc as GeneratedType»\r
343         «FOR getter : ifc.methodDefinitions»\r
344             this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();\r
345         «ENDFOR»\r
346         «ENDIF»\r
347     '''\r
348 \r
349     private def List<Type> getBaseIfcs(GeneratedType type) {\r
350         val List<Type> baseIfcs = new ArrayList();\r
351         for (ifc : type.implements) {\r
352             if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {\r
353                 baseIfcs.add(ifc)\r
354             }\r
355         }\r
356         return baseIfcs \r
357     }\r
358 \r
359     private def Set<Type> getAllIfcs(Type type) {\r
360         val Set<Type> baseIfcs = new HashSet()\r
361         if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {\r
362             val ifc = type as GeneratedType\r
363             for (impl : ifc.implements) {\r
364                 if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {\r
365                     baseIfcs.add(impl)\r
366                 }\r
367                 baseIfcs.addAll(impl.getAllIfcs)\r
368             }\r
369         }\r
370         return baseIfcs \r
371     }\r
372 \r
373     private def List<String> toListOfNames(Collection<Type> types) {\r
374         val List<String> names = new ArrayList\r
375         for (type : types) {\r
376             names.add(type.fullyQualifiedName)\r
377         }\r
378         return names\r
379     }\r
380 \r
381         /**\r
382          * Template method which generates class attributes.\r
383          * \r
384          * @param boolean value which specify whether field is|isn't final\r
385          * @return string with class attributes and their types\r
386          */\r
387     def private generateFields(boolean _final) '''\r
388         «IF !properties.empty»\r
389             «FOR f : properties»\r
390                 private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;\r
391             «ENDFOR»\r
392         «ENDIF»\r
393         «IF augmentField != null»\r
394             private «Map.importedName»<Class<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();\r
395         «ENDIF»\r
396     '''\r
397 \r
398         /**\r
399          * Template method which generates setter methods\r
400          * \r
401          * @return string with the setter methods \r
402          */\r
403     def private generateSetters() '''\r
404         «FOR field : properties SEPARATOR '\n'»\r
405             public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {\r
406                 «generateRestrictions(field, "value")»\r
407 \r
408                 this.«field.fieldName» = value;\r
409                 return this;\r
410             }\r
411         «ENDFOR»\r
412         «IF augmentField != null»\r
413 \r
414             public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentation) {\r
415                 this.«augmentField.name».put(augmentationType, augmentation);\r
416                 return this;\r
417             }\r
418         «ENDIF»\r
419     '''\r
420 \r
421     /**\r
422      * Template method which generate constructor for IMPL class.\r
423      * \r
424      * @return string with IMPL class constructor\r
425      */\r
426     def private generateConstructor() '''\r
427         private «type.name»«IMPL»(«type.name»«BUILDER» builder) {\r
428             «val allProps = new ArrayList(properties)»\r
429             «val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»\r
430             «val keyType = type.getKey»\r
431             «IF isList && keyType != null»\r
432                 «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»\r
433                 «Collections.sort(keyProps,\r
434                     [ p1, p2 |\r
435                         return p1.name.compareTo(p2.name)\r
436                     ])\r
437                 »\r
438                 «FOR field : keyProps»\r
439                     «removeProperty(allProps, field.name)»\r
440                 «ENDFOR»\r
441                 «removeProperty(allProps, "key")»\r
442                 if (builder.getKey() == null) {\r
443                     this._key = new «keyType.importedName»(\r
444                         «FOR keyProp : keyProps SEPARATOR ", "»\r
445                             builder.«keyProp.getterMethodName»()\r
446                         «ENDFOR»\r
447                     );\r
448                     «FOR field : keyProps»\r
449                         this.«field.fieldName» = builder.«field.getterMethodName»();\r
450                     «ENDFOR»\r
451                 } else {\r
452                     this._key = builder.getKey();\r
453                     «FOR field : keyProps»\r
454                            this.«field.fieldName» = _key.«field.getterMethodName»();\r
455                     «ENDFOR»\r
456                 }\r
457             «ENDIF»\r
458             «FOR field : allProps»\r
459                 this.«field.fieldName» = builder.«field.getterMethodName»();\r
460             «ENDFOR»\r
461             «IF augmentField != null»\r
462                 this.«augmentField.name».putAll(builder.«augmentField.name»);\r
463             «ENDIF»\r
464         }\r
465     '''\r
466 \r
467     private def boolean implementsIfc(GeneratedType type, Type impl) {\r
468         for (Type ifc : type.implements) {\r
469             if (ifc.equals(impl)) {\r
470                 return true;\r
471             }\r
472         }\r
473         return false;\r
474     }\r
475 \r
476     private def Type getKey(GeneratedType type) {\r
477         for (m : type.methodDefinitions) {\r
478             if ("getKey".equals(m.name)) {\r
479                 return m.returnType;\r
480             }\r
481         }\r
482         return null;\r
483     }\r
484 \r
485     private def void removeProperty(Collection<GeneratedProperty> props, String name) {\r
486         var GeneratedProperty toRemove = null\r
487         for (p : props) {\r
488             if (p.name.equals(name)) {\r
489                 toRemove = p;\r
490             }\r
491         }\r
492         if (toRemove != null) {\r
493             props.remove(toRemove);\r
494         }\r
495     }\r
496 \r
497     /**\r
498      * Template method which generate getter methods for IMPL class.\r
499      * \r
500      * @return string with getter methods\r
501      */\r
502     def private generateGetters(boolean addOverride) '''\r
503         «IF !properties.empty»\r
504             «FOR field : properties SEPARATOR '\n'»\r
505                 «IF addOverride»@Override«ENDIF»\r
506                 «field.getterMethod»\r
507             «ENDFOR»\r
508         «ENDIF»\r
509         «IF augmentField != null»\r
510 \r
511             @SuppressWarnings("unchecked")\r
512             «IF addOverride»@Override«ENDIF»\r
513             public <E extends «augmentField.returnType.importedName»> E get«augmentField.name.toFirstUpper»(Class<E> augmentationType) {\r
514                 if (augmentationType == null) {\r
515                     throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");\r
516                 }\r
517                 return (E) «augmentField.name».get(augmentationType);\r
518             }\r
519         «ENDIF»\r
520     '''\r
521 \r
522     /**\r
523      * Template method which generates the method <code>hashCode()</code>.\r
524      * \r
525      * @return string with the <code>hashCode()</code> method definition in JAVA format\r
526      */\r
527     def protected generateHashCode() '''\r
528         «IF !properties.empty || augmentField != null»\r
529             @Override\r
530             public int hashCode() {\r
531                 final int prime = 31;\r
532                 int result = 1;\r
533                 «FOR property : properties»\r
534                     «IF property.returnType.name.contains("[")»\r
535                     result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));\r
536                     «ELSE»\r
537                     result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
538                     «ENDIF»\r
539                 «ENDFOR»\r
540                 «IF augmentField != null»\r
541                     result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode());\r
542                 «ENDIF»\r
543                 return result;\r
544             }\r
545         «ENDIF»\r
546     '''\r
547 \r
548     /**\r
549      * Template method which generates the method <code>equals()</code>.\r
550      * \r
551      * @return string with the <code>equals()</code> method definition in JAVA format     \r
552      */\r
553     def protected generateEquals() '''\r
554         «IF !properties.empty || augmentField != null»\r
555             @Override\r
556             public boolean equals(java.lang.Object obj) {\r
557                 if (this == obj) {\r
558                     return true;\r
559                 }\r
560                 if (obj == null) {\r
561                     return false;\r
562                 }\r
563                 if (getClass() != obj.getClass()) {\r
564                     return false;\r
565                 }\r
566                 «type.name»«IMPL» other = («type.name»«IMPL») obj;\r
567                 «FOR property : properties»\r
568                     «val fieldName = property.fieldName»\r
569                     if («fieldName» == null) {\r
570                         if (other.«fieldName» != null) {\r
571                             return false;\r
572                         }\r
573                     «IF property.returnType.name.contains("[")»\r
574                     } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {\r
575                     «ELSE»\r
576                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
577                     «ENDIF»\r
578                         return false;\r
579                     }\r
580                 «ENDFOR»\r
581                 «IF augmentField != null»\r
582                     «val fieldName = augmentField.name»\r
583                     if («fieldName» == null) {\r
584                         if (other.«fieldName» != null) {\r
585                             return false;\r
586                         }\r
587                     } else if(!«fieldName».equals(other.«fieldName»)) {\r
588                         return false;\r
589                     }\r
590                 «ENDIF»\r
591                 return true;\r
592             }\r
593         «ENDIF»\r
594     '''\r
595 \r
596     def override generateToString(Collection<GeneratedProperty> properties) '''\r
597         «IF !properties.empty»\r
598             @Override\r
599             public String toString() {\r
600                 StringBuilder builder = new StringBuilder();\r
601                 builder.append("«type.name» [«properties.get(0).fieldName»=");\r
602                 «IF properties.get(0).returnType.name.contains("[")»\r
603                     builder.append(«Arrays.importedName».toString(«properties.get(0).fieldName»));\r
604                 «ELSE»\r
605                     builder.append(«properties.get(0).fieldName»);\r
606                 «ENDIF»\r
607                 «FOR i : 1..<properties.size»\r
608                     builder.append(", «properties.get(i).fieldName»=");\r
609                     «IF properties.get(i).returnType.name.contains("[")»\r
610                         builder.append(«Arrays.importedName».toString(«properties.get(i).fieldName»));\r
611                     «ELSE»\r
612                         builder.append(«properties.get(i).fieldName»);\r
613                     «ENDIF»\r
614                 «ENDFOR»\r
615                 «IF augmentField != null»\r
616                     builder.append(", «augmentField.name»=");\r
617                     builder.append(«augmentField.name».values());\r
618                 «ENDIF»\r
619                 builder.append("]");\r
620                 return builder.toString();\r
621             }\r
622         «ENDIF»\r
623     '''\r
624 \r
625     override protected getFullyQualifiedName() {\r
626         '''«type.fullyQualifiedName»Builder'''.toString\r
627     }\r
628 \r
629     def implementedInterfaceGetter() '''\r
630     public «Class.importedName»<«type.importedName»> getImplementedInterface() {\r
631         return «type.importedName».class;\r
632     }\r
633     '''\r
634 \r
635 }\r
636 \r