Fixed bug in generation of leaf-list return types.
Fixed bug in decimal64 range parsing.
Added tests.
Change-Id: If46dbccfb0517b9d92d6bb48f219355e796f834e
Signed-off-by: Martin Vitez <mvitez@cisco.com>
nodeDesc = "";
}
if (nodeName !== null && !node.isAddedByUses()) {
- val TypeDefinition<?> type = node.type;
- val listType = Types.listTypeFor(typeProvider.javaTypeForSchemaDefinitionType(type, node));
+ val TypeDefinition<?> typeDef = node.type;\r
+ val parentModule = findParentModule(schemaContext, node);\r
+\r
+ var Type returnType = null;\r
+ if (typeDef instanceof EnumTypeDefinition) {\r
+ returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node);\r
+ val enumTypeDef = typeDef as EnumTypeDefinition;\r
+ val enumBuilder = resolveInnerEnumFromTypeDefinition(enumTypeDef, nodeName, typeBuilder);\r
+ returnType = new ReferencedTypeImpl(enumBuilder.packageName, enumBuilder.name);\r
+ (typeProvider as TypeProviderImpl).putReferencedType(node.path, returnType);\r
+ } else if (typeDef instanceof UnionType) {\r
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
+ returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
+ } else if (typeDef instanceof BitsTypeDefinition) {\r
+ val genTOBuilder = addTOToTypeBuilder(typeDef, typeBuilder, nodeName, node, parentModule);\r
+ returnType = new ReferencedTypeImpl(genTOBuilder.packageName, genTOBuilder.name);\r
+ } else {\r
+ val Restrictions restrictions = BindingGeneratorUtil.getRestrictions(typeDef);\r
+ returnType = typeProvider.javaTypeForSchemaDefinitionType(typeDef, node, restrictions);\r
+ }\r
+
+ val listType = Types.listTypeFor(returnType);
constructGetter(typeBuilder, nodeName, nodeDesc, listType);
return true;
}
* @return generated TO builder for <code>typeDef</code>\r
*/
private def GeneratedTOBuilder addTOToTypeBuilder(TypeDefinition<?> typeDef, GeneratedTypeBuilder typeBuilder,
- String leafName, LeafSchemaNode leaf, Module parentModule) {
+ String leafName, DataSchemaNode leaf, Module parentModule) {
val classNameFromLeaf = parseToClassName(leafName);
val List<GeneratedTOBuilder> genTOBuilders = new ArrayList();
val packageName = typeBuilder.fullyQualifiedName;
import org.opendaylight.yangtools.yang.model.api.Module;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
+import org.opendaylight.yangtools.yang.model.api.type.DecimalTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.IntegerTypeDefinition;
import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;
import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
range.addAll(((IntegerTypeDefinition)base).getRangeConstraints());
} else if (base instanceof UnsignedIntegerTypeDefinition && range.isEmpty()) {
range.addAll(((UnsignedIntegerTypeDefinition)base).getRangeConstraints());
+ } else if (base instanceof DecimalTypeDefinition && range.isEmpty()) {
+ range.addAll(((DecimalTypeDefinition)base).getRangeConstraints());
}
}
}
}
if (!isValidRange) {
- throw new IllegalArgumentException("illegal length");
+ throw new IllegalArgumentException("illegal range");
}
}
'''
«ENDIF»\r
'''\r
\r
+ def private generateGetRange() '''\r
+ «IF restrictions != null && !(restrictions.lengthConstraints.empty)»\r
+ public static «List.importedName»<«Range.importedName»<Integer>> getLength() {\r
+ final «List.importedName»<«Range.importedName»<Integer>> result = new «ArrayList.importedName»<>();\r
+ «List.importedName»<«Range.importedName»<«Integer.importedName»>> lengthConstraints = new «ArrayList.importedName»<>(); \r
+ «FOR r : restrictions.lengthConstraints»\r
+ result.add(«Range.importedName».closed(«r.min», «r.max»));\r
+ «ENDFOR»\r
+ return result;\r
+ }\r
+ «ENDIF»\r
+ '''\r
+\r
}\r
String pkg = BASE_PKG + ".urn.opendaylight.test.rev131008";
ClassLoader loader = new URLClassLoader(new URL[] { compiledOutputDir.toURI().toURL() });
Class<?> nodesClass = Class.forName(pkg + ".Nodes", true, loader);
+ Class<?> builderClass = Class.forName(pkg + ".NodesBuilder", true, loader);
// Test methods return type
byte[] b = new byte[] {};
assertContainsMethod(nodesClass, BigInteger.class, "getIdU64");
assertContainsMethod(nodesClass, pkg + ".Nodes$IdUnion", "getIdUnion", loader);
+ Object builderObj = builderClass.newInstance();
+
+ Method m = assertContainsMethod(builderClass, builderClass, "setIdBinary", b.getClass());
+ assertContainsRestrictionCheck(builderObj, m, "illegal length", new byte[] {});
+
+ m = assertContainsMethod(builderClass, builderClass, "setIdDecimal64", BigDecimal.class);
+ assertContainsRestrictionCheck(builderObj, m, "illegal range", new BigDecimal("1.4"));
+
cleanUp(sourcesOutputDir, compiledOutputDir);
}
import java.io.FileNotFoundException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
}
/**
- * Asserts that class containes hashCode, equals and toString methods.
+ * Asserts that class contains hashCode, equals and toString methods.
*
* @param clazz
* class to test
assertContainsMethod(clazz, String.class, "toString");
}
+ /**
+ * Asserts that constructor contains check for illegal argument.
+ *
+ * @param constructor
+ * constructor to invoke
+ * @param errorMsg
+ * expected error message
+ * @param args
+ * constructor arguments
+ * @throws Exception
+ */
+ static void assertContainsRestrictionCheck(Constructor<?> constructor, String errorMsg, Object... args)
+ throws Exception {
+ try {
+ constructor.newInstance(args);
+ fail("constructor invocation should fail");
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ assertTrue(cause instanceof IllegalArgumentException);
+ assertEquals(errorMsg, cause.getMessage());
+ }
+ }
+
+ /**
+ * Asserts that method contains check for illegal argument.
+ *
+ * @param obj
+ * object to test (can be null, if method is static)
+ * @param method
+ * method to invoke
+ * @param errorMsg
+ * expected error message
+ * @param args
+ * constructor arguments
+ * @throws Exception
+ */
+ static void assertContainsRestrictionCheck(Object obj, Method method, String errorMsg, Object... args)
+ throws Exception {
+ try {
+ method.invoke(obj, args);
+ fail("method invocation should fail");
+ } catch (InvocationTargetException e) {
+ Throwable cause = e.getCause();
+ assertTrue(cause instanceof IllegalArgumentException);
+ assertEquals(errorMsg, cause.getMessage());
+ }
+ }
+
/**
* Asserts that class contains 'public static
* java.util.List<com.google.common.collect.Range<java.lang.Integer>>
defInst = assertContainsMethod(int32Ext1Class, int32Ext1Class, "getDefaultInstance", String.class);
assertEquals(5, int32Ext1Class.getDeclaredMethods().length);
+ assertContainsRestrictionCheck(expectedConstructor, "illegal range", new Integer("1"));
obj = expectedConstructor.newInstance(new Integer("159"));
assertEquals(obj, defInst.invoke(null, "159"));
defInst = assertContainsMethod(int32Ext2Class, int32Ext2Class, "getDefaultInstance", String.class);
assertEquals(2, int32Ext2Class.getDeclaredMethods().length);
- obj = expectedConstructor.newInstance(new Integer("159"));
- assertEquals(obj, defInst.invoke(null, "159"));
+ assertContainsRestrictionCheck(expectedConstructor, "illegal range", new Integer("10"));
+ obj = expectedConstructor.newInstance(new Integer("2147483647"));
+ assertEquals(obj, defInst.invoke(null, "2147483647"));
// typedef string-ext1
assertFalse(stringExt1Class.isInterface());
assertContainsGetLength(stringExt1Class);
assertEquals(6, stringExt1Class.getDeclaredMethods().length);
+ assertContainsRestrictionCheck(expectedConstructor, "illegal length", "abcd");
obj = expectedConstructor.newInstance("hello world");
assertEquals(obj, defInst.invoke(null, "hello world"));
defInst = assertContainsMethod(stringExt2Class, stringExt2Class, "getDefaultInstance", String.class);
assertEquals(2, stringExt2Class.getDeclaredMethods().length);
+ assertContainsRestrictionCheck(expectedConstructor, "illegal length", "abcde");
obj = expectedConstructor.newInstance("helloWorld");
assertEquals(obj, defInst.invoke(null, "helloWorld"));
defInst = assertContainsMethod(myDecimalTypeClass, myDecimalTypeClass, "getDefaultInstance", String.class);
assertEquals(5, myDecimalTypeClass.getDeclaredMethods().length);
+ assertContainsRestrictionCheck(expectedConstructor, "illegal range", new BigDecimal("1.4"));
obj = expectedConstructor.newInstance(new BigDecimal("3.14"));
assertEquals(obj, defInst.invoke(null, "3.14"));
assertEquals(5, unionExt4Class.getDeclaredConstructors().length);
assertContainsDefaultMethods(unionExt4Class);
- //cleanUp(sourcesOutputDir, compiledOutputDir);
+ cleanUp(sourcesOutputDir, compiledOutputDir);
}
}
container nodes {
leaf id-binary {
- type binary;
+ type binary {
+ length 1..10;
+ }
}
leaf id-bits {
type bits {
leaf id-decimal64 {
type decimal64 {
fraction-digits 4;
+ range "1.5..5.5";
}
}
leaf id-empty {
typedef my-decimal-type {
type decimal64 {
fraction-digits 6;
+ range "1.5..5.5";
}
}
\r
import java.math.BigDecimal;\r
import java.math.BigInteger;\r
+import java.util.Collections;\r
import java.util.HashMap;\r
+import java.util.List;\r
import java.util.Map;\r
\r
import org.opendaylight.yangtools.binding.generator.util.Types;\r
import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;\r
import org.opendaylight.yangtools.yang.model.api.SchemaNode;\r
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;\r
+import org.opendaylight.yangtools.yang.model.api.type.LengthConstraint;\r
+import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;\r
+import org.opendaylight.yangtools.yang.model.api.type.RangeConstraint;\r
+import org.opendaylight.yangtools.yang.model.util.BaseConstraints;\r
\r
public final class BaseYangTypes {\r
/**\r
*/\r
public static final Type EMPTY_TYPE = Types.typeForClass(Boolean.class);\r
\r
+ public static final Type ENUM_TYPE = Types.typeForClass(Enum.class);\r
+\r
/**\r
* <code>Type</code> representation of <code>int8</code> YANG type\r
*/\r
/**\r
* <code>Type</code> representation of <code>uint8</code> YANG type\r
*/\r
- public static final Type UINT8_TYPE = Types.typeForClass(Short.class);\r
+ public static final Type UINT8_TYPE = Types.typeForClass(Short.class, singleRangeRestrictions(0, 255));\r
\r
/**\r
* <code>Type</code> representation of <code>uint16</code> YANG type\r
*/\r
- public static final Type UINT16_TYPE = Types.typeForClass(Integer.class);\r
+ public static final Type UINT16_TYPE = Types.typeForClass(Integer.class, singleRangeRestrictions(0, 65535));\r
\r
/**\r
* <code>Type</code> representation of <code>uint32</code> YANG type\r
*/\r
- public static final Type UINT32_TYPE = Types.typeForClass(Long.class);\r
+ public static final Type UINT32_TYPE = Types.typeForClass(Long.class, singleRangeRestrictions(0, 4294967295L));\r
\r
/**\r
* <code>Type</code> representation of <code>uint64</code> YANG type\r
*/\r
- public static final Type UINT64_TYPE = Types.typeForClass(BigInteger.class);\r
+ public static final Type UINT64_TYPE = Types.typeForClass(BigInteger.class,\r
+ singleRangeRestrictions(0, new BigInteger("18446744073709551615")));\r
\r
/**\r
* <code>Type</code> representation of <code>binary</code> YANG type\r
static {\r
typeMap.put("boolean", BOOLEAN_TYPE);\r
typeMap.put("empty", EMPTY_TYPE);\r
+ typeMap.put("enumeration", ENUM_TYPE);\r
typeMap.put("int8", INT8_TYPE);\r
typeMap.put("int16", INT16_TYPE);\r
typeMap.put("int32", INT32_TYPE);\r
typeMap.put("uint32", UINT32_TYPE);\r
typeMap.put("uint64", UINT64_TYPE);\r
typeMap.put("binary", BINARY_TYPE);\r
- typeMap.put("instance-identifier", INSTANCE_IDENTIFIER );\r
+ typeMap.put("instance-identifier", INSTANCE_IDENTIFIER);\r
}\r
\r
public static final TypeProvider BASE_YANG_TYPES_PROVIDER = new TypeProvider() {\r
}\r
\r
@Override\r
- public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode, Restrictions restrictions) {\r
+ public Type javaTypeForSchemaDefinitionType(TypeDefinition<?> type, SchemaNode parentNode,\r
+ Restrictions restrictions) {\r
String typeName = type.getQName().getLocalName();\r
switch (typeName) {\r
- case "binary" : return Types.primitiveType("byte[]", restrictions);\r
- case "decimal64": return Types.typeForClass(BigDecimal.class, restrictions);\r
- case "enumeration": return Types.typeForClass(Enum.class, restrictions);\r
- case "int8": return Types.typeForClass(Byte.class, restrictions);\r
- case "int16": return Types.typeForClass(Short.class, restrictions);\r
- case "int32": return Types.typeForClass(Integer.class, restrictions);\r
- case "int64": return Types.typeForClass(Long.class, restrictions);\r
- case "string": return Types.typeForClass(String.class, restrictions);\r
- case "uint8": return Types.typeForClass(Short.class, restrictions);\r
- case "uint16": Types.typeForClass(Integer.class, restrictions);\r
- case "uint32": Types.typeForClass(Long.class, restrictions);\r
- case "uint64": Types.typeForClass(BigInteger.class, restrictions);\r
- default: return javaTypeForSchemaDefinitionType(type, parentNode);\r
+ case "binary":\r
+ return Types.primitiveType("byte[]", restrictions);\r
+ case "decimal64":\r
+ return Types.typeForClass(BigDecimal.class, restrictions);\r
+ case "enumeration":\r
+ return Types.typeForClass(Enum.class, restrictions);\r
+ case "int8":\r
+ return Types.typeForClass(Byte.class, restrictions);\r
+ case "int16":\r
+ return Types.typeForClass(Short.class, restrictions);\r
+ case "int32":\r
+ return Types.typeForClass(Integer.class, restrictions);\r
+ case "int64":\r
+ return Types.typeForClass(Long.class, restrictions);\r
+ case "string":\r
+ return Types.typeForClass(String.class, restrictions);\r
+ case "uint8":\r
+ return Types.typeForClass(Short.class, restrictions);\r
+ case "uint16":\r
+ return Types.typeForClass(Integer.class, restrictions);\r
+ case "uint32":\r
+ return Types.typeForClass(Long.class, restrictions);\r
+ case "uint64":\r
+ return Types.typeForClass(BigInteger.class, restrictions);\r
+ default:\r
+ return javaTypeForSchemaDefinitionType(type, parentNode);\r
}\r
}\r
\r
return null;\r
}\r
};\r
+\r
+ private static Restrictions singleRangeRestrictions(final Number min, final Number max) {\r
+ return new Restrictions() {\r
+ @Override\r
+ public boolean isEmpty() {\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public List<RangeConstraint> getRangeConstraints() {\r
+ return Collections.singletonList(BaseConstraints.rangeConstraint(min, max, null, null));\r
+ }\r
+\r
+ @Override\r
+ public List<PatternConstraint> getPatternConstraints() {\r
+ return Collections.emptyList();\r
+ }\r
+\r
+ @Override\r
+ public List<LengthConstraint> getLengthConstraints() {\r
+ return Collections.emptyList();\r
+ }\r
+ };\r
+ }\r
+\r
}\r
* @throws IllegalArgumentException
* <ul>
* <li>if <code>typeDefinition</code> equal null</li>
- * <li>if Q name of <code>typeDefinition</code> equal null</li>
+ * <li>if Qname of <code>typeDefinition</code> equal null</li>
* <li>if name of <code>typeDefinition</code> equal null</li>
* </ul>
*/
} else {
returnType = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
if (returnType == null) {
- returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition,
- parentNode, r);
+ returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(typeDefinition.getQName()
+ .getLocalName());
}
}
// TODO: add throw exception when we will be able to resolve ALL yang
*/
package org.opendaylight.yangtools.yang.parser.util;
+import java.math.BigDecimal;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
List<RangeConstraint> rangeConstraints = Collections.emptyList();
outer: for (int i = 0; i < ctx.getChildCount(); i++) {
ParseTree numRestrChild = ctx.getChild(i);
+
if (numRestrChild instanceof Numerical_restrictionsContext) {
for (int j = 0; j < numRestrChild.getChildCount(); j++) {
ParseTree rangeChild = numRestrChild.getChild(j);
}
}
}
+
+ if (numRestrChild instanceof Decimal64_specificationContext) {
+ for (int j = 0; j < numRestrChild.getChildCount(); j++) {
+ ParseTree decRestr = numRestrChild.getChild(j);
+ if (decRestr instanceof Numerical_restrictionsContext) {
+ for (int k = 0; k < decRestr.getChildCount(); k++) {
+ ParseTree rangeChild = decRestr.getChild(k);
+ if (rangeChild instanceof Range_stmtContext) {
+ rangeConstraints = parseRangeConstraints((Range_stmtContext) rangeChild, moduleName);
+ break outer;
+ }
+ }
+
+ }
+ }
+ }
}
return rangeConstraints;
}
result = new UnknownBoundaryNumber(value);
} else {
try {
- result = Long.valueOf(value);
+ if (value.contains(".")) {
+ result = new BigDecimal(value);
+ } else {
+ result = Long.valueOf(value);
+ }
} catch (NumberFormatException e) {
throw new YangParseException(moduleName, line, "Unable to parse range value '" + value + "'.", e);
}