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» extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> «augmentField.name» = new «HashMap.importedName»<>();
+ «IF isPrivate»private «ENDIF»«Map.importedName»<«Class.importedName» extends «augmentField.returnType.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» extends «augmentField.returnType.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» extends «augmentField.returnType.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 extends Number> 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 extends Number> 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» extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = «prop».«augmentField.name».entrySet().iterator().next();
- this.«augmentField.name» = «Collections.importedName».<«Class.importedName» extends «augmentField.returnType.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» extends «augmentField.returnType.importedName»>, «augmentField.returnType.importedName»> e = base.«augmentField.name».entrySet().iterator().next();
+ this.«augmentField.name» = «Collections.importedName».<«Class.importedName» extends «augmentField.returnType.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)