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