Merge "Added export of augmentation schemas to Binding Context"
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / BuilderTemplate.xtend
index 96c7445e9bf2fd0970f4526bec03285f3877cf65..fbe9886d00c375b13ebf9b41cc413a3e50e40833 100644 (file)
-package org.opendaylight.yangtools.sal.java.api.generator
-
-import java.util.LinkedHashSet
-import java.util.List
-import java.util.Map
-import java.util.Set
-import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl
-import org.opendaylight.yangtools.binding.generator.util.Types
-import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
-import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
-import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature
-import org.opendaylight.yangtools.sal.binding.model.api.Type
-import org.opendaylight.yangtools.yang.binding.Augmentable
-
-class BuilderTemplate {
-
-    val static GET_PREFIX = "get"
-    val static JAVA_UTIL = "java.util"
-    val static HASH_MAP = "HashMap"
-    val static MAP = "Map"
-    val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"
-    val static BUILDER = 'Builder'
-    val static IMPL = 'Impl'
-    
-    val GeneratedType genType
-    val Map<String, String> imports
-    var GeneratedProperty augmentField
-    val Set<GeneratedProperty> fields
-    
-    new(GeneratedType genType) {
-        if (genType == null) {
-            throw new IllegalArgumentException("Generated type reference cannot be NULL!")
-        }
-        
-        this.genType = genType
-        this.imports = GeneratorUtil.createChildImports(genType)
-        this.fields = createFieldsFromMethods(createMethods)
-    }
-    
-    def private Set<MethodSignature> createMethods() {
-        val Set<MethodSignature> methods = new LinkedHashSet
-        methods.addAll(genType.methodDefinitions)
-        storeMethodsOfImplementedIfcs(methods, genType.implements)
-        return methods
-    }
-    
-    def private void storeMethodsOfImplementedIfcs(Set<MethodSignature> methods, List<Type> implementedIfcs) {
-        if (implementedIfcs == null || implementedIfcs.empty) {
-            return
-        }
-        for (implementedIfc : implementedIfcs) {
-            if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
-                val ifc = implementedIfc as GeneratedType
-                methods.addAll(ifc.methodDefinitions)
-                storeMethodsOfImplementedIfcs(methods, ifc.implements)
-            } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {
-                for (m : Augmentable.methods) {
-                    if (m.name == GET_AUGMENTATION_METHOD_NAME) {
-                        addToImports(JAVA_UTIL, HASH_MAP)
-                        addToImports(JAVA_UTIL, MAP)
-                        val fullyQualifiedName = m.returnType.name
-                        val pkg = fullyQualifiedName.package
-                        val name = fullyQualifiedName.name
-                        addToImports(pkg, name)
-                        val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)
-                        val type = new ReferencedTypeImpl(pkg, name)
-                        val generic = new ReferencedTypeImpl(genType.packageName, genType.name)
-                        val parametrizedReturnType = Types.parameterizedTypeFor(type, generic)
-                        tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)
-                        augmentField = tmpGenTO.toInstance.methodDefinitions.first.createFieldFromGetter
-                    }
-                }
-            }
-        }
-    }
-    
-    def private void addToImports(String typePackageName,String typeName) {
-        if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
-            return
-        }
-        if (!imports.containsKey(typeName)) {
-            imports.put(typeName, typePackageName)
-        }
-    }
-    
-    def private <E> first(List<E> elements) {
-        elements.get(0)
-    }
-    
-    def private String getPackage(String fullyQualifiedName) {
-        val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
-        return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)
-    }
-
-    def private String getName(String fullyQualifiedName) {
-        val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
-        return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)
-    }
-    
-    def private createFieldsFromMethods(Set<MethodSignature> methods) {
-        val Set<GeneratedProperty> result = new LinkedHashSet
-
-        if (methods == null || methods.isEmpty()) {
-            return result
-        }
-
-        for (m : methods) {
-            val createdField = m.createFieldFromGetter
-            if (createdField != null) {
-                result.add(createdField)
-            }
-        }
-        return result
-    }
-    
-    def private GeneratedProperty createFieldFromGetter(MethodSignature method) {
-        if (method == null || method.name == null || method.name.empty || method.returnType == null) {
-            throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")
-        }
-        if (method.name.startsWith(GET_PREFIX)) {
-            val fieldName = method.getName().substring(GET_PREFIX.length()).toFirstLower
-            val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")
-            tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)
-            return tmpGenTO.toInstance.properties.first
-        }
-    }
-
-    def generate() {
-        val body = generateBody
-        val pkgAndImports = generatePkgAndImports
-        return pkgAndImports.toString + body.toString
-    }
-    
-    def private generateBody() '''
-        public class «genType.name»«BUILDER» {
-        
-            «generateFields»
-
-            «generateSetters»
-
-            public «genType.name» build() {
-                return new «genType.name»«IMPL»();
-            }
-
-            private class «genType.name»«IMPL» implements «genType.name» {
-
-                «generateFields»
-
-                «generateConstructor»
-
-                «generateGetters»
-
-            }
-
-        }
-    '''
-
-    def private generateFields() '''
-        «IF !fields.empty»
-            «FOR f : fields»
-                private «f.returnType.resolveName» «f.name»;
-            «ENDFOR»
-        «ENDIF»
-        «IF augmentField != null»
-            private Map<Class<? extends «augmentField.returnType.resolveName»>, «augmentField.returnType.resolveName»> «augmentField.name» = new HashMap<>();
-        «ENDIF»
-    '''
-
-    def private generateSetters() '''
-        «FOR field : fields SEPARATOR '\n'»
-            public «genType.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.resolveName» «field.name») {
-                this.«field.name» = «field.name»;
-                return this;
-            }
-        «ENDFOR»
-        «IF augmentField != null»
-            
-            public «genType.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.resolveName»> augmentationType, «augmentField.returnType.resolveName» augmentation) {
-                this.«augmentField.name».put(augmentationType, augmentation);
-                return this;
-            }
-        «ENDIF»
-    '''
-    
-    def private generateConstructor() '''
-        private «genType.name»«IMPL»() {
-            «IF !fields.empty»
-                «FOR field : fields»
-                    this.«field.name» = «genType.name»«BUILDER».this.«field.name»;
-                «ENDFOR»
-            «ENDIF»
-            «IF augmentField != null»
-                this.«augmentField.name».putAll(«genType.name»«BUILDER».this.«augmentField.name»);
-            «ENDIF»
-        }
-    '''
-    
-    def private generateGetters() '''
-        «IF !fields.empty»
-            «FOR field : fields SEPARATOR '\n'»
-                @Override
-                public «field.returnType.resolveName» get«field.name.toFirstUpper»() {
-                    return «field.name»;
-                }
-            «ENDFOR»
-        «ENDIF»
-        «IF augmentField != null»
-
-            @SuppressWarnings("unchecked")
-            @Override
-            public <E extends «augmentField.returnType.resolveName»> E get«augmentField.name.toFirstUpper»(Class<E> augmentationType) {
-                if (augmentationType == null) {
-                    throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
-                }
-                return (E) «augmentField.name».get(augmentationType);
-            }
-        «ENDIF»
-    '''    
-    
-    def private generatePkgAndImports() '''
-        package «genType.packageName»;
-        
-        
-        «IF !imports.empty»
-            «FOR entry : imports.entrySet»
-                import «entry.value».«entry.key»;
-            «ENDFOR»
-        «ENDIF»
-        
-    '''
-    
-    def private resolveName(Type type) {
-        GeneratorUtil.putTypeIntoImports(genType, type, imports);
-        GeneratorUtil.getExplicitType(genType, type, imports)
-    }
-    
-}
+package org.opendaylight.yangtools.sal.java.api.generator\r
+\r
+import java.util.Arrays;\r
+import java.util.LinkedHashSet\r
+import java.util.List\r
+import java.util.Map\r
+import java.util.Set\r
+import org.opendaylight.yangtools.binding.generator.util.ReferencedTypeImpl\r
+import org.opendaylight.yangtools.binding.generator.util.Types\r
+import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl\r
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty\r
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject\r
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType\r
+import org.opendaylight.yangtools.sal.binding.model.api.MethodSignature\r
+import org.opendaylight.yangtools.sal.binding.model.api.Type\r
+import org.opendaylight.yangtools.yang.binding.Augmentable\r
+import static org.opendaylight.yangtools.binding.generator.util.Types.*\r
+import java.util.HashMap\r
+import java.util.Collections\rimport org.opendaylight.yangtools.yang.binding.DataObject
+import java.util.ArrayList
+import java.util.HashSet
+import java.util.Collection
+import org.opendaylight.yangtools.yang.binding.Identifiable
 
+/**\r
+ * Template for generating JAVA builder classes. \r
+ */\r
+\r
+class BuilderTemplate extends BaseTemplate {\r
+\r
+    /**\r
+     * Constant with the name of the concrete method.\r
+     */\r
+    val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"\r
+\r
+    /**\r
+     * Constant with the suffix for builder classes.\r
+     */\r
+    val static BUILDER = 'Builder'\r
+\r
+    /**\r
+     * Constant with suffix for the classes which are generated from the builder classes.\r
+     */\r
+    val static IMPL = 'Impl'\r
+\r
+    /**\r
+     * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME\r
+     */\r
+    var GeneratedProperty augmentField\r
+\r
+    /**\r
+     * Set of class attributes (fields) which are derived from the getter methods names\r
+     */\r
+    val Set<GeneratedProperty> properties\r
+\r
+    /**\r
+     * Constructs new instance of this class.\r
+     * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>\r
+     */\r
+    new(GeneratedType genType) {\r
+        super(genType)\r
+        this.properties = propertiesFromMethods(createMethods)\r
+    }\r
+\r
+    /**\r
+     * Returns set of method signature instances which contains all the methods of the <code>genType</code>\r
+     * and all the methods of the implemented interfaces.\r
+     * \r
+     * @returns set of method signature instances\r
+     */\r
+    def private Set<MethodSignature> createMethods() {\r
+        val Set<MethodSignature> methods = new LinkedHashSet\r
+        methods.addAll(type.methodDefinitions)\r
+        collectImplementedMethods(methods, type.implements)\r
+        return methods\r
+    }\r
+\r
+    /**\r
+     * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code> \r
+     * and recursivelly their implemented interfaces.\r
+     * \r
+     * @param methods set of method signatures\r
+     * @param implementedIfcs list of implemented interfaces\r
+     */\r
+    def private void collectImplementedMethods(Set<MethodSignature> methods, List<Type> implementedIfcs) {\r
+        if (implementedIfcs == null || implementedIfcs.empty) {\r
+            return\r
+        }\r
+        for (implementedIfc : implementedIfcs) {\r
+            if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {\r
+                val ifc = implementedIfc as GeneratedType\r
+                methods.addAll(ifc.methodDefinitions)\r
+                collectImplementedMethods(methods, ifc.implements)\r
+            } else if (implementedIfc.fullyQualifiedName == Augmentable.name) {\r
+                for (m : Augmentable.methods) {\r
+                    if (m.name == GET_AUGMENTATION_METHOD_NAME) {\r
+                        val fullyQualifiedName = m.returnType.name\r
+                        val pkg = fullyQualifiedName.package\r
+                        val name = fullyQualifiedName.name\r
+                        val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name)\r
+                        val refType = new ReferencedTypeImpl(pkg, name)\r
+                        val generic = new ReferencedTypeImpl(type.packageName, type.name)\r
+                        val parametrizedReturnType = Types.parameterizedTypeFor(refType, generic)\r
+                        tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)\r
+                        augmentField = tmpGenTO.toInstance.methodDefinitions.first.propertyFromGetter\r
+                    }\r
+                }\r
+            }\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Returns the first element of the list <code>elements</code>.\r
+     * \r
+     * @param list of elements\r
+     */\r
+    def private <E> first(List<E> elements) {\r
+        elements.get(0)\r
+    }\r
+\r
+    /**\r
+     * Returns the name of the package from <code>fullyQualifiedName</code>.\r
+     * \r
+     * @param fullyQualifiedName string with fully qualified type name (package + type)\r
+     * @return string with the package name\r
+     */\r
+    def private String getPackage(String fullyQualifiedName) {\r
+        val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)\r
+        return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)\r
+    }\r
+\r
+       /**\r
+        * Returns the name of tye type from <code>fullyQualifiedName</code>\r
+        * \r
+        * @param fullyQualifiedName string with fully qualified type name (package + type)\r
+        * @return string with the name of the type\r
+        */\r
+    def private String getName(String fullyQualifiedName) {\r
+        val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)\r
+        return if (lastDotIndex == -1) fullyQualifiedName else fullyQualifiedName.substring(lastDotIndex + 1)\r
+    }\r
+\r
+    /**\r
+     * Creates set of generated property instances from getter <code>methods</code>.\r
+     * \r
+     * @param set of method signature instances which should be transformed to list of properties \r
+     * @return set of generated property instances which represents the getter <code>methods</code>\r
+     */\r
+    def private propertiesFromMethods(Set<MethodSignature> methods) {\r
+        if (methods == null || methods.isEmpty()) {\r
+            return Collections.emptySet\r
+        }\r
+        val Set<GeneratedProperty> result = new LinkedHashSet\r
+        for (m : methods) {\r
+            val createdField = m.propertyFromGetter\r
+            if (createdField != null) {\r
+                result.add(createdField)\r
+            }\r
+        }\r
+        return result\r
+    }\r
+\r
+    /**\r
+     * Creates generated property instance from the getter <code>method</code> name and return type.\r
+     * \r
+     * @param method method signature from which is the method name and return type obtained\r
+     * @return generated property instance for the getter <code>method</code>\r
+     * @throws IllegalArgumentException<ul>\r
+     *         <li>if the <code>method</code> equals <code>null</code></li>\r
+     *         <li>if the name of the <code>method</code> equals <code>null</code></li>\r
+     *         <li>if the name of the <code>method</code> is empty</li>\r
+     *         <li>if the return type of the <code>method</code> equals <code>null</code></li>\r
+     * </ul>\r
+     */\r
+    def private GeneratedProperty propertyFromGetter(MethodSignature method) {\r
+        if (method == null || method.name == null || method.name.empty || method.returnType == null) {\r
+            throw new IllegalArgumentException("Method, method name, method return type reference cannot be NULL or empty!")\r
+        }\r
+        var prefix = "get";\r
+        if(BOOLEAN.equals(method.returnType)) {\r
+            prefix = "is";\r
+        } \r
+        if (method.name.startsWith(prefix)) {\r
+            val fieldName = method.getName().substring(prefix.length()).toFirstLower\r
+            val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")\r
+            tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)\r
+            return tmpGenTO.toInstance.properties.first\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Template method which generates JAVA class body for builder class and for IMPL class. \r
+     * \r
+     * @return string with JAVA source code\r
+     */\r
+    override body() '''\r
+\r
+        public class «type.name»«BUILDER» {\r
+\r
+            «generateFields(false)»\r
+\r
+            «generateConstructorsFromIfcs(type)»\r
+\r
+            «generateMethodFieldsFrom(type)»\r
+\r
+            «generateGetters(false)»\r
+\r
+            «generateSetters»\r
+\r
+            public «type.name» build() {\r
+                return new «type.name»«IMPL»(this);\r
+            }\r
+\r
+            private static final class «type.name»«IMPL» implements «type.name» {\r
+\r
+                «implementedInterfaceGetter»\r
+\r
+                «generateFields(true)»\r
+\r
+                «generateConstructor»\r
+\r
+                «generateGetters(true)»\r
+\r
+                «generateHashCode()»\r
+\r
+                «generateEquals()»\r
+            }\r
+\r
+        }\r
+    '''\r
+\r
+    /**\r
+     * Generate default constructor and constructor for every implemented interface from uses statements.\r
+     */\r
+    def private generateConstructorsFromIfcs(Type type) '''\r
+        public «type.name»«BUILDER»() {\r
+        } \r
+        «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
+            «val ifc = type as GeneratedType»\r
+            «FOR impl : ifc.implements»\r
+                «generateConstructorFromIfc(impl)»\r
+            «ENDFOR»\r
+        «ENDIF»\r
+    '''\r
+\r
+    /**\r
+     * Generate constructor with argument of given type.\r
+     */\r
+    def private generateConstructorFromIfc(Type impl) '''\r
+        «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
+            «val implType = impl as GeneratedType»\r
+\r
+            public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {\r
+                «printConstructorPropertySetter(implType)»\r
+            }\r
+            «FOR implTypeImplement : implType.implements»\r
+                «generateConstructorFromIfc(implTypeImplement)»\r
+            «ENDFOR»\r
+        «ENDIF»\r
+    '''\r
+\r
+    def private printConstructorPropertySetter(Type implementedIfc) '''\r
+        «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
+            «val ifc = implementedIfc as GeneratedType»\r
+            «FOR getter : ifc.methodDefinitions»\r
+                this._«getter.propertyNameFromGetter» = arg.«getter.name»();\r
+            «ENDFOR»\r
+            «FOR impl : ifc.implements»\r
+                «printConstructorPropertySetter(impl)»\r
+            «ENDFOR»\r
+        «ENDIF»\r
+    '''\r
+\r
+    /**\r
+     * Generate 'fieldsFrom' method to set builder properties based on type of given argument.\r
+     */\r
+    def private generateMethodFieldsFrom(Type type) '''\r
+        «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»\r
+            «val ifc = type as GeneratedType»\r
+            «IF ifc.hasImplementsFromUses»\r
+                «val List<Type> done = ifc.getBaseIfcs»\r
+                «generateMethodFieldsFromComment(ifc)»\r
+                public void fieldsFrom(«DataObject.importedName» arg) {\r
+                    boolean isValidArg = false;\r
+                    «FOR impl : ifc.getAllIfcs»\r
+                        «generateIfCheck(impl, done)»\r
+                    «ENDFOR»\r
+                    if (!isValidArg) {\r
+                        throw new IllegalArgumentException(\r
+                          "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +\r
+                          "but was: " + arg\r
+                        );\r
+                    }\r
+                }\r
+            «ENDIF»\r
+        «ENDIF»\r
+    '''\r
+\r
+    def private generateMethodFieldsFromComment(GeneratedType type) '''\r
+        /**\r
+         Set fields from given grouping argument. Valid argument is instance of one of following types:\r
+         * <ul>\r
+         «FOR impl : type.getAllIfcs»\r
+         * <li>«impl.fullyQualifiedName»</li>\r
+         «ENDFOR»\r
+         * </ul>\r
+         *\r
+         * @param arg grouping object\r
+         * @throws IllegalArgumentException if given argument is none of valid types\r
+        */\r
+    '''\r
+\r
+    /**\r
+     * Method is used to find out if given type implements any interface from uses.\r
+     */\r
+    def boolean hasImplementsFromUses(GeneratedType type) {\r
+        var i = 0\r
+        for (impl : type.getAllIfcs) {\r
+            if ((impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)) {\r
+                i = i + 1\r
+            }\r
+        }\r
+        return i > 0\r
+    }\r
+\r
+    def private generateIfCheck(Type impl, List<Type> done) '''\r
+        «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»\r
+            «val implType = impl as GeneratedType»\r
+            if (arg instanceof «implType.fullyQualifiedName») {\r
+                «printPropertySetter(implType)»\r
+                isValidArg = true;\r
+            }\r
+        «ENDIF»\r
+    '''\r
+\r
+    def private printPropertySetter(Type implementedIfc) '''\r
+        «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»\r
+        «val ifc = implementedIfc as GeneratedType»\r
+        «FOR getter : ifc.methodDefinitions»\r
+            this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();\r
+        «ENDFOR»\r
+        «ENDIF»\r
+    '''\r
+\r
+    private def List<Type> getBaseIfcs(GeneratedType type) {\r
+        val List<Type> baseIfcs = new ArrayList();\r
+        for (ifc : type.implements) {\r
+            if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {\r
+                baseIfcs.add(ifc)\r
+            }\r
+        }\r
+        return baseIfcs \r
+    }\r
+\r
+    private def Set<Type> getAllIfcs(Type type) {\r
+        val Set<Type> baseIfcs = new HashSet()\r
+        if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {\r
+            val ifc = type as GeneratedType\r
+            for (impl : ifc.implements) {\r
+                if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {\r
+                    baseIfcs.add(impl)\r
+                }\r
+                baseIfcs.addAll(impl.getAllIfcs)\r
+            }\r
+        }\r
+        return baseIfcs \r
+    }\r
+\r
+    private def List<String> toListOfNames(Collection<Type> types) {\r
+        val List<String> names = new ArrayList\r
+        for (type : types) {\r
+            names.add(type.fullyQualifiedName)\r
+        }\r
+        return names\r
+    }\r
+\r
+       /**\r
+        * Template method which generates class attributes.\r
+        * \r
+        * @param boolean value which specify whether field is|isn't final\r
+        * @return string with class attributes and their types\r
+        */\r
+    def private generateFields(boolean _final) '''\r
+        «IF !properties.empty»\r
+            «FOR f : properties»\r
+                private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;\r
+            «ENDFOR»\r
+        «ENDIF»\r
+        «IF augmentField != null»\r
+            private «Map.importedName»<Class<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();\r
+        «ENDIF»\r
+    '''\r
+\r
+       /**\r
+        * Template method which generates setter methods\r
+        * \r
+        * @return string with the setter methods \r
+        */\r
+    def private generateSetters() '''\r
+        «FOR field : properties SEPARATOR '\n'»\r
+            public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {\r
+                «generateRestrictions(field, "value")»\r
+\r
+                this.«field.fieldName» = value;\r
+                return this;\r
+            }\r
+        «ENDFOR»\r
+        «IF augmentField != null»\r
+\r
+            public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentation) {\r
+                this.«augmentField.name».put(augmentationType, augmentation);\r
+                return this;\r
+            }\r
+        «ENDIF»\r
+    '''\r
+\r
+    /**\r
+     * Template method which generate constructor for IMPL class.\r
+     * \r
+     * @return string with IMPL class constructor\r
+     */\r
+    def private generateConstructor() '''\r
+        private «type.name»«IMPL»(«type.name»«BUILDER» builder) {\r
+            «val allProps = new ArrayList(properties)»\r
+            «val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»\r
+            «val keyType = type.getKey»\r
+            «IF isList && keyType != null»\r
+                «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»\r
+                «Collections.sort(keyProps,\r
+                    [ p1, p2 |\r
+                        return p1.name.compareTo(p2.name)\r
+                    ])\r
+                »\r
+                «FOR field : keyProps»\r
+                    «removeProperty(allProps, field.name)»\r
+                «ENDFOR»\r
+                «removeProperty(allProps, "key")»\r
+                if (builder.getKey() == null) {\r
+                    this._key = new «keyType.importedName»(\r
+                        «FOR keyProp : keyProps SEPARATOR ", "»\r
+                            builder.«keyProp.getterMethodName»()\r
+                        «ENDFOR»\r
+                    );\r
+                    «FOR field : keyProps»\r
+                        this.«field.fieldName» = builder.«field.getterMethodName»();\r
+                    «ENDFOR»\r
+                } else {\r
+                    this._key = builder.getKey();\r
+                    «FOR field : keyProps»\r
+                           this.«field.fieldName» = _key.«field.getterMethodName»();\r
+                    «ENDFOR»\r
+                }\r
+            «ENDIF»\r
+            «FOR field : allProps»\r
+                this.«field.fieldName» = builder.«field.getterMethodName»();\r
+            «ENDFOR»\r
+            «IF augmentField != null»\r
+                this.«augmentField.name».putAll(builder.«augmentField.name»);\r
+            «ENDIF»\r
+        }\r
+    '''\r
+\r
+    private def boolean implementsIfc(GeneratedType type, Type impl) {\r
+        for (Type ifc : type.implements) {\r
+            if (ifc.equals(impl)) {\r
+                return true;\r
+            }\r
+        }\r
+        return false;\r
+    }\r
+\r
+    private def Type getKey(GeneratedType type) {\r
+        for (m : type.methodDefinitions) {\r
+            if ("getKey".equals(m.name)) {\r
+                return m.returnType;\r
+            }\r
+        }\r
+        return null;\r
+    }\r
+\r
+    private def void removeProperty(Collection<GeneratedProperty> props, String name) {\r
+        var GeneratedProperty toRemove = null\r
+        for (p : props) {\r
+            if (p.name.equals(name)) {\r
+                toRemove = p;\r
+            }\r
+        }\r
+        if (toRemove != null) {\r
+            props.remove(toRemove);\r
+        }\r
+    }\r
+\r
+    /**\r
+     * Template method which generate getter methods for IMPL class.\r
+     * \r
+     * @return string with getter methods\r
+     */\r
+    def private generateGetters(boolean addOverride) '''\r
+        «IF !properties.empty»\r
+            «FOR field : properties SEPARATOR '\n'»\r
+                «IF addOverride»@Override«ENDIF»\r
+                «field.getterMethod»\r
+            «ENDFOR»\r
+        «ENDIF»\r
+        «IF augmentField != null»\r
+\r
+            @SuppressWarnings("unchecked")\r
+            «IF addOverride»@Override«ENDIF»\r
+            public <E extends «augmentField.returnType.importedName»> E get«augmentField.name.toFirstUpper»(Class<E> augmentationType) {\r
+                if (augmentationType == null) {\r
+                    throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");\r
+                }\r
+                return (E) «augmentField.name».get(augmentationType);\r
+            }\r
+        «ENDIF»\r
+    '''\r
+\r
+    /**\r
+     * Template method which generates the method <code>hashCode()</code>.\r
+     * \r
+     * @return string with the <code>hashCode()</code> method definition in JAVA format\r
+     */\r
+    def protected generateHashCode() '''\r
+        «IF !properties.empty || augmentField != null»\r
+            @Override\r
+            public int hashCode() {\r
+                final int prime = 31;\r
+                int result = 1;\r
+                «FOR property : properties»\r
+                    «IF property.returnType.name.contains("[")»\r
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));\r
+                    «ELSE»\r
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());\r
+                    «ENDIF»\r
+                «ENDFOR»\r
+                «IF augmentField != null»\r
+                    result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode());\r
+                «ENDIF»\r
+                return result;\r
+            }\r
+        «ENDIF»\r
+    '''\r
+\r
+    /**\r
+     * Template method which generates the method <code>equals()</code>.\r
+     * \r
+     * @return string with the <code>equals()</code> method definition in JAVA format     \r
+     */\r
+    def protected generateEquals() '''\r
+        «IF !properties.empty || augmentField != null»\r
+            @Override\r
+            public boolean equals(java.lang.Object obj) {\r
+                if (this == obj) {\r
+                    return true;\r
+                }\r
+                if (obj == null) {\r
+                    return false;\r
+                }\r
+                if (getClass() != obj.getClass()) {\r
+                    return false;\r
+                }\r
+                «type.name»«IMPL» other = («type.name»«IMPL») obj;\r
+                «FOR property : properties»\r
+                    «val fieldName = property.fieldName»\r
+                    if («fieldName» == null) {\r
+                        if (other.«fieldName» != null) {\r
+                            return false;\r
+                        }\r
+                    «IF property.returnType.name.contains("[")»\r
+                    } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {\r
+                    «ELSE»\r
+                    } else if(!«fieldName».equals(other.«fieldName»)) {\r
+                    «ENDIF»\r
+                        return false;\r
+                    }\r
+                «ENDFOR»\r
+                «IF augmentField != null»\r
+                    «val fieldName = augmentField.name»\r
+                    if («fieldName» == null) {\r
+                        if (other.«fieldName» != null) {\r
+                            return false;\r
+                        }\r
+                    } else if(!«fieldName».equals(other.«fieldName»)) {\r
+                        return false;\r
+                    }\r
+                «ENDIF»\r
+                return true;\r
+            }\r
+        «ENDIF»\r
+    '''\r
+\r
+    override protected getFullyQualifiedName() {\r
+        '''«type.fullyQualifiedName»Builder'''.toString\r
+    }\r
+    \r
+    def implementedInterfaceGetter() '''\r
+    public «Class.importedName»<«type.importedName»> getImplementedInterface() {\r
+        return «type.importedName».class;\r
+    }\r
+    '''\r
+\r
+}\r
+\r