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=038a2a8c18a1a7252e3d52dc3050dbea48842e5c;hb=5b7dc4042d5827c60bf9ca9daaaf369242c931f9;hp=66b72cf9e62647a475bc359744bff63b7386f67a;hpb=b1f4e95dbefd402a3b9bc9804184006229cfc30d;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 66b72cf9e6..038a2a8c18 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 @@ -29,12 +29,17 @@ 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.ChildOf import org.opendaylight.yangtools.yang.binding.DataObject import org.opendaylight.yangtools.yang.binding.Identifiable +import org.opendaylight.yangtools.concepts.Builder +import org.opendaylight.yangtools.yang.binding.AugmentationHolder +import org.opendaylight.yangtools.sal.binding.model.api.Restrictions +import java.math.BigDecimal +import java.math.BigInteger +import com.google.common.collect.ImmutableList /** - * Template for generating JAVA builder classes. + * Template for generating JAVA builder classes. */ class BuilderTemplate extends BaseTemplate { @@ -49,6 +54,11 @@ class BuilderTemplate extends BaseTemplate { */ val static BUILDER = 'Builder' + /** + * Constant with the name of the BuilderFor interface + */ + val static BUILDERFOR = Builder.simpleName; + /** * Constant with suffix for the classes which are generated from the builder classes. */ @@ -73,12 +83,13 @@ class BuilderTemplate extends BaseTemplate { new(GeneratedType genType) { super(genType) this.properties = propertiesFromMethods(createMethods) + importMap.put(Builder.simpleName, Builder.package.name) } /** * 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() { @@ -91,9 +102,9 @@ class BuilderTemplate extends BaseTemplate { } /** - * Adds to the methods set all the methods of the implementedIfcs + * 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 */ @@ -126,7 +137,7 @@ class BuilderTemplate extends BaseTemplate { /** * Returns the first element of the list elements. - * + * * @param list of elements */ def private first(List elements) { @@ -135,7 +146,7 @@ class BuilderTemplate extends BaseTemplate { /** * Returns the name of the package from fullyQualifiedName. - * + * * @param fullyQualifiedName string with fully qualified type name (package + type) * @return string with the package name */ @@ -157,8 +168,8 @@ class BuilderTemplate extends BaseTemplate { /** * Creates set of generated property instances from getter methods. - * - * @param set of method signature instances which should be transformed to list of properties + * + * @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) { @@ -177,7 +188,7 @@ class BuilderTemplate extends BaseTemplate { /** * 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
    @@ -194,7 +205,7 @@ class BuilderTemplate extends BaseTemplate { 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") @@ -204,13 +215,13 @@ class BuilderTemplate extends BaseTemplate { } /** - * Template method which generates JAVA class body for builder class and for IMPL class. - * + * 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» { + public class «type.name»«BUILDER» implements «BUILDERFOR» <«type.importedName»> { «generateFields(false)» @@ -226,9 +237,9 @@ class BuilderTemplate extends BaseTemplate { «generateSetters» - «generateBuildMethod» - - «generateBuildBoxedMethod» + public «type.name» build() { + return new «type.name»«IMPL»(this); + } private static final class «type.name»«IMPL» implements «type.name» { @@ -245,66 +256,19 @@ class BuilderTemplate extends BaseTemplate { «generateHashCode()» «generateEquals()» - + «generateToString(properties)» } } ''' - def private generateBuildMethod() ''' - public «type.name» build() { - return new «type.name»«IMPL»(this); - } - ''' - - def private generateBuildBoxedMethod() { - if(type.suitableForBoxing && type.parentType != null && isContainerAndIsNotList(type)) { - val parentTypeBuilder = createParentTypeBuilder() - if (countMatches(parentTypeBuilder, "org") < 2) { - return ''' - public «type.parentType.importedName» buildBoxed() { - return new «parentTypeBuilder»().set«type.name»(build()).build(); - } - ''' - } - } - return '' - } - - def private int countMatches(String string, String subString) { - if (string.nullOrEmpty || subString.nullOrEmpty) { - return 0 - } - var int count = 0; - var int idx = 0; - while ((idx = string.indexOf(subString, idx)) != -1) { - count = count + 1; - idx = idx + subString.length(); - } - return count; - } - - def private createParentTypeBuilder() { - return type.parentType.packageName + "." + type.parentType.importedName + "Builder" - } - - def private boolean isContainerAndIsNotList(GeneratedType type) { - val isList = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(Identifiable), type)) - val implementsChildOf = implementsIfc(type, Types.parameterizedTypeFor(Types.typeForClass(ChildOf), type)) - - if (implementsChildOf && !isList) { - return true - } - return false; - } - /** * 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» @@ -318,14 +282,12 @@ class BuilderTemplate extends BaseTemplate { */ 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)» + «IF !(impl.methodDefinitions.empty)» + public «type.name»«BUILDER»(«impl.fullyQualifiedName» arg) { + «printConstructorPropertySetter(impl)» } «ENDIF» - «FOR implTypeImplement : implType.implements» + «FOR implTypeImplement : impl.implements» «generateConstructorFromIfc(implTypeImplement)» «ENDFOR» «ENDIF» @@ -421,7 +383,7 @@ class BuilderTemplate extends BaseTemplate { baseIfcs.add(ifc) } } - return baseIfcs + return baseIfcs } private def Set getAllIfcs(Type type) { @@ -435,7 +397,7 @@ class BuilderTemplate extends BaseTemplate { baseIfcs.addAll(impl.getAllIfcs) } } - return baseIfcs + return baseIfcs } private def List toListOfNames(Collection types) { @@ -471,7 +433,7 @@ class BuilderTemplate extends BaseTemplate { def private generateAugmentField(boolean isPrivate) ''' «IF augmentField != null» - «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName», «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>(); + «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName», «augmentField.returnType.importedName»> «augmentField.name» = «Collections.importedName».emptyMap(); «ENDIF» ''' @@ -483,43 +445,73 @@ class BuilderTemplate extends BaseTemplate { def private generateSetters() ''' «FOR field : properties SEPARATOR '\n'» «val length = field.fieldName + "_length"» - «val range = field.fieldName + "_range"» + «val restrictions = field.returnType.restrictions» + «IF restrictions != null» + «IF !restrictions.rangeConstraints.nullOrEmpty» + «val rangeGenerator = AbstractRangeGenerator.forType(field.returnType)» + «rangeGenerator.generateRangeChecker(field.name.toFirstUpper, restrictions.rangeConstraints)» + + «ENDIF» + «ENDIF» public «type.name»«BUILDER» set«field.name.toFirstUpper»(«field.returnType.importedName» value) { - «generateRestrictions(field, "value", length, range)» + «IF restrictions != null && !restrictions.rangeConstraints.nullOrEmpty» + if (value != null) { + «val rangeGenerator = AbstractRangeGenerator.forType(field.returnType)» + «IF field.returnType instanceof ConcreteType» + «rangeGenerator.generateRangeCheckerCall(field.name.toFirstUpper, "value")» + «ELSE» + «rangeGenerator.generateRangeCheckerCall(field.name.toFirstUpper, "value.getValue()")» + «ENDIF» + } + «ENDIF» + «generateRestrictions(field, "value", length)» 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)» + «val range = field.fieldName + "_range"» + «generateRangeMethod(range, 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) { + if (augmentation == null) { + return remove«augmentField.name.toFirstUpper»(augmentationType); + } + + if (!(this.«augmentField.name» instanceof «HashMap.importedName»)) { + this.«augmentField.name» = new «HashMap.importedName»<>(); + } + this.«augmentField.name».put(augmentationType, augmentation); return this; } + + public «type.name»«BUILDER» remove«augmentField.name.toFirstUpper»(«Class.importedName» augmentationType) { + if (this.«augmentField.name» instanceof «HashMap.importedName») { + this.«augmentField.name».remove(augmentationType); + } + return this; + } «ENDIF» ''' - def generateRestrictions(GeneratedProperty field, String paramName, String lengthGetter, String rangeGetter) ''' + def private generateRestrictions(GeneratedProperty field, String paramName, String lengthGetter) ''' «val Type type = field.returnType» «IF type instanceof ConcreteType» - «createRestrictions(type, paramName, type.name.contains("["), lengthGetter, rangeGetter)» + «createRestrictions(type, paramName, type.name.contains("["), lengthGetter)» «ELSEIF type instanceof GeneratedTransferObject» - «createRestrictions(type, paramName, isArrayType(type as GeneratedTransferObject), lengthGetter, rangeGetter)» + «createRestrictions(type, paramName, isArrayType(type as GeneratedTransferObject), lengthGetter)» «ENDIF» ''' - def private createRestrictions(Type type, String paramName, boolean isArray, String lengthGetter, String rangeGetter) ''' + def private createRestrictions(Type type, String paramName, boolean isArray, String lengthGetter) ''' «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» ''' @@ -540,19 +532,69 @@ class BuilderTemplate extends BaseTemplate { } ''' - 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; + def private generateLengthMethod(String methodName, Type type, String className, String varName) ''' + «val Restrictions restrictions = type.restrictions» + «IF restrictions != null && !(restrictions.lengthConstraints.empty)» + «val numberClass = restrictions.lengthConstraints.iterator.next.min.class» + /** + * @deprecated This method is slated for removal in a future release. See BUG-1485 for details. + */ + @Deprecated + public static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> «methodName»() { + «IF numberClass.equals(typeof(BigDecimal))» + «lengthBody(restrictions, numberClass, className, varName)» + «ELSE» + «lengthBody(restrictions, typeof(BigInteger), className, varName)» + «ENDIF» + } + «ENDIF» + ''' + + def private lengthBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + if («varName» == null) { + synchronized («className».class) { + if («varName» == null) { + «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder(); + «FOR r : restrictions.lengthConstraints» + builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»)); + «ENDFOR» + «varName» = builder.build(); } } - if (!isValidRange) { - throw new IllegalArgumentException(String.format("Invalid range: %s, expected: %s.", «paramName», «getterName»)); + } + return «varName»; + ''' + + def private generateRangeMethod(String methodName, Restrictions restrictions, Type returnType, String className, String varName) ''' + «IF restrictions != null && !(restrictions.rangeConstraints.empty)» + «val number = returnType.importedNumber» + /** + * @deprecated This method is slated for removal in a future release. See BUG-1485 for details. + */ + @Deprecated + public static «List.importedName»<«Range.importedName»<«number»>> «methodName»() { + «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)» + «rangeBody(restrictions, BigDecimal, className, varName)» + «ELSE» + «rangeBody(restrictions, BigInteger, className, varName)» + «ENDIF» + } + «ENDIF» + ''' + + def private rangeBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + if («varName» == null) { + synchronized («className».class) { + if («varName» == null) { + «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder(); + «FOR r : restrictions.rangeConstraints» + builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»)); + «ENDFOR» + «varName» = builder.build(); + } } } + return «varName»; ''' def private CharSequence generateCopyConstructor(boolean impl) ''' @@ -591,25 +633,32 @@ class BuilderTemplate extends BaseTemplate { 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»); + «IF impl» + switch (base.«augmentField.name».size()) { + case 0: + this.«augmentField.name» = «Collections.importedName».emptyMap(); + break; + case 1: + final «Map.importedName».Entry<«Class.importedName», «augmentField.returnType.importedName»> e = base.«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»<>(base.«augmentField.name»); + } + «ELSE» + if (base instanceof «type.name»«IMPL») { + «type.name»«IMPL» impl = («type.name»«IMPL») base; + if (!impl.«augmentField.name».isEmpty()) { + this.«augmentField.name» = new «HashMap.importedName»<>(impl.«augmentField.name»); } - «ELSE» - this.«augmentField.name» = new «HashMap.importedName»<>(«prop».«augmentField.name»); - «ENDIF» - «IF !impl»}«ENDIF» + } else if (base instanceof «AugmentationHolder.importedName») { + @SuppressWarnings("unchecked") + «AugmentationHolder.importedName»<«type.importedName»> casted =(«AugmentationHolder.importedName»<«type.importedName»>) base; + if (!casted.augmentations().isEmpty()) { + this.«augmentField.name» = new «HashMap.importedName»<>(casted.augmentations()); + } + } + «ENDIF» «ENDIF» } ''' @@ -646,7 +695,7 @@ class BuilderTemplate extends BaseTemplate { /** * Template method which generate getter methods for IMPL class. - * + * * @return string with getter methods */ def private generateGetters(boolean addOverride) ''' @@ -671,7 +720,7 @@ class BuilderTemplate extends BaseTemplate { /** * Template method which generates the method hashCode(). - * + * * @return string with the hashCode() method definition in JAVA format */ def protected generateHashCode() ''' @@ -697,8 +746,8 @@ class BuilderTemplate extends BaseTemplate { /** * Template method which generates the method equals(). - * - * @return string with the equals() method definition in JAVA format + * + * @return string with the equals() method definition in JAVA format */ def protected generateEquals() ''' «IF !properties.empty || augmentField != null» @@ -803,15 +852,15 @@ class BuilderTemplate extends BaseTemplate { 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)