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.DECIMAL64_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 static extension org.opendaylight.mdsal.binding.model.ri.BindingTypes.isBitsType
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.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
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<GeneratedProperty> PROP_COMPARATOR = Comparator.comparing([prop | prop.name])
+ static val VALUEOF_TYPES = Set.of(
+ BOOLEAN_TYPE,
+ DECIMAL64_TYPE,
+ INT8_TYPE,
+ INT16_TYPE,
+ INT32_TYPE,
+ INT64_TYPE,
+ UINT8_TYPE,
+ UINT16_TYPE,
+ UINT32_TYPE,
+ UINT64_TYPE)
protected val List<GeneratedProperty> properties
protected val List<GeneratedProperty> finalProperties
protected val List<GeneratedProperty> parentProperties
- protected val Iterable<GeneratedProperty> allProperties
+ protected val List<GeneratedProperty> allProperties
protected val Restrictions restrictions
/**
this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
this.restrictions = genType.restrictions
- var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();
+ 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
}
* @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»
«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)»
«defaultInstance»
- «FOR field : properties SEPARATOR "\n"»
- «field.getterMethod»
- «IF !field.readOnly»
- «field.setterMethod»
- «ENDIF»
- «ENDFOR»
+ «propertyMethods»
- «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
+ «IF genTO.isBitsType»
«generateGetValueForBitsTypeDef»
«ENDIF»
'''
+ 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 <code>getValue()</code> for typedef,
* which base type is BitsDefinition.
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»
«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")»
- «CodeHelpers.importedName».requireValue(_value);
- «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() '''
«genConstructor(p, other)»
«ENDIF»
«ENDFOR»
-
'''
- def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''
+ def protected genConstructor(GeneratedProperty property, Iterable<GeneratedProperty> 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»
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»
'''
}
}
- 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»
* @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»
}
'''
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»
);
'''
«FOR c : consts»
«IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
«val cValue = c.value as Map<String, String>»
- public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
+ «val jurPatternRef = JUR_PATTERN.importedName»
+ public static final «JU_LIST.importedName»<String> «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»
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»
}
'''
*
* @return string with the <code>equals()</code> 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»)) {
«ENDIF»
'''
+ def private generateToString(Collection<? extends GeneratedProperty> 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
}
-
}