Migrate getDataChildByName() users
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / yang / types / AbstractTypeProvider.java
index fa3457fbd544d6800bf75f3c2e7acf3516d40a2e..3d092c7b6e07860226f47f64c8114b6f00c8ac04 100644 (file)
@@ -8,16 +8,17 @@
 package org.opendaylight.mdsal.binding.yang.types;
 
 import static java.util.Objects.requireNonNull;
-import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.TYPE_OBJECT;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataTreeSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
 import com.google.common.annotations.Beta;
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Strings;
 import com.google.common.collect.ImmutableMap;
 import java.math.BigDecimal;
-import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Base64;
 import java.util.Collection;
@@ -33,6 +34,7 @@ import java.util.Set;
 import java.util.TreeMap;
 import java.util.regex.Pattern;
 import org.opendaylight.mdsal.binding.generator.spi.TypeProvider;
+import org.opendaylight.mdsal.binding.generator.util.BaseYangTypesProvider;
 import org.opendaylight.mdsal.binding.model.api.AccessModifier;
 import org.opendaylight.mdsal.binding.model.api.ConcreteType;
 import org.opendaylight.mdsal.binding.model.api.Enumeration;
@@ -47,7 +49,9 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.mdsal.binding.model.util.BaseYangTypes;
 import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
+import org.opendaylight.mdsal.binding.model.util.BindingTypes;
 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
 import org.opendaylight.mdsal.binding.model.util.Types;
 import org.opendaylight.mdsal.binding.model.util.generated.type.builder.AbstractEnumerationBuilder;
@@ -55,13 +59,17 @@ import org.opendaylight.mdsal.binding.model.util.generated.type.builder.Generate
 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.Revision;
+import org.opendaylight.yangtools.yang.common.Uint16;
+import org.opendaylight.yangtools.yang.common.Uint32;
+import org.opendaylight.yangtools.yang.common.Uint64;
+import org.opendaylight.yangtools.yang.common.Uint8;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.IdentitySchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.Module;
-import org.opendaylight.yangtools.yang.model.api.RevisionAwareXPath;
+import org.opendaylight.yangtools.yang.model.api.PathExpression;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -81,7 +89,7 @@ import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
 import org.opendaylight.yangtools.yang.model.api.type.StringTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 import org.opendaylight.yangtools.yang.model.util.ModuleDependencySort;
-import org.opendaylight.yangtools.yang.model.util.RevisionAwareXPathImpl;
+import org.opendaylight.yangtools.yang.model.util.PathExpressionImpl;
 import org.opendaylight.yangtools.yang.model.util.SchemaContextUtil;
 import org.opendaylight.yangtools.yang.model.util.type.BaseTypes;
 import org.opendaylight.yangtools.yang.model.util.type.CompatUtils;
@@ -92,6 +100,7 @@ import org.slf4j.LoggerFactory;
 public abstract class AbstractTypeProvider implements TypeProvider {
     private static final Logger LOG = LoggerFactory.getLogger(AbstractTypeProvider.class);
     private static final Pattern GROUPS_PATTERN = Pattern.compile("\\[(.*?)\\]");
+    private static final JavaTypeName DEPRECATED_ANNOTATION = JavaTypeName.create(Deprecated.class);
 
     // Backwards compatibility: Union types used to be instantiated in YANG namespace, which is no longer
     // the case, as unions are emitted to their correct schema path.
@@ -150,8 +159,9 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     @Override
-    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
-        return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null);
+    public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
+            final boolean lenientRelativeLeafrefs) {
+        return javaTypeForSchemaDefinitionType(typeDefinition, parentNode, null, lenientRelativeLeafrefs);
     }
 
     /**
@@ -167,7 +177,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      */
     @Override
     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
-            final Restrictions restrictions) {
+            final Restrictions restrictions, final boolean lenientRelativeLeafrefs) {
         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
         Preconditions.checkArgument(typeDefinition.getQName() != null,
                 "Type Definition cannot have non specified QName (QName cannot be NULL!)");
@@ -180,15 +190,15 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             // and generated an enclosing ExtendedType to hold any range constraints. The new parser instantiates
             // a base type which holds these constraints.
             if (typeDefinition instanceof DecimalTypeDefinition) {
-                final Type ret = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(typeDefinition,
-                    parentNode, restrictions);
+                final Type ret = BaseYangTypesProvider.INSTANCE.javaTypeForSchemaDefinitionType(typeDefinition,
+                    parentNode, restrictions, lenientRelativeLeafrefs);
                 if (ret != null) {
                     return ret;
                 }
             }
 
             // Deal with leafrefs/identityrefs
-            Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
+            Type ret = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode, lenientRelativeLeafrefs);
             if (ret != null) {
                 return ret;
             }
@@ -202,7 +212,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             return ret;
         }
 
-        Type returnType = javaTypeForExtendedType(typeDefinition);
+        Type returnType = javaTypeForExtendedType(typeDefinition, lenientRelativeLeafrefs);
         if (restrictions != null && returnType instanceof GeneratedTransferObject) {
             final GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
             final Module module = findParentModule(schemaContext, parentNode);
@@ -218,6 +228,17 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         return returnType;
     }
 
+    public SchemaNode getTargetForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode) {
+        final PathExpression xpath = leafrefType.getPathStatement();
+        Preconditions.checkArgument(xpath != null, "The Path Statement for Leafref Type Definition cannot be NULL!");
+
+        final Module module = findParentModule(schemaContext, parentNode);
+        Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
+
+        return xpath.isAbsolute() ? findDataTreeSchemaNode(schemaContext, module.getQNameModule(), xpath)
+                : findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
+    }
+
     private GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto,
             final Restrictions restrictions) {
         final GeneratedTOBuilder gtob = newGeneratedTOBuilder(gto.getIdentifier());
@@ -239,45 +260,42 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     private boolean isLeafRefSelfReference(final LeafrefTypeDefinition leafref, final SchemaNode parentNode) {
-        final SchemaNode leafRefValueNode;
-        final RevisionAwareXPath leafRefXPath = leafref.getPathStatement();
-        final RevisionAwareXPath leafRefStrippedXPath = new RevisionAwareXPathImpl(
-            GROUPS_PATTERN.matcher(leafRefXPath.toString()).replaceAll(""), leafRefXPath.isAbsolute());
-
-        ///// skip leafrefs in augments - they're checked once augments are resolved
-        final Iterator<QName> iterator = parentNode.getPath().getPathFromRoot().iterator();
-        boolean isAugmenting = false;
+        /*
+         * First check if the leafref is an augment. If that is the case, skip it as it will be checked once augments
+         * are resolved.
+         */
         DataNodeContainer current = null;
         DataSchemaNode dataChildByName;
-
-        while (iterator.hasNext() && !isAugmenting) {
-            final QName next = iterator.next();
+        for (QName next : parentNode.getPath().getPathFromRoot()) {
             if (current == null) {
-                dataChildByName = schemaContext.getDataChildByName(next);
+                dataChildByName = schemaContext.dataChildByName(next);
             } else {
-                dataChildByName = current.getDataChildByName(next);
+                dataChildByName = current.dataChildByName(next);
             }
-            if (dataChildByName != null) {
-                isAugmenting = dataChildByName.isAugmenting();
-            } else {
+            if (dataChildByName == null) {
+                return false;
+            }
+            if (dataChildByName.isAugmenting()) {
                 return false;
             }
             if (dataChildByName instanceof DataNodeContainer) {
                 current = (DataNodeContainer) dataChildByName;
             }
         }
-        if (isAugmenting) {
-            return false;
-        }
-        /////
 
+        // Then try to look up the expression.
+        final PathExpression leafRefXPath = leafref.getPathStatement();
         final Module parentModule = getParentModule(parentNode);
-        if (!leafRefStrippedXPath.isAbsolute()) {
-            leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
-                    parentNode, leafRefStrippedXPath);
+        final SchemaNode leafRefValueNode;
+        if (leafRefXPath.isAbsolute()) {
+            leafRefValueNode = SchemaContextUtil.findDataTreeSchemaNode(schemaContext, parentModule.getQNameModule(),
+                leafRefXPath);
         } else {
-            leafRefValueNode = SchemaContextUtil.findDataSchemaNode(schemaContext, parentModule, leafRefStrippedXPath);
+            leafRefValueNode = SchemaContextUtil.findDataSchemaNodeForRelativeXPath(schemaContext, parentModule,
+                parentNode, new PathExpressionImpl(
+                    GROUPS_PATTERN.matcher(leafRefXPath.getOriginalString()).replaceAll(""), false));
         }
+
         return leafRefValueNode != null && leafRefValueNode.equals(parentNode);
     }
 
@@ -288,12 +306,13 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @param typeDefinition type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
+    private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
+            final boolean inGrouping) {
         if (typeDefinition instanceof LeafrefTypeDefinition) {
             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
             Preconditions.checkArgument(!isLeafRefSelfReference(leafref, parentNode),
                 "Leafref %s is referencing itself, incoming StackOverFlowError detected.", leafref);
-            return provideTypeForLeafref(leafref, parentNode);
+            return provideTypeForLeafref(leafref, parentNode, inGrouping);
         } else if (typeDefinition instanceof IdentityrefTypeDefinition) {
             return provideTypeForIdentityref((IdentityrefTypeDefinition) typeDefinition);
         }
@@ -307,10 +326,10 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @param typeDefinition type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
+    private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition, final boolean lenient) {
         final String typedefName = typeDefinition.getQName().getLocalName();
         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
-        Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
+        Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition, lenient);
         if (returnType == null) {
             if (baseTypeDef instanceof EnumTypeDefinition) {
                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
@@ -326,8 +345,8 @@ public abstract class AbstractTypeProvider implements TypeProvider {
                         returnType = genTOs.get(typedefName);
                     }
                     if (returnType == null) {
-                        returnType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
-                                baseTypeDef, typeDefinition, r);
+                        returnType = BaseYangTypesProvider.INSTANCE.javaTypeForSchemaDefinitionType(baseTypeDef,
+                            typeDefinition, r, lenient);
                     }
                 }
             }
@@ -347,7 +366,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @return JAVA <code>Type</code> of the identity which is referenced through <code>idref</code>
      */
     private Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref) {
-        final Collection<IdentitySchemaNode> identities = idref.getIdentities();
+        final Collection<? extends IdentitySchemaNode> identities = idref.getIdentities();
         if (identities.size() > 1) {
             LOG.warn("Identity reference {} has multiple identities, using only the first one", idref);
         }
@@ -360,7 +379,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
                 identity = id;
             }
         }
-        Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exists");
+        Preconditions.checkArgument(identity != null, "Target identity '" + baseIdQName + "' do not exist");
 
         final String basePackageName = BindingMapping.getRootPackageName(module.getQNameModule());
         final JavaTypeName identifier = JavaTypeName.create(BindingGeneratorUtil.packageNameForGeneratedType(
@@ -484,50 +503,80 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * to find referenced node and its <code>Type</code> is returned.
      *
      * @param leafrefType leafref type definition for which is the type sought
+     * @param parentNode parent node of the leaf being resolved
+     * @param inGrouping true if we are resolving the type within a grouping.
      * @return JAVA <code>Type</code> of data schema node which is referenced in <code>leafrefType</code>
      * @throws IllegalArgumentException
      *             <ul>
      *             <li>if <code>leafrefType</code> equal null</li>
      *             <li>if path statement of <code>leafrefType</code> equal null</li>
      *             </ul>
-     *
      */
-    public Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode) {
+    @VisibleForTesting
+    Type provideTypeForLeafref(final LeafrefTypeDefinition leafrefType, final SchemaNode parentNode,
+            final boolean inGrouping) {
         Preconditions.checkArgument(leafrefType != null, "Leafref Type Definition reference cannot be NULL!");
-        Preconditions.checkArgument(leafrefType.getPathStatement() != null,
-                "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        final RevisionAwareXPath xpath = leafrefType.getPathStatement();
-        final String strXPath = xpath.toString();
-        Type returnType = null;
+        final PathExpression xpath = leafrefType.getPathStatement();
+        Preconditions.checkArgument(xpath != null, "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        if (strXPath != null) {
-            if (strXPath.indexOf('[') == -1) {
-                final Module module = findParentModule(schemaContext, parentNode);
-                Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
+        final String strXPath = xpath.getOriginalString();
+        if (strXPath.indexOf('[') != -1) {
+            // XXX: why are we special-casing this?
+            return Types.objectType();
+        }
 
-                final SchemaNode dataNode;
-                if (xpath.isAbsolute()) {
-                    dataNode = findDataSchemaNode(schemaContext, module, xpath);
-                } else {
-                    dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
-                }
-                Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
-                        strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule());
-
-                // FIXME: this block seems to be some weird magic hack. Analyze and refactor it.
-                if (leafContainsEnumDefinition(dataNode)) {
-                    returnType = referencedTypes.get(dataNode.getPath());
-                } else if (leafListContainsEnumDefinition(dataNode)) {
-                    returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
-                }
-                if (returnType == null) {
-                    returnType = resolveTypeFromDataSchemaNode(dataNode);
-                }
-            } else {
-                returnType = Types.objectType();
+        final Module module = findParentModule(schemaContext, parentNode);
+        Preconditions.checkArgument(module != null, "Failed to find module for parent %s", parentNode);
+
+        final SchemaNode dataNode;
+        if (xpath.isAbsolute()) {
+            dataNode = findDataTreeSchemaNode(schemaContext, module.getQNameModule(), xpath);
+        } else {
+            dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
+            if (dataNode == null && inGrouping) {
+                // Relative path within a grouping may end up being unresolvable because it may refer outside
+                // the grouping, in which case it is polymorphic based on instantiation, for example:
+                //
+                // grouping foo {
+                //     leaf foo {
+                //         type leafref {
+                //             path "../../bar";
+                //         }
+                //     }
+                // }
+                //
+                // container one {
+                //     leaf bar {
+                //         type string;
+                //     }
+                //     uses foo;
+                // }
+                //
+                // container two {
+                //     leaf bar {
+                //         type uint16;
+                //     }
+                //     uses foo;
+                // }
+                LOG.debug("Leafref type {} not found in parent {}, assuming polymorphic object", leafrefType,
+                    parentNode);
+                return Types.objectType();
             }
         }
+        Preconditions.checkArgument(dataNode != null, "Failed to find leafref target: %s in module %s (%s)",
+                strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule());
+
+        // FIXME: this block seems to be some weird magic hack. Analyze and refactor it.
+        Type returnType = null;
+        if (leafContainsEnumDefinition(dataNode)) {
+            returnType = referencedTypes.get(dataNode.getPath());
+        } else if (leafListContainsEnumDefinition(dataNode)) {
+            returnType = Types.listTypeFor(referencedTypes.get(dataNode.getPath()));
+        }
+        if (returnType == null) {
+            returnType = resolveTypeFromDataSchemaNode(dataNode, inGrouping);
+        }
         Preconditions.checkArgument(returnType != null, "Failed to find leafref target: %s in module %s (%s)",
                 strXPath, this.getParentModule(parentNode).getName(), parentNode.getQName().getModule(), this);
         return returnType;
@@ -547,7 +596,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     private static boolean leafContainsEnumDefinition(final SchemaNode dataNode) {
         if (dataNode instanceof LeafSchemaNode) {
             final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
-            return CompatUtils.compatLeafType(leaf) instanceof EnumTypeDefinition;
+            return CompatUtils.compatType(leaf) instanceof EnumTypeDefinition;
         }
         return false;
     }
@@ -682,16 +731,16 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * @param dataNode contains information about YANG type
      * @return JAVA <code>Type</code> representation of <code>dataNode</code>
      */
-    private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode) {
+    private Type resolveTypeFromDataSchemaNode(final SchemaNode dataNode, final boolean inGrouping) {
         Type returnType = null;
         if (dataNode != null) {
             if (dataNode instanceof LeafSchemaNode) {
                 final LeafSchemaNode leaf = (LeafSchemaNode) dataNode;
-                final TypeDefinition<?> type = CompatUtils.compatLeafType(leaf);
-                returnType = javaTypeForSchemaDefinitionType(type, leaf);
+                final TypeDefinition<?> type = CompatUtils.compatType(leaf);
+                returnType = javaTypeForSchemaDefinitionType(type, leaf, inGrouping);
             } else if (dataNode instanceof LeafListSchemaNode) {
                 final LeafListSchemaNode leafList = (LeafListSchemaNode) dataNode;
-                returnType = javaTypeForSchemaDefinitionType(leafList.getType(), leafList);
+                returnType = javaTypeForSchemaDefinitionType(leafList.getType(), leafList, inGrouping);
             }
         }
         return returnType;
@@ -709,9 +758,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
      * which map current module name to the map which maps type names to returned types (generated types).
      */
     private void resolveTypeDefsFromContext() {
-        final Set<Module> modules = schemaContext.getModules();
-        Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
-        final List<Module> modulesSortedByDependency = ModuleDependencySort.sort(modules);
+        final List<Module> modulesSortedByDependency = ModuleDependencySort.sort(schemaContext.getModules());
 
         for (Module module : modulesSortedByDependency) {
             Map<Optional<Revision>, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.computeIfAbsent(
@@ -829,13 +876,15 @@ public abstract class AbstractTypeProvider implements TypeProvider {
 
         final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
-        final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty("value");
+        final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(TypeConstants.VALUE_PROP);
         genPropBuilder.setReturnType(javaType);
+
         genTOBuilder.addEqualsIdentity(genPropBuilder);
         genTOBuilder.addHashIdentity(genPropBuilder);
         genTOBuilder.addToStringProperty(genPropBuilder);
+        genTOBuilder.addImplementsType(BindingTypes.scalarTypeObject(javaType));
         if (typedef.getStatus() == Status.DEPRECATED) {
-            genTOBuilder.addAnnotation("java.lang", "Deprecated");
+            genTOBuilder.addAnnotation(DEPRECATED_ANNOTATION);
         }
         if (javaType instanceof ConcreteType && "String".equals(javaType.getName()) && typedef.getBaseType() != null) {
             addStringRegExAsConstant(genTOBuilder, resolveRegExpressionsFromTypedef(typedef));
@@ -892,6 +941,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         unionGenTOBuilder.setIsUnion(true);
         unionGenTOBuilder.setSchemaPath(typedef.getPath());
         unionGenTOBuilder.setModuleName(module.getName());
+        unionGenTOBuilder.addImplementsType(TYPE_OBJECT);
         addCodegenInformation(unionGenTOBuilder, typedef);
         generatedTOBuilders.add(unionGenTOBuilder);
 
@@ -977,8 +1027,8 @@ public abstract class AbstractTypeProvider implements TypeProvider {
 
         final TypeDefinition<?> baseType = baseTypeDefForExtendedType(unionSubtype);
         if (unionTypeName.equals(baseType.getQName().getLocalName())) {
-            final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(baseType,
-                parentNode, BindingGeneratorUtil.getRestrictions(unionSubtype));
+            final Type javaType = BaseYangTypesProvider.INSTANCE.javaTypeForSchemaDefinitionType(baseType, parentNode,
+                BindingGeneratorUtil.getRestrictions(unionSubtype));
             if (javaType != null) {
                 updateUnionTypeAsProperty(parentUnionGenTOBuilder, javaType, unionTypeName);
             }
@@ -1106,13 +1156,13 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         genTOBuilder.setSchemaPath(typeDef.getPath());
         genTOBuilder.setModuleName(moduleName);
         genTOBuilder.setBaseType(typeDef);
+        genTOBuilder.addImplementsType(TYPE_OBJECT);
         addCodegenInformation(genTOBuilder, typeDef);
 
-        final List<Bit> bitList = typeDef.getBits();
-        GeneratedPropertyBuilder genPropertyBuilder;
-        for (Bit bit : bitList) {
+        for (Bit bit : typeDef.getBits()) {
             final String name = bit.getName();
-            genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
+            GeneratedPropertyBuilder genPropertyBuilder = genTOBuilder.addProperty(
+                BindingMapping.getPropertyName(name));
             genPropertyBuilder.setReadOnly(true);
             genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
 
@@ -1177,7 +1227,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         addStringRegExAsConstant(genTOBuilder, resolveRegExpressionsFromTypedef(typedef));
 
         if (typedef.getStatus() == Status.DEPRECATED) {
-            genTOBuilder.addAnnotation("java.lang", "Deprecated");
+            genTOBuilder.addAnnotation(DEPRECATED_ANNOTATION);
         }
 
         if (baseTypeDefForExtendedType(innerExtendedType) instanceof UnionTypeDefinition) {
@@ -1316,7 +1366,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     public String getTypeDefaultConstruction(final LeafSchemaNode node, final String defaultValue) {
-        final TypeDefinition<?> type = CompatUtils.compatLeafType(node);
+        final TypeDefinition<?> type = CompatUtils.compatType(node);
         final QName typeQName = type.getQName();
         final TypeDefinition<?> base = baseTypeDefForExtendedType(type);
         requireNonNull(type, () -> "Cannot provide default construction for null type of " + node);
@@ -1375,38 +1425,26 @@ public abstract class AbstractTypeProvider implements TypeProvider {
             throw new UnsupportedOperationException("Cannot get default construction for identityref type");
         } else if (base instanceof InstanceIdentifierTypeDefinition) {
             throw new UnsupportedOperationException("Cannot get default construction for instance-identifier type");
-        } else if (BaseTypes.isInt8(base)) {
+        } else if (isInt8(base)) {
             result = typeToValueOfDef(Byte.class, defaultValue);
-        } else if (BaseTypes.isInt16(base)) {
+        } else if (isInt16(base)) {
             result = typeToValueOfDef(Short.class, defaultValue);
-        } else if (BaseTypes.isInt32(base)) {
+        } else if (isInt32(base)) {
             result = typeToValueOfDef(Integer.class, defaultValue);
-        } else if (BaseTypes.isInt64(base)) {
+        } else if (isInt64(base)) {
             result = typeToValueOfDef(Long.class, defaultValue);
         } else if (base instanceof LeafrefTypeDefinition) {
             result = leafrefToDef(node, (LeafrefTypeDefinition) base, defaultValue);
         } else if (base instanceof StringTypeDefinition) {
             result = "\"" + defaultValue + "\"";
-        } else if (BaseTypes.isUint8(base)) {
-            result = typeToValueOfDef(Short.class, defaultValue);
-        } else if (BaseTypes.isUint16(base)) {
-            result = typeToValueOfDef(Integer.class, defaultValue);
-        } else if (BaseTypes.isUint32(base)) {
-            result = typeToValueOfDef(Long.class, defaultValue);
-        } else if (BaseTypes.isUint64(base)) {
-            switch (defaultValue) {
-                case "0":
-                    result = "java.math.BigInteger.ZERO";
-                    break;
-                case "1":
-                    result = "java.math.BigInteger.ONE";
-                    break;
-                case "10":
-                    result = "java.math.BigInteger.TEN";
-                    break;
-                default:
-                    result = typeToDef(BigInteger.class, defaultValue);
-            }
+        } else if (isUint8(base)) {
+            result = typeToValueOfDef(Uint8.class, defaultValue);
+        } else if (isUint16(base)) {
+            result = typeToValueOfDef(Uint16.class, defaultValue);
+        } else if (isUint32(base)) {
+            result = typeToValueOfDef(Uint32.class, defaultValue);
+        } else if (isUint64(base)) {
+            result = typeToValueOfDef(Uint64.class, defaultValue);
         } else if (base instanceof UnionTypeDefinition) {
             result = unionToDef(node);
         } else {
@@ -1428,6 +1466,91 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         return sb.toString();
     }
 
+
+    /**
+     * Check if a particular type definition represents the built-in int8 type.
+     *
+     * @param type Type definition
+     * @return True if the definition is the built-in int8 type.
+     */
+    private static boolean isInt8(final TypeDefinition<?> type) {
+        return BaseTypes.int8Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type definition represents the built-in int16 type.
+     *
+     * @param type Type definition
+     * @return True if the definition is the built-in int16 type.
+     */
+    private static boolean isInt16(final TypeDefinition<?> type) {
+        return BaseTypes.int16Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type definition represents the built-in int32 type.
+     *
+     * @param type Type definition
+     * @return True if the definition is the built-in int32 type.
+     */
+    private static boolean isInt32(final TypeDefinition<?> type) {
+        return BaseTypes.int32Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type definition represents the built-in int64 type.
+     *
+     * @param type Type definition
+     * @return True if the definition is the built-in int64 type.
+     */
+    private static boolean isInt64(final TypeDefinition<?> type) {
+        return BaseTypes.int64Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type is the base type for uint8.
+     *
+     * @param type The type to check
+     * @return If the type corresponds to the base uint8 type.
+     * @throws NullPointerException if type is null
+     */
+    private static boolean isUint8(final TypeDefinition<?> type) {
+        return BaseTypes.uint8Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type is the base type for uint16.
+     *
+     * @param type The type to check
+     * @return If the type corresponds to the base uint16 type.
+     * @throws NullPointerException if type is null
+     */
+    private static boolean isUint16(final TypeDefinition<?> type) {
+        return BaseTypes.uint16Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type is the base type for uint32.
+     *
+     * @param type The type to check
+     * @return If the type corresponds to the base uint32 type.
+     * @throws NullPointerException if type is null
+     */
+    private static boolean isUint32(final TypeDefinition<?> type) {
+        return BaseTypes.uint32Type().getPath().equals(type.getPath());
+    }
+
+    /**
+     * Check if a particular type is the base type for uint64.
+     *
+     * @param type The type to check
+     * @return If the type corresponds to the base uint64 type.
+     * @throws NullPointerException if type is null
+     */
+    private static boolean isUint64(final TypeDefinition<?> type) {
+        return BaseTypes.uint64Type().getPath().equals(type.getPath());
+    }
+
     private static String typeToDef(final Class<?> clazz, final String defaultValue) {
         return "new " + clazz.getName() + "(\"" + defaultValue + "\")";
     }
@@ -1469,16 +1592,10 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         bits.sort(BIT_NAME_COMPARATOR);
         final StringBuilder sb = new StringBuilder();
         if (!isExt) {
-            sb.append("new ");
-            sb.append(className);
-            sb.append('(');
+            sb.append("new ").append(className).append('(');
         }
         for (int i = 0; i < bits.size(); i++) {
-            if (bits.get(i).getName().equals(defaultValue)) {
-                sb.append(true);
-            } else {
-                sb.append(false);
-            }
+            sb.append(bits.get(i).getName().equals(defaultValue));
             if (i != bits.size() - 1) {
                 sb.append(", ");
             }
@@ -1500,8 +1617,8 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         Preconditions.checkArgument(leafrefType.getPathStatement() != null,
                 "The Path Statement for Leafref Type Definition cannot be NULL!");
 
-        final RevisionAwareXPath xpath = leafrefType.getPathStatement();
-        final String strXPath = xpath.toString();
+        final PathExpression xpath = leafrefType.getPathStatement();
+        final String strXPath = xpath.getOriginalString();
 
         if (strXPath != null) {
             if (strXPath.indexOf('[') == -1) {
@@ -1509,7 +1626,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
                 if (module != null) {
                     final SchemaNode dataNode;
                     if (xpath.isAbsolute()) {
-                        dataNode = findDataSchemaNode(schemaContext, module, xpath);
+                        dataNode = findDataTreeSchemaNode(schemaContext, module.getQNameModule(), xpath);
                     } else {
                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
                     }
@@ -1525,14 +1642,14 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     private String unionToDef(final LeafSchemaNode node) {
-        final TypeDefinition<?> type = CompatUtils.compatLeafType(node);
+        final TypeDefinition<?> type = CompatUtils.compatType(node);
         String parentName;
         String className;
 
         if (type.getBaseType() != null) {
             final QName typeQName = type.getQName();
             Module module = null;
-            final Set<Module> modules = schemaContext.findModules(typeQName.getNamespace());
+            final Collection<? extends Module> modules = schemaContext.findModules(typeQName.getNamespace());
             if (modules.size() > 1) {
                 for (Module m : modules) {
                     if (m.getRevision().equals(typeQName.getRevision())) {
@@ -1569,18 +1686,14 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     }
 
     private static String union(final String className, final String defaultValue, final LeafSchemaNode node) {
-        final StringBuilder sb = new StringBuilder();
-        sb.append("new ");
-        sb.append(className);
-        sb.append("(\"");
-        sb.append(defaultValue);
-        sb.append("\".toCharArray())");
-        return sb.toString();
+        return new StringBuilder()
+                .append("new ").append(className).append("(\"").append(defaultValue).append("\".toCharArray())")
+                .toString();
     }
 
     @Override
     public String getConstructorPropertyName(final SchemaNode node) {
-        return node instanceof TypeDefinition<?> ? "value" : "";
+        return node instanceof TypeDefinition<?> ? TypeConstants.VALUE_PROP : "";
     }
 
     @Override