Merge "Bug 735 - Part 1: Update ietf-restconf and ietf-yangtypes to newer versions"
[yangtools.git] / code-generator / binding-java-api-generator / src / main / java / org / opendaylight / yangtools / sal / java / api / generator / BuilderTemplate.xtend
index 6ffc912ebfd7d781da432f2992efe4aab0149968..7d954465df34d83b3234563e28d66c7065d81462 100644 (file)
@@ -1,5 +1,13 @@
+/*
+ * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
 package org.opendaylight.yangtools.sal.java.api.generator
 
+import java.util.Arrays;
 import java.util.LinkedHashSet
 import java.util.List
 import java.util.Map
@@ -13,40 +21,76 @@ 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
+import static org.opendaylight.yangtools.binding.generator.util.Types.*
+import java.util.HashMap
+import java.util.Collections
+import 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
 
-class BuilderTemplate {
+/**
+ * Template for generating JAVA builder classes. 
+ */
 
-    val static GET_PREFIX = "get"
-    val static JAVA_UTIL = "java.util"
-    val static HASH_MAP = "HashMap"
-    val static MAP = "Map"
+class BuilderTemplate extends BaseTemplate {
+
+    /**
+     * Constant with the name of the concrete method.
+     */
     val static GET_AUGMENTATION_METHOD_NAME = "getAugmentation"
+
+    /**
+     * Constant with the suffix for builder classes.
+     */
     val static BUILDER = 'Builder'
+
+    /**
+     * Constant with suffix for the classes which are generated from the builder classes.
+     */
     val static IMPL = 'Impl'
-    
-    val GeneratedType genType
-    val Map<String, String> imports
+
+    /**
+     * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME
+     */
     var GeneratedProperty augmentField
-    val Set<GeneratedProperty> fields
-    
+
+    /**
+     * Set of class attributes (fields) which are derived from the getter methods names
+     */
+    val Set<GeneratedProperty> properties
+
+    /**
+     * Constructs new instance of this class.
+     * @throws IllegalArgumentException if <code>genType</code> equals <code>null</code>
+     */
     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)
+        super(genType)
+        this.properties = propertiesFromMethods(createMethods)
     }
-    
+
+    /**
+     * Returns set of method signature instances which contains all the methods of the <code>genType</code>
+     * and all the methods of the implemented interfaces.
+     * 
+     * @returns set of method signature instances
+     */
     def private Set<MethodSignature> createMethods() {
         val Set<MethodSignature> methods = new LinkedHashSet
-        methods.addAll(genType.methodDefinitions)
-        storeMethodsOfImplementedIfcs(methods, genType.implements)
+        methods.addAll(type.methodDefinitions)
+        collectImplementedMethods(methods, type.implements)
         return methods
     }
-    
-    def private void storeMethodsOfImplementedIfcs(Set<MethodSignature> methods, List<Type> implementedIfcs) {
+
+    /**
+     * Adds to the <code>methods</code> set all the methods of the <code>implementedIfcs</code> 
+     * and recursivelly their implemented interfaces.
+     * 
+     * @param methods set of method signatures
+     * @param implementedIfcs list of implemented interfaces
+     */
+    def private void collectImplementedMethods(Set<MethodSignature> methods, List<Type> implementedIfcs) {
         if (implementedIfcs == null || implementedIfcs.empty) {
             return
         }
@@ -54,187 +98,571 @@ class BuilderTemplate {
             if ((implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))) {
                 val ifc = implementedIfc as GeneratedType
                 methods.addAll(ifc.methodDefinitions)
-                storeMethodsOfImplementedIfcs(methods, ifc.implements)
+                collectImplementedMethods(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)
+                        val refType = new ReferencedTypeImpl(pkg, name)
+                        val generic = new ReferencedTypeImpl(type.packageName, type.name)
+                        val parametrizedReturnType = Types.parameterizedTypeFor(refType, generic)
                         tmpGenTO.addMethod(m.name).setReturnType(parametrizedReturnType)
-                        augmentField = tmpGenTO.toInstance.methodDefinitions.first.createFieldFromGetter
+                        augmentField = tmpGenTO.toInstance.methodDefinitions.first.propertyFromGetter
                     }
                 }
             }
         }
     }
-    
-    def private void addToImports(String typePackageName,String typeName) {
-        if (typePackageName.startsWith("java.lang") || typePackageName.isEmpty()) {
-            return
-        }
-        if (!imports.containsKey(typeName)) {
-            imports.put(typeName, typePackageName)
-        }
-    }
-    
+
+    /**
+     * Returns the first element of the list <code>elements</code>.
+     * 
+     * @param list of elements
+     */
     def private <E> first(List<E> elements) {
         elements.get(0)
     }
-    
+
+    /**
+     * Returns the name of the package from <code>fullyQualifiedName</code>.
+     * 
+     * @param fullyQualifiedName string with fully qualified type name (package + type)
+     * @return string with the package name
+     */
     def private String getPackage(String fullyQualifiedName) {
         val lastDotIndex = fullyQualifiedName.lastIndexOf(Constants.DOT)
         return if (lastDotIndex == -1) "" else fullyQualifiedName.substring(0, lastDotIndex)
     }
 
+       /**
+        * Returns the name of tye type from <code>fullyQualifiedName</code>
+        * 
+        * @param fullyQualifiedName string with fully qualified type name (package + type)
+        * @return string with the name of the type
+        */
     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
 
+    /**
+     * Creates set of generated property instances from getter <code>methods</code>.
+     * 
+     * @param set of method signature instances which should be transformed to list of properties 
+     * @return set of generated property instances which represents the getter <code>methods</code>
+     */
+    def private propertiesFromMethods(Set<MethodSignature> methods) {
         if (methods == null || methods.isEmpty()) {
-            return result
+            return Collections.emptySet
         }
-
+        val Set<GeneratedProperty> result = new LinkedHashSet
         for (m : methods) {
-            val createdField = m.createFieldFromGetter
+            val createdField = m.propertyFromGetter
             if (createdField != null) {
                 result.add(createdField)
             }
         }
         return result
     }
-    
-    def private GeneratedProperty createFieldFromGetter(MethodSignature method) {
+
+    /**
+     * Creates generated property instance from the getter <code>method</code> name and return type.
+     * 
+     * @param method method signature from which is the method name and return type obtained
+     * @return generated property instance for the getter <code>method</code>
+     * @throws IllegalArgumentException<ul>
+     *         <li>if the <code>method</code> equals <code>null</code></li>
+     *         <li>if the name of the <code>method</code> equals <code>null</code></li>
+     *         <li>if the name of the <code>method</code> is empty</li>
+     *         <li>if the return type of the <code>method</code> equals <code>null</code></li>
+     * </ul>
+     */
+    def private GeneratedProperty propertyFromGetter(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
+        var prefix = "get";
+        if(BOOLEAN.equals(method.returnType)) {
+            prefix = "is";
+        } 
+        if (method.name.startsWith(prefix)) {
+            val fieldName = method.getName().substring(prefix.length()).toFirstLower
             val tmpGenTO = new GeneratedTOBuilderImpl("foo", "foo")
             tmpGenTO.addProperty(fieldName).setReturnType(method.returnType)
             return tmpGenTO.toInstance.properties.first
         }
     }
 
-    def String generate() {
-        val body = generateBody
-        val pkgAndImports = generatePkgAndImports
-        return pkgAndImports.toString + body.toString
-    }
-    
-    def private generateBody() '''
-        public class «genType.name»«BUILDER» {
-        
+    /**
+     * Template method which generates JAVA class body for builder class and for IMPL class. 
+     * 
+     * @return string with JAVA source code
+     */
+    override body() '''
+
+        public class «type.name»«BUILDER» {
+
             «generateFields(false)»
 
+            «generateAugmentField(true)»
+
+            «generateConstructorsFromIfcs(type)»
+
+            «generateMethodFieldsFrom(type)»
+
+            «generateGetters(false)»
+
             «generateSetters»
 
-            public «genType.name» build() {
-                return new «genType.name»«IMPL»();
+            public «type.name» build() {
+                return new «type.name»«IMPL»(this);
             }
 
-            private class «genType.name»«IMPL» implements «genType.name» {
+            private static final class «type.name»«IMPL» implements «type.name» {
+
+                «implementedInterfaceGetter»
 
                 «generateFields(true)»
 
+                «generateAugmentField(false)»
+
                 «generateConstructor»
 
-                «generateGetters»
+                «generateGetters(true)»
+
+                «generateHashCode()»
 
+                «generateEquals()»
+                
+                «generateToString(properties)»
             }
 
         }
     '''
 
+    /**
+     * Generate default constructor and constructor for every implemented interface from uses statements.
+     */
+    def private generateConstructorsFromIfcs(Type type) '''
+        public «type.name»«BUILDER»() {
+        } 
+        «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
+            «val ifc = type as GeneratedType»
+            «FOR impl : ifc.implements»
+                «generateConstructorFromIfc(impl)»
+            «ENDFOR»
+        «ENDIF»
+    '''
+
+    /**
+     * Generate constructor with argument of given type.
+     */
+    def private Object generateConstructorFromIfc(Type impl) '''
+        «IF (impl instanceof GeneratedType)»
+            «val implType = impl as GeneratedType»
+
+            «IF !(implType.methodDefinitions.empty)»
+                public «type.name»«BUILDER»(«implType.fullyQualifiedName» arg) {
+                    «printConstructorPropertySetter(implType)»
+                }
+            «ENDIF»
+            «FOR implTypeImplement : implType.implements»
+                «generateConstructorFromIfc(implTypeImplement)»
+            «ENDFOR»
+        «ENDIF»
+    '''
+
+    def private Object printConstructorPropertySetter(Type implementedIfc) '''
+        «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
+            «val ifc = implementedIfc as GeneratedType»
+            «FOR getter : ifc.methodDefinitions»
+                this._«getter.propertyNameFromGetter» = arg.«getter.name»();
+            «ENDFOR»
+            «FOR impl : ifc.implements»
+                «printConstructorPropertySetter(impl)»
+            «ENDFOR»
+        «ENDIF»
+    '''
+
+    /**
+     * Generate 'fieldsFrom' method to set builder properties based on type of given argument.
+     */
+    def private generateMethodFieldsFrom(Type type) '''
+        «IF (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject))»
+            «val ifc = type as GeneratedType»
+            «IF ifc.hasImplementsFromUses»
+                «val List<Type> done = ifc.getBaseIfcs»
+                «generateMethodFieldsFromComment(ifc)»
+                public void fieldsFrom(«DataObject.importedName» arg) {
+                    boolean isValidArg = false;
+                    «FOR impl : ifc.getAllIfcs»
+                        «generateIfCheck(impl, done)»
+                    «ENDFOR»
+                    if (!isValidArg) {
+                        throw new IllegalArgumentException(
+                          "expected one of: «ifc.getAllIfcs.toListOfNames» \n" +
+                          "but was: " + arg
+                        );
+                    }
+                }
+            «ENDIF»
+        «ENDIF»
+    '''
+
+    def private generateMethodFieldsFromComment(GeneratedType type) '''
+        /**
+         Set fields from given grouping argument. Valid argument is instance of one of following types:
+         * <ul>
+         «FOR impl : type.getAllIfcs»
+         * <li>«impl.fullyQualifiedName»</li>
+         «ENDFOR»
+         * </ul>
+         *
+         * @param arg grouping object
+         * @throws IllegalArgumentException if given argument is none of valid types
+        */
+    '''
+
+    /**
+     * Method is used to find out if given type implements any interface from uses.
+     */
+    def boolean hasImplementsFromUses(GeneratedType type) {
+        var i = 0
+        for (impl : type.getAllIfcs) {
+            if ((impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)) {
+                i = i + 1
+            }
+        }
+        return i > 0
+    }
+
+    def private generateIfCheck(Type impl, List<Type> done) '''
+        «IF (impl instanceof GeneratedType) &&  !((impl as GeneratedType).methodDefinitions.empty)»
+            «val implType = impl as GeneratedType»
+            if (arg instanceof «implType.fullyQualifiedName») {
+                «printPropertySetter(implType)»
+                isValidArg = true;
+            }
+        «ENDIF»
+    '''
+
+    def private printPropertySetter(Type implementedIfc) '''
+        «IF (implementedIfc instanceof GeneratedType && !(implementedIfc instanceof GeneratedTransferObject))»
+        «val ifc = implementedIfc as GeneratedType»
+        «FOR getter : ifc.methodDefinitions»
+            this._«getter.propertyNameFromGetter» = ((«implementedIfc.fullyQualifiedName»)arg).«getter.name»();
+        «ENDFOR»
+        «ENDIF»
+    '''
+
+    private def List<Type> getBaseIfcs(GeneratedType type) {
+        val List<Type> baseIfcs = new ArrayList();
+        for (ifc : type.implements) {
+            if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) {
+                baseIfcs.add(ifc)
+            }
+        }
+        return baseIfcs 
+    }
+
+    private def Set<Type> getAllIfcs(Type type) {
+        val Set<Type> baseIfcs = new HashSet()
+        if (type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)) {
+            val ifc = type as GeneratedType
+            for (impl : ifc.implements) {
+                if (impl instanceof GeneratedType && !(impl as GeneratedType).methodDefinitions.empty) {
+                    baseIfcs.add(impl)
+                }
+                baseIfcs.addAll(impl.getAllIfcs)
+            }
+        }
+        return baseIfcs 
+    }
+
+    private def List<String> toListOfNames(Collection<Type> types) {
+        val List<String> names = new ArrayList
+        for (type : types) {
+            names.add(type.fullyQualifiedName)
+        }
+        return names
+    }
+
+       /**
+        * Template method which generates class attributes.
+        * 
+        * @param boolean value which specify whether field is|isn't final
+        * @return string with class attributes and their types
+        */
     def private generateFields(boolean _final) '''
-        «IF !fields.empty»
-            «FOR f : field
-                private  «IF _final»final«ENDIF»  «f.returnType.resolveName» «f.name»;
+        «IF !properties.empty»
+            «FOR f : propertie
+                private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
             «ENDFOR»
         «ENDIF»
+    '''
+
+    def private generateAugmentField(boolean init) '''
         «IF augmentField != null»
-            private Map<Class<? extends «augmentField.returnType.resolveName»>, «augmentField.returnType.resolveName»> «augmentField.name» = new HashMap<>();
+            private final «Map.importedName»<Class<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name»«IF init» = new «HashMap.importedName»<>()«ENDIF»;
         «ENDIF»
     '''
 
+       /**
+        * Template method which generates setter methods
+        * 
+        * @return string with the setter methods 
+        */
     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»;
+        «FOR field : properties SEPARATOR '\n'»
+            public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) {
+                «generateRestrictions(field, "value")»
+
+                this.«field.fieldName» = value;
                 return this;
             }
         «ENDFOR»
         «IF augmentField != null»
-            
-            public «genType.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.resolveName»> augmentationType, «augmentField.returnType.resolveName» augmentation) {
+
+            public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class<? extends «augmentField.returnType.importedName»> augmentationType, «augmentField.returnType.importedName» augmentation) {
                 this.«augmentField.name».put(augmentationType, augmentation);
                 return this;
             }
         «ENDIF»
     '''
-    
+
+    /**
+     * Template method which generate constructor for IMPL class.
+     * 
+     * @return string with IMPL class constructor
+     */
     def private generateConstructor() '''
-        private «genType.name»«IMPL»() {
-            «IF !fields.empty»
-                «FOR field : fields»
-                    this.«field.name» = «genType.name»«BUILDER».this.«field.name»;
+        private «type.name»«IMPL»(«type.name»«BUILDER» builder) {
+            «val allProps = new ArrayList(properties)»
+            «val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type))»
+            «val keyType = type.getKey»
+            «IF isList && keyType != null»
+                «val keyProps = new ArrayList((keyType as GeneratedTransferObject).properties)»
+                «Collections.sort(keyProps,
+                    [ p1, p2 |
+                        return p1.name.compareTo(p2.name)
+                    ])
+                »
+                «FOR field : keyProps»
+                    «removeProperty(allProps, field.name)»
                 «ENDFOR»
+                «removeProperty(allProps, "key")»
+                if (builder.getKey() == null) {
+                    this._key = new «keyType.importedName»(
+                        «FOR keyProp : keyProps SEPARATOR ", "»
+                            builder.«keyProp.getterMethodName»()
+                        «ENDFOR»
+                    );
+                    «FOR field : keyProps»
+                        this.«field.fieldName» = builder.«field.getterMethodName»();
+                    «ENDFOR»
+                } else {
+                    this._key = builder.getKey();
+                    «FOR field : keyProps»
+                           this.«field.fieldName» = _key.«field.getterMethodName»();
+                    «ENDFOR»
+                }
             «ENDIF»
+            «FOR field : allProps»
+                this.«field.fieldName» = builder.«field.getterMethodName»();
+            «ENDFOR»
             «IF augmentField != null»
-                this.«augmentField.name».putAll(«genType.name»«BUILDER».this.«augmentField.name»);
+               switch (builder.«augmentField.name».size()) {
+                case 0:
+                    this.«augmentField.name» = «Collections.importedName».emptyMap();
+                    break;
+                case 1:
+                    final «Map.importedName».Entry<Class<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = builder.«augmentField.name».entrySet().iterator().next();
+                    this.«augmentField.name» = «Collections.importedName».<Class<? extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue());
+                    break;
+                default :
+                    this.«augmentField.name» = new «HashMap.importedName»<>(builder.«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»;
-                }
+
+    private def boolean implementsIfc(GeneratedType type, Type impl) {
+        for (Type ifc : type.implements) {
+            if (ifc.equals(impl)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private def Type getKey(GeneratedType type) {
+        for (m : type.methodDefinitions) {
+            if ("getKey".equals(m.name)) {
+                return m.returnType;
+            }
+        }
+        return null;
+    }
+
+    private def void removeProperty(Collection<GeneratedProperty> props, String name) {
+        var GeneratedProperty toRemove = null
+        for (p : props) {
+            if (p.name.equals(name)) {
+                toRemove = p;
+            }
+        }
+        if (toRemove != null) {
+            props.remove(toRemove);
+        }
+    }
+
+    /**
+     * Template method which generate getter methods for IMPL class.
+     * 
+     * @return string with getter methods
+     */
+    def private generateGetters(boolean addOverride) '''
+        «IF !properties.empty»
+            «FOR field : properties SEPARATOR '\n'»
+                «IF addOverride»@Override«ENDIF»
+                «field.getterMethod»
             «ENDFOR»
         «ENDIF»
         «IF augmentField != null»
 
             @SuppressWarnings("unchecked")
-            @Override
-            public <E extends «augmentField.returnType.resolveName»> E get«augmentField.name.toFirstUpper»(Class<E> augmentationType) {
+            «IF addOverride»@Override«ENDIF»
+            public <E extends «augmentField.returnType.importedName»> 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»
+    '''
+
+    /**
+     * Template method which generates the method <code>hashCode()</code>.
+     * 
+     * @return string with the <code>hashCode()</code> method definition in JAVA format
+     */
+    def protected generateHashCode() '''
+        «IF !properties.empty || augmentField != null»
+            @Override
+            public int hashCode() {
+                final int prime = 31;
+                int result = 1;
+                «FOR property : properties»
+                    «IF property.returnType.name.contains("[")»
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));
+                    «ELSE»
+                    result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
+                    «ENDIF»
+                «ENDFOR»
+                «IF augmentField != null»
+                    result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode());
+                «ENDIF»
+                return result;
+            }
+        «ENDIF»
+    '''
+
+    /**
+     * Template method which generates the method <code>equals()</code>.
+     * 
+     * @return string with the <code>equals()</code> method definition in JAVA format     
+     */
+    def protected generateEquals() '''
+        «IF !properties.empty || augmentField != null»
+            @Override
+            public boolean equals(java.lang.Object obj) {
+                if (this == obj) {
+                    return true;
+                }
+                if (obj == null) {
+                    return false;
+                }
+                if (getClass() != obj.getClass()) {
+                    return false;
+                }
+                «type.name»«IMPL» other = («type.name»«IMPL») obj;
+                «FOR property : properties»
+                    «val fieldName = property.fieldName»
+                    if («fieldName» == null) {
+                        if (other.«fieldName» != null) {
+                            return false;
+                        }
+                    «IF property.returnType.name.contains("[")»
+                    } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {
+                    «ELSE»
+                    } else if(!«fieldName».equals(other.«fieldName»)) {
+                    «ENDIF»
+                        return false;
+                    }
+                «ENDFOR»
+                «IF augmentField != null»
+                    «val fieldName = augmentField.name»
+                    if («fieldName» == null) {
+                        if (other.«fieldName» != null) {
+                            return false;
+                        }
+                    } else if(!«fieldName».equals(other.«fieldName»)) {
+                        return false;
+                    }
+                «ENDIF»
+                return true;
+            }
+        «ENDIF»
+    '''
+
+    def override generateToString(Collection<GeneratedProperty> properties) '''
+        «IF !(properties === null)»
+            @Override
+            public String toString() {
+                StringBuilder builder = new StringBuilder("«type.name» [");
+                boolean first = true;
+
+                «FOR property : properties»
+                    if («property.fieldName» != null) {
+                        if (first) {
+                            first = false;
+                        } else {
+                            builder.append(", ");
+                        }
+                        builder.append("«property.fieldName»=");
+                        «IF property.returnType.name.contains("[")»
+                            builder.append(«Arrays.importedName».toString(«property.fieldName»));
+                        «ELSE»
+                            builder.append(«property.fieldName»);
+                        «ENDIF»
+                     }
+                «ENDFOR»
+                «IF augmentField != null»
+                    if (first) {
+                        first = false;
+                    } else {
+                        builder.append(", ");
+                    }
+                    builder.append("«augmentField.name»=");
+                    builder.append(«augmentField.name».values());
+                «ENDIF»
+                return builder.append(']').toString();
+            }
         «ENDIF»
-        
     '''
-    
-    def private resolveName(Type type) {
-        GeneratorUtil.putTypeIntoImports(genType, type, imports);
-        GeneratorUtil.getExplicitType(genType, type, imports)
+
+    override protected getFullyQualifiedName() {
+        '''«type.fullyQualifiedName»Builder'''.toString
     }
-    
+
+    def implementedInterfaceGetter() '''
+    public «Class.importedName»<«type.importedName»> getImplementedInterface() {
+        return «type.importedName».class;
+    }
+    '''
+
 }