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%2FClassTemplate.xtend;h=6699d502006c1682cea241daa1d322b033a67d8c;hb=28d6f7cda076e716ed70c120344a2486664ae552;hp=85b2df5d6243ad2f765ffae0943d1e91a8203f9e;hpb=4f83d8d8730b1d279b83632195419ea41cda0a8f;p=mdsal.git diff --git a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend index 85b2df5d62..6699d50200 100644 --- a/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend +++ b/code-generator/binding-java-api-generator/src/main/java/org/opendaylight/yangtools/sal/java/api/generator/ClassTemplate.xtend @@ -7,24 +7,30 @@ */ package org.opendaylight.yangtools.sal.java.api.generator +import com.google.common.collect.ImmutableList +import com.google.common.collect.Lists +import com.google.common.collect.Range +import com.google.common.io.BaseEncoding +import java.beans.ConstructorProperties +import java.math.BigDecimal +import java.math.BigInteger +import java.util.ArrayList +import java.util.Arrays +import java.util.Collections import java.util.List +import java.util.regex.Pattern import org.opendaylight.yangtools.binding.generator.util.TypeConstants import org.opendaylight.yangtools.sal.binding.model.api.Constant import org.opendaylight.yangtools.sal.binding.model.api.Enumeration 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 java.util.ArrayList -import java.util.Collections import java.util.Arrays import org.opendaylight.yangtools.sal.binding.model.api.Restrictions -import com.google.common.collect.Range -import java.util.regex.Pattern -import com.google.common.io.BaseEncoding -import java.beans.ConstructorProperties -import com.google.common.collect.Lists +import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition +import com.google.common.base.Preconditions /** - * Template for generating JAVA class. + * Template for generating JAVA class. */ class ClassTemplate extends BaseTemplate { @@ -33,28 +39,27 @@ class ClassTemplate extends BaseTemplate { protected val List parentProperties protected val Iterable allProperties; protected val Restrictions restrictions - + /** * List of enumeration which are generated as JAVA enum type. */ protected val List enums - + /** * List of constant instances which are generated as JAVA public static final attributes. */ protected val List consts - + /** * List of generated types which are enclosed inside genType */ protected val List enclosedGeneratedTypes; - - + protected val GeneratedTransferObject genTO; /** * Creates instance of this class with concrete genType. - * + * * @param genType generated transfer object which will be transformed to JAVA class source code */ new(GeneratedTransferObject genType) { @@ -78,29 +83,27 @@ class ClassTemplate extends BaseTemplate { this.enclosedGeneratedTypes = genType.enclosedTypes } - /** * Generates JAVA class source code (class body only). - * + * * @return string with JAVA class body source code */ def CharSequence generateAsInnerClass() { return generateBody(true) } - override protected body() { generateBody(false); } /** * Template method which generates class body. - * + * * @param isInnerClass boolean value which specify if generated class is|isn't inner * @return string with class source code in JAVA format */ def protected generateBody(boolean isInnerClass) ''' - «type.comment.asJavadoc» + «wrapToDocumentation(formatDataForJavaDoc(type))» «generateClassDeclaration(isInnerClass)» { «suidDeclaration» «innerClassesDeclarations» @@ -108,8 +111,13 @@ class ClassTemplate extends BaseTemplate { «constantsDeclarations» «generateFields» + «IF restrictions != null && (!restrictions.rangeConstraints.nullOrEmpty || + !restrictions.lengthConstraints.nullOrEmpty)» + «generateConstraints» + + «ENDIF» «constructors» - + «defaultInstance» «FOR field : properties SEPARATOR "\n"» @@ -119,38 +127,84 @@ class ClassTemplate extends BaseTemplate { «ENDIF» «ENDFOR» + «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)» + «generateGetValueForBitsTypeDef» + «ENDIF» + «generateHashCode» «generateEquals» «generateToString(genTO.toStringIdentifiers)» - «generateLengthMethod("length", genTO, genTO.importedName, "_length")» + «generateLengthMethod("length", "_length")» - «generateRangeMethod("range", genTO, genTO.importedName, "_range")» + «generateRangeMethod("range", "_range")» } + ''' + /** + * Template method which generates the method getValue() for typedef, + * which base type is BitsDefinition. + * + * @return string with the getValue() method definition in JAVA format + */ + def protected generateGetValueForBitsTypeDef() ''' + + public boolean[] getValue() { + return new boolean[]{ + «FOR property: genTO.properties SEPARATOR ','» + «property.fieldName» + «ENDFOR» + }; + } + ''' + + def private generateLengthMethod(String methodName, String varName) ''' + «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»() { + return «varName»; + } + «ENDIF» + ''' + + def private generateRangeMethod(String methodName, String varName) ''' + «IF restrictions != null && !(restrictions.rangeConstraints.empty)» + «val returnType = allProperties.iterator.next.returnType» + /** + * @deprecated This method is slated for removal in a future release. See BUG-1485 for details. + */ + @Deprecated + public static «List.importedName»<«Range.importedName»<«returnType.importedNumber»>> «methodName»() { + return «varName»; + } + «ENDIF» + ''' /** * Template method which generates inner classes inside this interface. - * + * * @return string with the source code for inner classes in JAVA format */ def protected innerClassesDeclarations() ''' «IF !enclosedGeneratedTypes.empty» «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"» «IF (innerClass instanceof GeneratedTransferObject)» - «val classTemplate = new ClassTemplate(innerClass as GeneratedTransferObject)» + «val classTemplate = new ClassTemplate(innerClass)» «classTemplate.generateAsInnerClass» - + «ENDIF» «ENDFOR» «ENDIF» ''' - - + def protected constructors() ''' «IF genTO.unionType» «genUnionConstructor» @@ -165,6 +219,55 @@ class ClassTemplate extends BaseTemplate { «ENDIF» ''' + def private generateConstraints() ''' + static { + «IF !restrictions.rangeConstraints.nullOrEmpty» + «generateRangeConstraints» + «ENDIF» + «IF !restrictions.lengthConstraints.nullOrEmpty» + «generateLengthConstraints» + «ENDIF» + } + ''' + + private def generateRangeConstraints() ''' + «IF !allProperties.nullOrEmpty» + «val returnType = allProperties.iterator.next.returnType» + «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)» + «rangeBody(restrictions, BigDecimal, genTO.importedName, "_range")» + «ELSE» + «rangeBody(restrictions, BigInteger, genTO.importedName, "_range")» + «ENDIF» + «ENDIF» + ''' + + private def rangeBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + «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(); + ''' + + private def lengthBody(Restrictions restrictions, Class numberClass, String className, String varName) ''' + «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(); + ''' + + private def generateLengthConstraints() ''' + «IF restrictions != null && !(restrictions.lengthConstraints.empty)» + «val numberClass = restrictions.lengthConstraints.iterator.next.min.class» + «IF numberClass.equals(typeof(BigDecimal))» + «lengthBody(restrictions, numberClass, genTO.importedName, "_length")» + «ELSE» + «lengthBody(restrictions, typeof(BigInteger), genTO.importedName, "_length")» + «ENDIF» + «ENDIF» + ''' + def protected allValuesConstructor() ''' «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")» @«ConstructorProperties.importedName»("value") @@ -173,13 +276,37 @@ class ClassTemplate extends BaseTemplate { «IF false == parentProperties.empty» super(«parentProperties.asArguments»); «ENDIF» - «FOR p : allProperties» + «FOR p : allProperties» «generateRestrictions(type, p.fieldName.toString, p.returnType)» «ENDFOR» - «FOR p : properties» + + «/* + * If we have patterns, we need to apply them to the value field. This is a sad + * consequence of how this code is structured. + */ + IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")» + + «Preconditions.importedName».checkNotNull(_value, "Supplied value may not be null"); + + «FOR c : consts» + «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME && c.value instanceof List» + for (Pattern p : patterns) { + «Preconditions.importedName».checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match any of the permitted patterns %s", _value, «TypeConstants.PATTERN_CONSTANT_NAME»); + } + + «ENDIF» + «ENDFOR» + «ENDIF» + + «FOR p : properties» + «IF p.returnType.importedName.contains("[]")» + this.«p.fieldName» = «p.fieldName» == null ? null : «p.fieldName».clone(); + «ELSE» this.«p.fieldName» = «p.fieldName»; + «ENDIF» «ENDFOR» } + ''' def protected genUnionConstructor() ''' @@ -197,11 +324,13 @@ class ClassTemplate extends BaseTemplate { «IF false == parentProperties.empty» super(«parentProperties.asArguments»); «ENDIF» - «generateRestrictions(type, property.fieldName.toString, property.returnType)» - this.«property.fieldName» = «property.name»; - «FOR p : other» + + «generateRestrictions(type, property.fieldName.toString, property.returnType)» + + this.«property.fieldName» = «property.name»; + «FOR p : other» this.«p.fieldName» = null; - «ENDFOR» + «ENDFOR» } ''' @@ -215,7 +344,7 @@ class ClassTemplate extends BaseTemplate { «IF false == parentProperties.empty» super(source); «ENDIF» - «FOR p : properties» + «FOR p : properties» this.«p.fieldName» = source.«p.fieldName»; «ENDFOR» } @@ -238,12 +367,22 @@ class ClassTemplate extends BaseTemplate { «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))» public static «genTO.name» getDefaultInstance(String defaultValue) { «IF "byte[]".equals(prop.returnType.name)» - «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64(); + «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64(); return new «genTO.name»(baseEncoding.decode(defaultValue)); «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)» return new «genTO.name»(defaultValue); «ELSEIF allProperties.size > 1» «bitsArgs» + «ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)» + return new «genTO.name»(Boolean.valueOf(defaultValue)); + «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)» + return new «genTO.name»(Byte.valueOf(defaultValue)); + «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)» + return new «genTO.name»(Short.valueOf(defaultValue)); + «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)» + return new «genTO.name»(Integer.valueOf(defaultValue)); + «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)» + return new «genTO.name»(Long.valueOf(defaultValue)); «ELSE» return new «genTO.name»(new «prop.returnType.importedName»(defaultValue)); «ENDIF» @@ -260,7 +399,7 @@ class ClassTemplate extends BaseTemplate { int i = 0; return new «genTO.name»( «FOR prop : allProperties SEPARATOR ","» - properties.get(i++).equals(defaultValue) ? new «Boolean.importedName»("true") : null + properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null «ENDFOR» ); ''' @@ -273,7 +412,7 @@ class ClassTemplate extends BaseTemplate { /** * Template method which generates JAVA class declaration. - * + * * @param isInnerClass boolean value which specify if generated class is|isn't inner * @return string with class declaration in JAVA format */ @@ -296,10 +435,10 @@ class ClassTemplate extends BaseTemplate { ENDFOR»« ENDIF »''' - + /** * Template method which generates JAVA enum type. - * + * * @return string with inner enum source code in JAVA format */ def protected enumDeclarations() ''' @@ -313,14 +452,14 @@ class ClassTemplate extends BaseTemplate { def protected suidDeclaration() ''' «IF genTO.SUID != null» - private static final long serialVersionUID = «genTO.SUID.value»L; + private static final long serialVersionUID = «genTO.SUID.value»L; «ENDIF» ''' /** - * Template method wich generates JAVA constants. - * - * @return string with constants in JAVA format + * Template method which generates JAVA constants. + * + * @return string with constants in JAVA format */ def protected constantsDeclarations() ''' «IF !consts.empty» @@ -328,12 +467,11 @@ class ClassTemplate extends BaseTemplate { «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME» «val cValue = c.value» «IF cValue instanceof List» - «val cValues = cValue as List» - private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST» = new «ArrayList.importedName»<«Pattern.importedName»>(); - public static final «List.importedName» «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(« - FOR v : cValues SEPARATOR ", "»« + private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST»; + public static final «List.importedName» «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(« + FOR v : cValue SEPARATOR ", "»« IF v instanceof String»"« - v as String»"« + v»"« ENDIF»« ENDFOR»); @@ -353,9 +491,12 @@ class ClassTemplate extends BaseTemplate { */ def protected generateStaticInicializationBlock() ''' static { + final «List.importedName»<«Pattern.importedName»> l = new «ArrayList.importedName»<«Pattern.importedName»>(); for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») { - «Constants.MEMBER_PATTERN_LIST».add(Pattern.compile(regEx)); + l.add(Pattern.compile(regEx)); } + + «Constants.MEMBER_PATTERN_LIST» = «ImmutableList.importedName».copyOf(l); } ''' @@ -366,23 +507,23 @@ class ClassTemplate extends BaseTemplate { */ def protected generateFields() ''' «IF restrictions != null» - «IF !(restrictions.lengthConstraints.empty)» - «val numberClass = restrictions.lengthConstraints.iterator.next.min.class» - private static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> _length; - «ENDIF» - «IF !(restrictions.rangeConstraints.empty)» - «val numberClass = restrictions.rangeConstraints.iterator.next.min.class» - private static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> _range; + «val prop = getPropByName("value")» + «IF prop != null» + «IF !(restrictions.lengthConstraints.empty)» + private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _length; + «ENDIF» + «IF !(restrictions.rangeConstraints.empty)» + private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _range; + «ENDIF» «ENDIF» «ENDIF» «IF !properties.empty» «FOR f : properties» - «IF f.readOnly»final«ENDIF» private «f.returnType.importedName» «f.fieldName»; + private«IF f.readOnly» final«ENDIF» «f.returnType.importedName» «f.fieldName»; «ENDFOR» «ENDIF» ''' - /** * Template method which generates the method hashCode(). * @@ -444,4 +585,13 @@ class ClassTemplate extends BaseTemplate { «ENDIF» ''' + def GeneratedProperty getPropByName(String name) { + for (GeneratedProperty prop : allProperties) { + if (prop.name.equals(name)) { + return prop; + } + } + return null; + } + }