X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=code-generator%2Fbinding-java-api-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fyangtools%2Fsal%2Fjava%2Fapi%2Fgenerator%2FBuilderTemplate.xtend;h=286b5f06b17017a6c01fe9ad678db612a65af16b;hb=a71ab3b0e3e59e938bae3b71f614e08b335e641e;hp=18d6730bd10dd0953ec60d6ddfc3e83ca485ffb1;hpb=7d7503ed440129ac9736bfd1e5ee99ebb3ba18b8;p=yangtools.git diff --git a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend index 18d6730bd1..286b5f06b1 100644 --- a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend +++ b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/BuilderTemplate.xtend @@ -1,383 +1,777 @@ -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 -import static org.opendaylight.yangtools.binding.generator.util.Types.* -import java.util.HashMap -import java.util.Collections - -/** - * Template for generating JAVA builder classes. - */ - -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' - - /** - * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME - */ - var GeneratedProperty augmentField - - /** - * Set of class attributes (fields) which are derived from the getter methods names - */ - val Set properties - - /** - * Constructs new instance of this class. - * @throws IllegalArgumentException if genType equals null - */ - new(GeneratedType genType) { - super(genType) - this.properties = propertiesFromMethods(createMethods) - } - - /** - * Returns set of method signature instances which contains all the methods of the genType - * and all the methods of the implemented interfaces. - * - * @returns set of method signature instances - */ - def private Set createMethods() { - val Set methods = new LinkedHashSet - methods.addAll(type.methodDefinitions) - collectImplementedMethods(methods, type.implements) - return methods - } - - - /** - * Adds to the methods set all the methods of the implementedIfcs - * and recursivelly their implemented interfaces. - * - * @param methods set of method signatures - * @param implementedIfcs list of implemented interfaces - */ - def private void collectImplementedMethods(Set methods, List 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) - 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 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.propertyFromGetter - } - } - } - } - } - - - /** - * Returns the first element of the list elements. - * - * @param list of elements - */ - def private first(List elements) { - elements.get(0) - } - - /** - * Returns the name of the package from fullyQualifiedName. - * - * @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 fullyQualifiedName - * - * @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) - } - - - /** - * Creates set of generated property instances from getter methods. - * - * @param set of method signature instances which should be transformed to list of properties - * @return set of generated property instances which represents the getter methods - */ - def private propertiesFromMethods(Set methods) { - - - if (methods == null || methods.isEmpty()) { - return Collections.emptySet - } - val Set result = new LinkedHashSet - for (m : methods) { - val createdField = m.propertyFromGetter - if (createdField != null) { - result.add(createdField) - } - } - return result - } - - /** - * Creates generated property instance from the getter method 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 method - * @throws IllegalArgumentException
    - *
  • if the method equals null
  • - *
  • if the name of the method equals null
  • - *
  • if the name of the method is empty
  • - *
  • if the return type of the method equals null
  • - *
- */ - 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!") - } - 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 - } - } - - /** - * 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)» - - «generateGetters(false)» - - «generateSetters» - - public «type.name» build() { - return new «type.name»«IMPL»(this); - } - - private static final class «type.name»«IMPL» implements «type.name» { - - «generateFields(true)» - - «generateConstructor» - - «generateGetters(true)» - - «generateHashCode()» - - «generateEquals()» - } - - } - ''' - - /** - * 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 !properties.empty» - «FOR f : properties» - private «IF _final»final«ENDIF» «f.returnType.importedName» «f.fieldName»; - «ENDFOR» - «ENDIF» - «IF augmentField != null» - private «Map.importedName», «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>(); - «ENDIF» - ''' - - /** - * Template method which generates setter methods - * - * @return string with the setter methods - */ - def private generateSetters() ''' - «FOR field : properties SEPARATOR '\n'» - public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) { - this.«field.fieldName» = value; - return this; - } - «ENDFOR» - «IF augmentField != null» - - public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(Class 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 «type.name»«IMPL»(«type.name»«BUILDER» builder) { - «IF !properties.empty» - «FOR field : properties» - this.«field.fieldName» = builder.«field.getterMethodName»(); - «ENDFOR» - «ENDIF» - «IF augmentField != null» - this.«augmentField.name».putAll(builder.«augmentField.name»); - «ENDIF» - } - ''' - - - /** - * 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") - «IF addOverride»@Override«ENDIF» - public E get«augmentField.name.toFirstUpper»(Class augmentationType) { - if (augmentationType == null) { - throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!"); - } - return (E) «augmentField.name».get(augmentationType); - } - «ENDIF» - ''' - - /** - * Template method which generates the method hashCode(). - * - * @return string with the hashCode() 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» - result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode()); - «ENDFOR» - «IF augmentField != null» - result = prime * result + ((«augmentField.name» == null) ? 0 : «augmentField.name».hashCode()); - «ENDIF» - return result; - } - «ENDIF» - ''' - - /** - * Template method which generates the method equals(). - * - * @return string with the equals() 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; - } - } else if(!«fieldName».equals(other.«fieldName»)) { - 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» - ''' - - override protected getFullyQualifiedName() { - '''«type.fullyQualifiedName»Builder'''.toString - } - -} - +/* + * 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 com.google.common.collect.ImmutableSortedSet +import com.google.common.collect.Range +import java.util.ArrayList +import java.util.Arrays +import java.util.Collection +import java.util.Collections +import java.util.HashMap +import java.util.HashSet +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.ConcreteType +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 +import org.opendaylight.yangtools.yang.binding.DataObject +import org.opendaylight.yangtools.yang.binding.Identifiable + +/** + * Template for generating JAVA builder classes. + */ + +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' + + /** + * Generated property is set if among methods is found one with the name GET_AUGMENTATION_METHOD_NAME + */ + var GeneratedProperty augmentField + + /** + * Set of class attributes (fields) which are derived from the getter methods names + */ + val Set properties + + private static val METHOD_COMPARATOR = new AlphabeticallyTypeMemberComparator(); + + /** + * Constructs new instance of this class. + * @throws IllegalArgumentException if genType equals null + */ + new(GeneratedType genType) { + super(genType) + this.properties = propertiesFromMethods(createMethods) + } + + /** + * Returns set of method signature instances which contains all the methods of the genType + * and all the methods of the implemented interfaces. + * + * @returns set of method signature instances + */ + def private Set createMethods() { + val Set methods = new LinkedHashSet(); + methods.addAll(type.methodDefinitions) + collectImplementedMethods(methods, type.implements) + val Set sortedMethods = ImmutableSortedSet.orderedBy(METHOD_COMPARATOR).addAll(methods).build() + + return sortedMethods + } + + /** + * Adds to the methods set all the methods of the implementedIfcs + * and recursively their implemented interfaces. + * + * @param methods set of method signatures + * @param implementedIfcs list of implemented interfaces + */ + def private void collectImplementedMethods(Set methods, List 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) + collectImplementedMethods(methods, ifc.implements) + } else if (implementedIfc.fullyQualifiedName == Augmentable.name) { + for (m : Augmentable.methods) { + if (m.name == GET_AUGMENTATION_METHOD_NAME) { + val fullyQualifiedName = m.returnType.name + val pkg = fullyQualifiedName.package + val name = fullyQualifiedName.name + val tmpGenTO = new GeneratedTOBuilderImpl(pkg, name) + 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.propertyFromGetter + } + } + } + } + } + + /** + * Returns the first element of the list elements. + * + * @param list of elements + */ + def private first(List elements) { + elements.get(0) + } + + /** + * Returns the name of the package from fullyQualifiedName. + * + * @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 fullyQualifiedName + * + * @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) + } + + /** + * Creates set of generated property instances from getter methods. + * + * @param set of method signature instances which should be transformed to list of properties + * @return set of generated property instances which represents the getter methods + */ + def private propertiesFromMethods(Collection methods) { + if (methods == null || methods.isEmpty()) { + return Collections.emptySet + } + val Set result = new LinkedHashSet + for (m : methods) { + val createdField = m.propertyFromGetter + if (createdField != null) { + result.add(createdField) + } + } + return result + } + + /** + * Creates generated property instance from the getter method 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 method + * @throws IllegalArgumentException
    + *
  • if the method equals null
  • + *
  • if the name of the method equals null
  • + *
  • if the name of the method is empty
  • + *
  • if the return type of the method equals null
  • + *
+ */ + 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!") + } + var prefix = "get"; + if(Types.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 + } + } + + /** + * Template method which generates JAVA class body for builder class and for IMPL class. + * + * @return string with JAVA source code + */ + override body() ''' + «wrapToDocumentation(formatDataForJavaDoc(type))» + public class «type.name»«BUILDER» { + + «generateFields(false)» + + «generateAugmentField(true)» + + «generateConstructorsFromIfcs(type)» + + «generateCopyConstructor(false)» + + «generateMethodFieldsFrom(type)» + + «generateGetters(false)» + + «generateSetters» + + public «type.name» build() { + return new «type.name»«IMPL»(this); + } + + private static final class «type.name»«IMPL» implements «type.name» { + + «implementedInterfaceGetter» + + «generateFields(true)» + + «generateAugmentField(false)» + + «generateCopyConstructor(true)» + + «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 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: + *
    + «FOR impl : type.getAllIfcs» + *
  • «impl.fullyQualifiedName»
  • + «ENDFOR» + *
+ * + * @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 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 getBaseIfcs(GeneratedType type) { + val List baseIfcs = new ArrayList(); + for (ifc : type.implements) { + if (ifc instanceof GeneratedType && !(ifc as GeneratedType).methodDefinitions.empty) { + baseIfcs.add(ifc) + } + } + return baseIfcs + } + + private def Set getAllIfcs(Type type) { + val Set 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 toListOfNames(Collection types) { + val List 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 properties !== null» + «FOR f : properties» + private«IF _final» final«ENDIF» «f.returnType.importedName» «f.fieldName»; + «val restrictions = f.returnType.restrictions» + «IF !_final && restrictions != null» + «IF !(restrictions.lengthConstraints.empty)» + private static «List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> «f.fieldName»_length; + «ENDIF» + «IF !(restrictions.rangeConstraints.empty)» + private static «List.importedName»<«Range.importedName»<«f.returnType.importedNumber»>> «f.fieldName»_range; + «ENDIF» + «ENDIF» + «ENDFOR» + «ENDIF» + ''' + + def private generateAugmentField(boolean init) ''' + «IF augmentField != null» + private «Map.importedName»<«Class.importedName», «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>(); + «ENDIF» + ''' + + /** + * Template method which generates setter methods + * + * @return string with the setter methods + */ + def private generateSetters() ''' + «FOR field : properties SEPARATOR '\n'» + «val length = field.fieldName + "_length"» + «val range = field.fieldName + "_range"» + public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) { + «generateRestrictions(field, "value", length, range)» + this.«field.fieldName» = value; + return this; + } + «generateLengthMethod(length, field.returnType, type.name+BUILDER, length)» + «generateRangeMethod(range, field.returnType.restrictions, field.returnType, type.name+BUILDER, range)» + «ENDFOR» + «IF augmentField != null» + + public «type.name»«BUILDER» add«augmentField.name.toFirstUpper»(«Class.importedName» augmentationType, «augmentField.returnType.importedName» augmentation) { + this.«augmentField.name».put(augmentationType, augmentation); + return this; + } + «ENDIF» + ''' + + def generateRestrictions(GeneratedProperty field, String paramName, String lengthGetter, String rangeGetter) ''' + «val Type type = field.returnType» + «IF type instanceof ConcreteType» + «createRestrictions(type, paramName, type.name.contains("["), lengthGetter, rangeGetter)» + «ELSEIF type instanceof GeneratedTransferObject» + «createRestrictions(type, paramName, isArrayType(type as GeneratedTransferObject), lengthGetter, rangeGetter)» + «ENDIF» + ''' + + def private createRestrictions(Type type, String paramName, boolean isArray, String lengthGetter, String rangeGetter) ''' + «val restrictions = type.getRestrictions» + «IF restrictions !== null» + «val boolean isNestedType = !(type instanceof ConcreteType)» + «IF !restrictions.lengthConstraints.empty» + «generateLengthRestriction(type, paramName, lengthGetter, isNestedType, isArray)» + «ENDIF» + «IF !restrictions.rangeConstraints.empty» + «generateRangeRestriction(type, paramName, rangeGetter, isNestedType)» + «ENDIF» + «ENDIF» + ''' + + def private generateLengthRestriction(Type type, String paramName, String getterName, boolean isNestedType, boolean isArray) ''' + «val restrictions = type.getRestrictions» + if («paramName» != null) { + «val clazz = restrictions.lengthConstraints.iterator.next.min.class» + «printLengthConstraint(type, clazz, paramName, isNestedType, isArray)» + boolean isValidLength = false; + for («Range.importedName»<«clazz.importedNumber»> r : «getterName»()) { + if (r.contains(_constraint)) { + isValidLength = true; + } + } + if (!isValidLength) { + throw new IllegalArgumentException(String.format("Invalid length: %s, expected: %s.", «paramName», «getterName»)); + } + } + ''' + + def private generateRangeRestriction(Type type, String paramName, String getterName, boolean isNestedType) ''' + if («paramName» != null) { + «printRangeConstraint(type, paramName, isNestedType)» + boolean isValidRange = false; + for («Range.importedName»<«type.importedNumber»> r : «getterName»()) { + if (r.contains(_constraint)) { + isValidRange = true; + } + } + if (!isValidRange) { + throw new IllegalArgumentException(String.format("Invalid range: %s, expected: %s.", «paramName», «getterName»)); + } + } + ''' + + def private CharSequence generateCopyConstructor(boolean impl) ''' + «IF impl»private«ELSE»public«ENDIF» «type.name»«IF impl»«IMPL»«ELSE»«BUILDER»«ENDIF»(«type.name»«IF impl»«BUILDER»«ENDIF» base) { + «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 (base.getKey() == null) { + this._key = new «keyType.importedName»( + «FOR keyProp : keyProps SEPARATOR ", "» + base.«keyProp.getterMethodName»() + «ENDFOR» + ); + «FOR field : keyProps» + this.«field.fieldName» = base.«field.getterMethodName»(); + «ENDFOR» + } else { + this._key = base.getKey(); + «FOR field : keyProps» + this.«field.fieldName» = _key.«field.getterMethodName»(); + «ENDFOR» + } + «ENDIF» + «FOR field : allProps» + this.«field.fieldName» = base.«field.getterMethodName»(); + «ENDFOR» + «IF augmentField != null» + «IF !impl»if (base instanceof «type.name»«IMPL») {«ENDIF» + «IF !impl»«type.name»«IMPL» _impl = («type.name»«IMPL») base;«ENDIF» + «val prop = if (impl) "base" else "_impl"» + «IF impl» + switch («prop».«augmentField.name».size()) { + case 0: + this.«augmentField.name» = «Collections.importedName».emptyMap(); + break; + case 1: + final «Map.importedName».Entry<«Class.importedName», «augmentField.returnType.importedName»> e = «prop».«augmentField.name».entrySet().iterator().next(); + this.«augmentField.name» = «Collections.importedName».<«Class.importedName», «augmentField.returnType.importedName»>singletonMap(e.getKey(), e.getValue()); + break; + default : + this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»); + } + «ELSE» + this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»); + «ENDIF» + «IF !impl»}«ENDIF» + «ENDIF» + } + ''' + + 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 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") + «IF addOverride»@Override«ENDIF» + public E get«augmentField.name.toFirstUpper»(«Class.importedName» augmentationType) { + if (augmentationType == null) { + throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!"); + } + return (E) «augmentField.name».get(augmentationType); + } + «ENDIF» + ''' + + /** + * Template method which generates the method hashCode(). + * + * @return string with the hashCode() 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 equals(). + * + * @return string with the equals() method definition in JAVA format + */ + def protected generateEquals() ''' + «IF !properties.empty || augmentField != null» + @Override + public boolean equals(«Object.importedName» obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof «DataObject.importedName»)) { + return false; + } + if (!«type.importedName».class.equals(((«DataObject.importedName»)obj).getImplementedInterface())) { + return false; + } + «type.importedName» other = («type.importedName»)obj; + «FOR property : properties» + «val fieldName = property.fieldName» + if («fieldName» == null) { + if (other.«property.getterMethodName»() != null) { + return false; + } + «IF property.returnType.name.contains("[")» + } else if(!«Arrays.importedName».equals(«fieldName», other.«property.getterMethodName»())) { + «ELSE» + } else if(!«fieldName».equals(other.«property.getterMethodName»())) { + «ENDIF» + return false; + } + «ENDFOR» + «IF augmentField != null» + if (getClass() == obj.getClass()) { + // Simple case: we are comparing against self + «type.name»«IMPL» otherImpl = («type.name»«IMPL») obj; + «val fieldName = augmentField.name» + if («fieldName» == null) { + if (otherImpl.«fieldName» != null) { + return false; + } + } else if(!«fieldName».equals(otherImpl.«fieldName»)) { + return false; + } + } else { + // Hard case: compare our augments with presence there... + for («Map.importedName».Entry<«Class.importedName», «augmentField.returnType.importedName»> e : «augmentField.name».entrySet()) { + if (!e.getValue().equals(other.getAugmentation(e.getKey()))) { + return false; + } + } + // .. and give the other one the chance to do the same + if (!obj.equals(this)) { + return false; + } + } + «ENDIF» + return true; + } + «ENDIF» + ''' + + def override generateToString(Collection properties) ''' + «IF !(properties === null)» + @Override + public «String.importedName» toString() { + «StringBuilder.importedName» builder = new «StringBuilder.importedName» ("«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» + ''' + + override protected getFullyQualifiedName() { + '''«type.fullyQualifiedName»Builder'''.toString + } + + def implementedInterfaceGetter() ''' + public «Class.importedName»<«type.importedName»> getImplementedInterface() { + return «type.importedName».class; + } + ''' + + private def createDescription(GeneratedType type) { + return ''' + Class that builds {@link «type.importedName»} instances. + + @see «type.importedName» + ''' + } + + override def protected String formatDataForJavaDoc(GeneratedType type) { + val typeDescription = createDescription(type) + + return ''' + «IF !typeDescription.nullOrEmpty» + «typeDescription» + «ENDIF» + '''.toString + } +} +