X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?a=blobdiff_plain;f=binding%2Fmdsal-binding-java-api-generator%2Fsrc%2Fmain%2Fjava%2Forg%2Fopendaylight%2Fmdsal%2Fbinding%2Fjava%2Fapi%2Fgenerator%2FClassTemplate.xtend;h=23be8b693a9bb8937973bbce2d164fbfdcb5bac3;hb=c7047214f75719494b9707d855cc5fd079f205aa;hp=24f2972c625635ec1a53b900295f63cbd4821eeb;hpb=e4c2cc63642bc697402ef850b87506bf536c6d28;p=mdsal.git diff --git a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend index 24f2972c62..23be8b693a 100644 --- a/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend +++ b/binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend @@ -8,22 +8,38 @@ package org.opendaylight.mdsal.binding.java.api.generator import static java.util.Objects.requireNonNull -import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN; -import static org.opendaylight.mdsal.binding.model.util.Types.BYTE_ARRAY; -import static org.opendaylight.mdsal.binding.model.util.Types.STRING; +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BINARY_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.BOOLEAN_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.EMPTY_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.INSTANCE_IDENTIFIER +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.INT16_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.INT32_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.INT64_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.INT8_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.STRING_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT16_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT32_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT64_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BaseYangTypes.UINT8_TYPE +import static org.opendaylight.mdsal.binding.model.ri.BindingTypes.SCALAR_TYPE_OBJECT +import static org.opendaylight.mdsal.binding.model.ri.Types.BOOLEAN +import static org.opendaylight.mdsal.binding.model.ri.Types.STRING; import static extension org.apache.commons.text.StringEscapeUtils.escapeJava import com.google.common.base.Preconditions import com.google.common.collect.ImmutableList import com.google.common.collect.Lists +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings import java.beans.ConstructorProperties import java.util.ArrayList import java.util.Base64; -import java.util.Collections +import java.util.Collection +import java.util.Comparator import java.util.List import java.util.Map -import java.util.Objects -import java.util.regex.Pattern +import java.util.Set +import javax.management.ConstructorParameters +import org.gaul.modernizer_maven_annotations.SuppressModernizer import org.opendaylight.mdsal.binding.model.api.ConcreteType import org.opendaylight.mdsal.binding.model.api.Constant import org.opendaylight.mdsal.binding.model.api.Enumeration @@ -31,20 +47,32 @@ import org.opendaylight.mdsal.binding.model.api.GeneratedProperty import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject import org.opendaylight.mdsal.binding.model.api.Restrictions import org.opendaylight.mdsal.binding.model.api.Type -import org.opendaylight.mdsal.binding.model.util.TypeConstants -import org.opendaylight.yangtools.yang.binding.CodeHelpers +import org.opendaylight.mdsal.binding.model.ri.TypeConstants +import org.opendaylight.mdsal.binding.spec.naming.BindingMapping import org.opendaylight.yangtools.yang.common.Empty import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition /** * Template for generating JAVA class. */ +@SuppressModernizer class ClassTemplate extends BaseTemplate { + static val Comparator PROP_COMPARATOR = Comparator.comparing([prop | prop.name]) + static val VALUEOF_TYPES = Set.of( + BOOLEAN_TYPE, + INT8_TYPE, + INT16_TYPE, + INT32_TYPE, + INT64_TYPE, + UINT8_TYPE, + UINT16_TYPE, + UINT32_TYPE, + UINT64_TYPE) protected val List properties protected val List finalProperties protected val List parentProperties - protected val Iterable allProperties + protected val List allProperties protected val Restrictions restrictions /** @@ -83,19 +111,17 @@ class ClassTemplate extends BaseTemplate { this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO) this.restrictions = genType.restrictions - var List sorted = new ArrayList(); + val sorted = new ArrayList(); sorted.addAll(properties); sorted.addAll(parentProperties); - Collections.sort(sorted, [p1, p2| - p1.name.compareTo(p2.name) - ]); + sorted.sort(PROP_COMPARATOR); this.allProperties = sorted this.enums = genType.enumerations this.consts = genType.constantDefinitions if (restrictions !== null && restrictions.rangeConstraint.present) { - rangeGenerator = requireNonNull(AbstractRangeGenerator.forType(findProperty(genType, "value").returnType)) + rangeGenerator = requireNonNull(AbstractRangeGenerator.forType(TypeUtils.encapsulatedValueType(genType))) } else { rangeGenerator = null } @@ -121,8 +147,11 @@ class ClassTemplate extends BaseTemplate { * @return string with class source code in JAVA format */ def protected generateBody(boolean isInnerClass) ''' - «wrapToDocumentation(formatDataForJavaDoc(type))» + «type.formatDataForJavaDoc.wrapToDocumentation» «annotationDeclaration» + «IF !isInnerClass» + «generatedAnnotation» + «ENDIF» «generateClassDeclaration(isInnerClass)» { «suidDeclaration» «innerClassesDeclarations» @@ -132,7 +161,8 @@ class ClassTemplate extends BaseTemplate { «IF restrictions !== null» «IF restrictions.lengthConstraint.present» - «LengthGenerator.generateLengthChecker("_value", findProperty(genTO, "value").returnType, restrictions.lengthConstraint.get, this)» + «LengthGenerator.generateLengthChecker("_value", TypeUtils.encapsulatedValueType(genTO), + restrictions.lengthConstraint.get, this)» «ENDIF» «IF restrictions.rangeConstraint.present» «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraint.get, this)» @@ -143,12 +173,7 @@ class ClassTemplate extends BaseTemplate { «defaultInstance» - «FOR field : properties SEPARATOR "\n"» - «field.getterMethod» - «IF !field.readOnly» - «field.setterMethod» - «ENDIF» - «ENDFOR» + «propertyMethods» «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)» «generateGetValueForBitsTypeDef» @@ -163,6 +188,38 @@ class ClassTemplate extends BaseTemplate { ''' + def private propertyMethods() { + if (properties.empty) { + return "" + } + isScalarTypeObject ? scalarTypeObjectValue(properties.get(0)) : defaultProperties + } + + def private isScalarTypeObject() { + for (impl : genTO.implements) { + if (SCALAR_TYPE_OBJECT.identifier.equals(impl.identifier)) { + return true + } + } + return false + } + + def private defaultProperties() ''' + «FOR field : properties SEPARATOR "\n"» + «field.getterMethod» + «IF !field.readOnly» + «field.setterMethod» + «ENDIF» + «ENDFOR» + ''' + + def private scalarTypeObjectValue(GeneratedProperty field) ''' + @«OVERRIDE.importedName» + public «field.returnType.importedName» «BindingMapping.SCALAR_TYPE_OBJECT_GET_VALUE_NAME»() { + return «field.fieldName»«field.cloneCall»; + } + ''' + /** * Template method which generates the method getValue() for typedef, * which base type is BitsDefinition. @@ -196,9 +253,12 @@ class ClassTemplate extends BaseTemplate { def protected constructors() ''' «IF genTO.unionType» «genUnionConstructor» + «ELSEIF genTO.typedef && allProperties.size == 1 && allProperties.get(0).name.equals(TypeConstants.VALUE_PROP)» + «typedefConstructor» «ELSE» «allValuesConstructor» «ENDIF» + «IF !allProperties.empty» «copyConstructor» «ENDIF» @@ -207,41 +267,48 @@ class ClassTemplate extends BaseTemplate { «ENDIF» ''' - def protected allValuesConstructor() ''' - «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")» - @«ConstructorProperties.importedName»("value") - «ENDIF» + def allValuesConstructor() ''' public «type.name»(«allProperties.asArgumentsDeclaration») { - «IF false == parentProperties.empty» + «IF !parentProperties.empty» super(«parentProperties.asArguments»); «ENDIF» «FOR p : allProperties» - «generateRestrictions(type, p.fieldName.toString, p.returnType)» + «generateRestrictions(type, p.fieldName, p.returnType)» «ENDFOR» - «/* - * 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")» - «Objects.importedName».requireNonNull(_value, "Supplied value may not be null"); - «genPatternEnforcer("_value")» - «ENDIF» - «FOR p : properties» - «IF p.returnType.importedName.contains("[]")» - «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name - .equals("value")» - this.«p.fieldName» = «p.fieldName».clone(); - «ELSE» - this.«p.fieldName» = «p.fieldName» == null ? null : «p.fieldName».clone(); - «ENDIF» + «val fieldName = p.fieldName» + «IF p.returnType.name.endsWith("[]")» + this.«fieldName» = «fieldName» == null ? null : «fieldName».clone(); «ELSE» - this.«p.fieldName» = «p.fieldName»; + this.«fieldName» = «fieldName»; «ENDIF» «ENDFOR» } + ''' + def private typedefConstructor() ''' + @«ConstructorParameters.importedName»("«TypeConstants.VALUE_PROP»") + @«ConstructorProperties.importedName»("«TypeConstants.VALUE_PROP»") + public «type.name»(«allProperties.asArgumentsDeclaration») { + «IF !parentProperties.empty» + super(«parentProperties.asArguments»); + «ENDIF» + «FOR p : allProperties» + «generateRestrictions(type, p.fieldName, p.returnType)» + «ENDFOR» + «/* + * If we have patterns, we need to apply them to the value field. This is a sad consequence of how this code is + * structured. + */» + «CODEHELPERS.importedName».requireValue(_value); + «genPatternEnforcer("_value")» + + «FOR p : properties» + «val fieldName = p.fieldName» + this.«fieldName» = «fieldName»«p.cloneCall»; + «ENDFOR» + } ''' def protected genUnionConstructor() ''' @@ -251,18 +318,18 @@ class ClassTemplate extends BaseTemplate { «genConstructor(p, other)» «ENDIF» «ENDFOR» - ''' - def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) ''' + def protected genConstructor(GeneratedProperty property, Iterable other) ''' public «type.name»(«property.returnType.importedName + " " + property.name») { - «IF false == parentProperties.empty» + «IF !parentProperties.empty» super(«parentProperties.asArguments»); «ENDIF» - «generateRestrictions(type, property.fieldName.toString, property.returnType)» + «val fieldName = property.fieldName» + «generateRestrictions(type, fieldName, property.returnType)» - this.«property.fieldName» = «property.name»; + this.«fieldName» = «property.name»; «FOR p : other» this.«p.fieldName» = null; «ENDFOR» @@ -272,7 +339,7 @@ class ClassTemplate extends BaseTemplate { def private genPatternEnforcer(String ref) ''' «FOR c : consts» «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME» - «CodeHelpers.importedName».checkPattern(«ref», «Constants.MEMBER_PATTERN_LIST», «Constants.MEMBER_REGEX_LIST»); + «CODEHELPERS.importedName».checkPattern(«ref», «Constants.MEMBER_PATTERN_LIST», «Constants.MEMBER_REGEX_LIST»); «ENDIF» «ENDFOR» ''' @@ -285,7 +352,7 @@ class ClassTemplate extends BaseTemplate { } } - def private generateRestrictions(Type type, String paramName, Type returnType) ''' + def generateRestrictions(Type type, String paramName, Type returnType) ''' «val restrictions = type.restrictions» «IF restrictions !== null» «IF restrictions.lengthConstraint.present || restrictions.rangeConstraint.present» @@ -308,11 +375,12 @@ class ClassTemplate extends BaseTemplate { * @param source Source object */ public «type.name»(«type.name» source) { - «IF false == parentProperties.empty» + «IF !parentProperties.empty» super(source); «ENDIF» «FOR p : properties» - this.«p.fieldName» = source.«p.fieldName»; + «val fieldName = p.fieldName» + this.«fieldName» = source.«fieldName»; «ENDFOR» } ''' @@ -332,44 +400,38 @@ class ClassTemplate extends BaseTemplate { def protected defaultInstance() ''' «IF genTO.typedef && !allProperties.empty && !genTO.unionType» «val prop = allProperties.get(0)» - «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))» - public static «genTO.name» getDefaultInstance(String defaultValue) { - «IF BYTE_ARRAY.equals(prop.returnType)» - return new «genTO.name»(«Base64.importedName».getDecoder().decode(defaultValue)); - «ELSEIF STRING.equals(prop.returnType)» + «val propType = prop.returnType» + «IF !(INSTANCE_IDENTIFIER.identifier.equals(propType.identifier))» + public static «genTO.name» getDefaultInstance(final String defaultValue) { + «IF allProperties.size > 1» + «bitsArgs» + «ELSEIF VALUEOF_TYPES.contains(propType)» + return new «genTO.name»(«propType.importedName».valueOf(defaultValue)); + «ELSEIF STRING_TYPE.equals(propType)» return new «genTO.name»(defaultValue); - «ELSEIF Constants.EMPTY.equals(prop.returnType)» + «ELSEIF BINARY_TYPE.equals(propType)» + return new «genTO.name»(«Base64.importedName».getDecoder().decode(defaultValue)); + «ELSEIF EMPTY_TYPE.equals(propType)» «Preconditions.importedName».checkArgument(defaultValue.isEmpty(), "Invalid value %s", defaultValue); - return new «genTO.name»(«Empty.importedName».getInstance()); - «ELSEIF allProperties.size > 1» - «bitsArgs» - «ELSEIF BOOLEAN.equals(prop.returnType)» - return new «genTO.name»(«Boolean.importedName».valueOf(defaultValue)); - «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)» - return new «genTO.name»(«Byte.importedName».valueOf(defaultValue)); - «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)» - return new «genTO.name»(«Short.importedName».valueOf(defaultValue)); - «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)» - return new «genTO.name»(«Integer.importedName».valueOf(defaultValue)); - «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)» - return new «genTO.name»(«Long.importedName».valueOf(defaultValue)); + return new «genTO.name»(«Empty.importedName».value()); «ELSE» - return new «genTO.name»(new «prop.returnType.importedName»(defaultValue)); + return new «genTO.name»(new «propType.importedName»(defaultValue)); «ENDIF» } «ENDIF» «ENDIF» ''' + @SuppressFBWarnings(value = "DLS_DEAD_LOCAL_STORE", justification = "FOR with SEPARATOR, not needing for value") def protected bitsArgs() ''' - «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»); + «JU_LIST.importedName»<«STRING.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»); if (!properties.contains(defaultValue)) { throw new «IllegalArgumentException.importedName»("invalid default parameter"); } int i = 0; return new «genTO.name»( «FOR prop : allProperties SEPARATOR ","» - properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null + properties.get(i++).equals(defaultValue) ? «BOOLEAN.importedName».TRUE : null «ENDFOR» ); ''' @@ -443,13 +505,14 @@ class ClassTemplate extends BaseTemplate { «FOR c : consts» «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME» «val cValue = c.value as Map» - public static final «List.importedName» «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(« + «val jurPatternRef = JUR_PATTERN.importedName» + public static final «JU_LIST.importedName» «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(« FOR v : cValue.keySet SEPARATOR ", "»"«v.escapeJava»"«ENDFOR»); «IF cValue.size == 1» - private static final «Pattern.importedName» «Constants.MEMBER_PATTERN_LIST» = «Pattern.importedName».compile(«TypeConstants.PATTERN_CONSTANT_NAME».get(0)); - private static final String «Constants.MEMBER_REGEX_LIST» = "«cValue.values.get(0).escapeJava»"; + private static final «jurPatternRef» «Constants.MEMBER_PATTERN_LIST» = «jurPatternRef».compile(«TypeConstants.PATTERN_CONSTANT_NAME».get(0)); + private static final String «Constants.MEMBER_REGEX_LIST» = "«cValue.values.iterator.next.escapeJava»"; «ELSE» - private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST» = «CodeHelpers.importedName».compilePatterns(«TypeConstants.PATTERN_CONSTANT_NAME»); + private static final «jurPatternRef»[] «Constants.MEMBER_PATTERN_LIST» = «CODEHELPERS.importedName».compilePatterns(«TypeConstants.PATTERN_CONSTANT_NAME»); private static final String[] «Constants.MEMBER_REGEX_LIST» = { « FOR v : cValue.values SEPARATOR ", "»"«v.escapeJava»"«ENDFOR» }; «ENDIF» @@ -488,13 +551,17 @@ class ClassTemplate extends BaseTemplate { return "" } return ''' - @«Override.importedName» + @«OVERRIDE.importedName» public int hashCode() { «IF size != 1» - «hashCodeResult(genTO.hashCodeIdentifiers)» + final int prime = 31; + int result = 1; + «FOR property : genTO.hashCodeIdentifiers» + result = prime * result + «property.importedUtilClass».hashCode(«property.fieldName»); + «ENDFOR» return result; «ELSE» - return «CodeHelpers.importedName».wrapperHashCode(«genTO.hashCodeIdentifiers.get(0).fieldName»); + return «CODEHELPERS.importedName».wrapperHashCode(«genTO.hashCodeIdentifiers.get(0).fieldName»); «ENDIF» } ''' @@ -505,20 +572,17 @@ class ClassTemplate extends BaseTemplate { * * @return string with the equals() method definition in JAVA format */ - def protected generateEquals() ''' + def private generateEquals() ''' «IF !genTO.equalsIdentifiers.empty» - @«Override.importedName» - public boolean equals(java.lang.Object obj) { + @«OVERRIDE.importedName» + public final boolean equals(java.lang.Object obj) { if (this == obj) { return true; } - if (obj == null) { + if (!(obj instanceof «type.name»)) { return false; } - if (getClass() != obj.getClass()) { - return false; - } - «type.name» other = («type.name») obj; + final «type.name» other = («type.name») obj; «FOR property : genTO.equalsIdentifiers» «val fieldName = property.fieldName» if (!«property.importedUtilClass».equals(«fieldName», other.«fieldName»)) { @@ -530,13 +594,25 @@ class ClassTemplate extends BaseTemplate { «ENDIF» ''' + def private generateToString(Collection properties) ''' + «IF !properties.empty» + @«OVERRIDE.importedName» + public «STRING.importedName» toString() { + final var helper = «MOREOBJECTS.importedName».toStringHelper(«type.importedName».class); + «FOR property : properties» + «CODEHELPERS.importedName».appendValue(helper, "«property.fieldName»", «property.fieldName»); + «ENDFOR» + return helper.toString(); + } + «ENDIF» + ''' + def GeneratedProperty getPropByName(String name) { for (GeneratedProperty prop : allProperties) { if (prop.name.equals(name)) { return prop; } } - return null; + return null } - }