Bug 2287 - TypeProviderImpl retains empty HashMaps
[yangtools.git] / code-generator / binding-type-provider / src / main / java / org / opendaylight / yangtools / sal / binding / yang / types / TypeProviderImpl.java
index 568428738bfb78247b33bdbaa109e26d42556008..11edd05925046b52f6bd309ca86d1b897c74f035 100644 (file)
@@ -7,24 +7,32 @@
  */
 package org.opendaylight.yangtools.sal.binding.yang.types;
 
-import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.*;
-import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.*;
+import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.moduleNamespaceToPackageName;
+import static org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil.packageNameForGeneratedType;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNodeForRelativeXPath;
+import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findParentModule;
 
+import com.google.common.base.Preconditions;
+import com.google.common.collect.Sets;
+import com.google.common.io.BaseEncoding;
+import java.io.Serializable;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 import java.util.HashMap;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
-
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.opendaylight.yangtools.binding.generator.util.BindingGeneratorUtil;
 import org.opendaylight.yangtools.binding.generator.util.TypeConstants;
@@ -33,8 +41,10 @@ import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.
 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedPropertyBuilderImpl;
 import org.opendaylight.yangtools.binding.generator.util.generated.type.builder.GeneratedTOBuilderImpl;
 import org.opendaylight.yangtools.sal.binding.generator.spi.TypeProvider;
+import org.opendaylight.yangtools.sal.binding.model.api.AccessModifier;
 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType;
 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration;
+import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty;
 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject;
 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions;
 import org.opendaylight.yangtools.sal.binding.model.api.Type;
@@ -42,9 +52,9 @@ import org.opendaylight.yangtools.sal.binding.model.api.type.builder.EnumBuilder
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedPropertyBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.yangtools.sal.binding.model.api.type.builder.GeneratedTypeBuilderBase;
+import org.opendaylight.yangtools.sal.binding.model.api.type.builder.MethodSignatureBuilder;
+import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.common.QName;
-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;
@@ -54,7 +64,6 @@ import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
-import org.opendaylight.yangtools.yang.model.api.YangNode;
 import org.opendaylight.yangtools.yang.model.api.type.BinaryTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition.Bit;
@@ -69,6 +78,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.DataNodeIterator;
+import org.opendaylight.yangtools.yang.model.util.EnumerationType;
 import org.opendaylight.yangtools.yang.model.util.ExtendedType;
 import org.opendaylight.yangtools.yang.model.util.Int16;
 import org.opendaylight.yangtools.yang.model.util.Int32;
@@ -80,12 +90,10 @@ import org.opendaylight.yangtools.yang.model.util.Uint32;
 import org.opendaylight.yangtools.yang.model.util.Uint64;
 import org.opendaylight.yangtools.yang.model.util.Uint8;
 import org.opendaylight.yangtools.yang.model.util.UnionType;
-import org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort;
-
-import com.google.common.base.Preconditions;
-import com.google.common.io.BaseEncoding;
 
 public final class TypeProviderImpl implements TypeProvider {
+    private static final Pattern NUMBERS_PATTERN = Pattern.compile("[0-9]+\\z");
+
     /**
      * Contains the schema data red from YANG files.
      */
@@ -94,12 +102,13 @@ public final class TypeProviderImpl implements TypeProvider {
     /**
      * Map<moduleName, Map<moduleDate, Map<typeName, type>>>
      */
-    private Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
+    private final Map<String, Map<Date, Map<String, Type>>> genTypeDefsContextMap;
 
     /**
      * The map which maps schema paths to JAVA <code>Type</code>.
      */
     private final Map<SchemaPath, Type> referencedTypes;
+    private final Map<Module, Set<Type>> additionalTypes;
 
     /**
      * Creates new instance of class <code>TypeProviderImpl</code>.
@@ -115,6 +124,7 @@ public final class TypeProviderImpl implements TypeProvider {
         this.schemaContext = schemaContext;
         this.genTypeDefsContextMap = new HashMap<>();
         this.referencedTypes = new HashMap<>();
+        this.additionalTypes = new HashMap<>();
         resolveTypeDefsFromContext();
     }
 
@@ -139,6 +149,10 @@ public final class TypeProviderImpl implements TypeProvider {
         referencedTypes.put(refTypePath, refType);
     }
 
+    public Map<Module, Set<Type>> getAdditionalTypes() {
+        return additionalTypes;
+    }
+
     /**
      *
      * Converts basic YANG type <code>type</code> to JAVA <code>Type</code>.
@@ -149,7 +163,8 @@ public final class TypeProviderImpl implements TypeProvider {
      * @see TypeProvider#javaTypeForYangType(String)
      */
     @Override
-    public Type javaTypeForYangType(String type) {
+    @Deprecated
+    public Type javaTypeForYangType(final String type) {
         return BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForYangType(type);
     }
 
@@ -173,18 +188,27 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     @Override
     public Type javaTypeForSchemaDefinitionType(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode,
-            Restrictions r) {
-        Type returnType = null;
+            final Restrictions r) {
+        Type returnType;
         Preconditions.checkArgument(typeDefinition != null, "Type Definition cannot be NULL!");
-        if (typeDefinition.getQName() == null) {
-            throw new IllegalArgumentException(
-                    "Type Definition cannot have non specified QName (QName cannot be NULL!)");
-        }
-        Preconditions.checkArgument(typeDefinition.getQName().getLocalName() != null,
-                "Type Definitions Local Name cannot be NULL!");
+        Preconditions.checkArgument(typeDefinition.getQName() != null,
+                "Type Definition cannot have non specified QName (QName cannot be NULL!)");
+        String typedefName = typeDefinition.getQName().getLocalName();
+        Preconditions.checkArgument(typedefName != null, "Type Definitions Local Name cannot be NULL!");
 
         if (typeDefinition instanceof ExtendedType) {
             returnType = javaTypeForExtendedType(typeDefinition);
+            if (r != null && returnType instanceof GeneratedTransferObject) {
+                GeneratedTransferObject gto = (GeneratedTransferObject) returnType;
+                Module module = findParentModule(schemaContext, parentNode);
+                String basePackageName = moduleNamespaceToPackageName(module);
+                String packageName = packageNameForGeneratedType(basePackageName, typeDefinition.getPath());
+                String genTOName = BindingMapping.getClassName(typedefName);
+                String name = packageName + "." + genTOName;
+                if (!(returnType.getFullyQualifiedName().equals(name))) {
+                    returnType = shadedTOWithRestrictions(gto, r);
+                }
+            }
         } else {
             returnType = javaTypeForLeafrefOrIdentityRef(typeDefinition, parentNode);
             if (returnType == null) {
@@ -192,15 +216,28 @@ public final class TypeProviderImpl implements TypeProvider {
                         .getLocalName());
             }
         }
-        // TODO: add throw exception when we will be able to resolve ALL yang
-        // types!
-        // if (returnType == null) {
-        // throw new IllegalArgumentException("Type Provider can't resolve " +
-        // "type for specified Type Definition " + typedefName);
-        // }
         return returnType;
     }
 
+    private GeneratedTransferObject shadedTOWithRestrictions(final GeneratedTransferObject gto, final Restrictions r) {
+        GeneratedTOBuilder gtob = new GeneratedTOBuilderImpl(gto.getPackageName(), gto.getName());
+        GeneratedTransferObject parent = gto.getSuperType();
+        if (parent != null) {
+            gtob.setExtendsType(parent);
+        }
+        gtob.setRestrictions(r);
+        for (GeneratedProperty gp : gto.getProperties()) {
+            GeneratedPropertyBuilder gpb = gtob.addProperty(gp.getName());
+            gpb.setValue(gp.getValue());
+            gpb.setReadOnly(gp.isReadOnly());
+            gpb.setAccessModifier(gp.getAccessModifier());
+            gpb.setReturnType(gp.getReturnType());
+            gpb.setFinal(gp.isFinal());
+            gpb.setStatic(gp.isStatic());
+        }
+        return gtob.toInstance();
+    }
+
     /**
      * Returns JAVA <code>Type</code> for instances of the type
      * <code>LeafrefTypeDefinition</code> or
@@ -210,7 +247,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *            type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForLeafrefOrIdentityRef(TypeDefinition<?> typeDefinition, SchemaNode parentNode) {
+    private Type javaTypeForLeafrefOrIdentityRef(final TypeDefinition<?> typeDefinition, final SchemaNode parentNode) {
         if (typeDefinition instanceof LeafrefTypeDefinition) {
             final LeafrefTypeDefinition leafref = (LeafrefTypeDefinition) typeDefinition;
             return provideTypeForLeafref(leafref, parentNode);
@@ -230,11 +267,10 @@ public final class TypeProviderImpl implements TypeProvider {
      *            type definition which is converted to JAVA <code>Type</code>
      * @return JAVA <code>Type</code> instance for <code>typeDefinition</code>
      */
-    private Type javaTypeForExtendedType(TypeDefinition<?> typeDefinition) {
+    private Type javaTypeForExtendedType(final TypeDefinition<?> typeDefinition) {
         final String typedefName = typeDefinition.getQName().getLocalName();
         final TypeDefinition<?> baseTypeDef = baseTypeDefForExtendedType(typeDefinition);
-        Type returnType = null;
-        returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
+        Type returnType = javaTypeForLeafrefOrIdentityRef(baseTypeDef, typeDefinition);
         if (returnType == null) {
             if (baseTypeDef instanceof EnumTypeDefinition) {
                 final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) baseTypeDef;
@@ -256,12 +292,6 @@ public final class TypeProviderImpl implements TypeProvider {
             }
         }
         return returnType;
-        // TODO: add throw exception when we will be able to resolve ALL yang
-        // types!
-        // if (returnType == null) {
-        // throw new IllegalArgumentException("Type Provider can't resolve " +
-        // "type for specified Type Definition " + typedefName);
-        // }
     }
 
     /**
@@ -279,7 +309,7 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return JAVA <code>Type</code> of the identity which is refrenced through
      *         <code>idref</code>
      */
-    private Type provideTypeForIdentityref(IdentityrefTypeDefinition idref) {
+    private Type provideTypeForIdentityref(final IdentityrefTypeDefinition idref) {
         QName baseIdQName = idref.getIdentity().getQName();
         Module module = schemaContext.findModuleByNamespaceAndRevision(baseIdQName.getNamespace(),
                 baseIdQName.getRevision());
@@ -293,7 +323,7 @@ public final class TypeProviderImpl implements TypeProvider {
 
         final String basePackageName = moduleNamespaceToPackageName(module);
         final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
-        final String genTypeName = parseToClassName(identity.getQName().getLocalName());
+        final String genTypeName = BindingMapping.getClassName(identity.getQName());
 
         Type baseType = Types.typeForClass(Class.class);
         Type paramType = Types.wildcardTypeFor(packageName, genTypeName);
@@ -356,7 +386,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             if <code>extendTypeDef</code> equal null
      */
     private TypeDefinition<?> baseTypeDefForExtendedType(final TypeDefinition<?> extendTypeDef) {
-        Preconditions.checkArgument(extendTypeDef != null, "Type Definiition reference cannot be NULL!");
+        Preconditions.checkArgument(extendTypeDef != null, "Type Definition reference cannot be NULL!");
         final TypeDefinition<?> baseTypeDef = extendTypeDef.getBaseType();
         if (baseTypeDef == null) {
             return extendTypeDef;
@@ -396,9 +426,7 @@ public final class TypeProviderImpl implements TypeProvider {
         final String strXPath = xpath.toString();
 
         if (strXPath != null) {
-            if (strXPath.contains("[")) {
-                returnType = Types.typeForClass(Object.class);
-            } else {
+            if (strXPath.indexOf('[') == -1) {
                 final Module module = findParentModule(schemaContext, parentNode);
                 if (module != null) {
                     final SchemaNode dataNode;
@@ -416,8 +444,13 @@ public final class TypeProviderImpl implements TypeProvider {
                         returnType = resolveTypeFromDataSchemaNode(dataNode);
                     }
                 }
+            } else {
+                returnType = Types.typeForClass(Object.class);
             }
         }
+        if (returnType == null) {
+            throw new IllegalArgumentException("Failed to find leafref target: " + strXPath);
+        }
         return returnType;
     }
 
@@ -496,12 +529,16 @@ public final class TypeProviderImpl implements TypeProvider {
         Preconditions.checkArgument(enumTypeDef.getQName().getLocalName() != null,
                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
 
-        final String enumerationName = parseToClassName(enumName);
+        final String enumerationName = BindingMapping.getClassName(enumName);
 
         Module module = findParentModule(schemaContext, parentNode);
         final String basePackageName = moduleNamespaceToPackageName(module);
 
-        final EnumBuilder enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
+        final EnumerationBuilderImpl enumBuilder = new EnumerationBuilderImpl(basePackageName, enumerationName);
+        enumBuilder.setDescription(enumTypeDef.getDescription());
+        enumBuilder.setReference(enumTypeDef.getReference());
+        enumBuilder.setModuleName(module.getName());
+        enumBuilder.setSchemaPath(enumTypeDef.getPath().getPathFromRoot());
         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
         return enumBuilder.toInstance(null);
     }
@@ -539,9 +576,10 @@ public final class TypeProviderImpl implements TypeProvider {
                 "Local Name in EnumTypeDefinition QName cannot be NULL!");
         Preconditions.checkArgument(typeBuilder != null, "Generated Type Builder reference cannot be NULL!");
 
-        final String enumerationName = parseToClassName(enumName);
+        final String enumerationName = BindingMapping.getClassName(enumName);
 
         final EnumBuilder enumBuilder = typeBuilder.addEnumeration(enumerationName);
+        enumBuilder.setDescription(enumTypeDef.getDescription());
         enumBuilder.updateEnumPairsFromEnumTypeDef(enumTypeDef);
         return enumBuilder.toInstance(enumBuilder);
     }
@@ -583,21 +621,21 @@ public final class TypeProviderImpl implements TypeProvider {
      */
     private void resolveTypeDefsFromContext() {
         final Set<Module> modules = schemaContext.getModules();
-        Preconditions.checkArgument(modules != null, "Sef of Modules cannot be NULL!");
+        Preconditions.checkArgument(modules != null, "Set of Modules cannot be NULL!");
         final Module[] modulesArray = new Module[modules.size()];
         int i = 0;
         for (Module modul : modules) {
             modulesArray[i++] = modul;
         }
-        final List<Module> modulesSortedByDependency = ModuleDependencySort.sort(modulesArray);
+        final List<Module> modulesSortedByDependency = org.opendaylight.yangtools.yang.parser.util.ModuleDependencySort
+                .sort(modulesArray);
 
         for (final Module module : modulesSortedByDependency) {
             Map<Date, Map<String, Type>> dateTypeMap = genTypeDefsContextMap.get(module.getName());
             if (dateTypeMap == null) {
                 dateTypeMap = new HashMap<>();
             }
-            final Map<String, Type> typeMap = new HashMap<>();
-            dateTypeMap.put(module.getRevision(), typeMap);
+            dateTypeMap.put(module.getRevision(), Collections.<String, Type>emptyMap());
             genTypeDefsContextMap.put(module.getName(), dateTypeMap);
         }
 
@@ -605,7 +643,6 @@ public final class TypeProviderImpl implements TypeProvider {
             if (module == null) {
                 continue;
             }
-            final String moduleName = module.getName();
             final String basePackageName = moduleNamespaceToPackageName(module);
 
             final DataNodeIterator it = new DataNodeIterator(module);
@@ -614,7 +651,7 @@ public final class TypeProviderImpl implements TypeProvider {
 
             if ((listTypeDefinitions != null) && (basePackageName != null)) {
                 for (final TypeDefinition<?> typedef : listTypeDefinitions) {
-                    typedefToGeneratedType(basePackageName, moduleName, module.getRevision(), typedef);
+                    typedefToGeneratedType(basePackageName, module, typedef);
                 }
             }
         }
@@ -624,7 +661,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *
      * @param basePackageName
      *            string with name of package to which the module belongs
-     * @param moduleName
+     * @param module
      *            string with the name of the module for to which the
      *            <code>typedef</code> belongs
      * @param typedef
@@ -635,10 +672,11 @@ public final class TypeProviderImpl implements TypeProvider {
      *         <code>modulName</code> or <code>typedef</code> or Q name of
      *         <code>typedef</code> equals <code>null</code>
      */
-    private Type typedefToGeneratedType(final String basePackageName, final String moduleName,
-            final Date moduleRevision, final TypeDefinition<?> typedef) {
+    private Type typedefToGeneratedType(final String basePackageName, final Module module,
+            final TypeDefinition<?> typedef) {
+        final String moduleName = module.getName();
+        final Date moduleRevision = module.getRevision();
         if ((basePackageName != null) && (moduleName != null) && (typedef != null) && (typedef.getQName() != null)) {
-
             final String typedefName = typedef.getQName().getLocalName();
             final TypeDefinition<?> innerTypeDefinition = typedef.getBaseType();
             if (!(innerTypeDefinition instanceof LeafrefTypeDefinition)
@@ -646,35 +684,58 @@ public final class TypeProviderImpl implements TypeProvider {
                 Type returnType = null;
                 if (innerTypeDefinition instanceof ExtendedType) {
                     ExtendedType innerExtendedType = (ExtendedType) innerTypeDefinition;
-                    returnType = provideGeneratedTOFromExtendedType(typedef, innerExtendedType, basePackageName);
+                    returnType = provideGeneratedTOFromExtendedType(typedef, innerExtendedType, basePackageName,
+                            module.getName());
                 } else if (innerTypeDefinition instanceof UnionTypeDefinition) {
                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForUnionTypeDef(basePackageName,
                             (UnionTypeDefinition) innerTypeDefinition, typedefName, typedef);
                     genTOBuilder.setTypedef(true);
                     genTOBuilder.setIsUnion(true);
                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
+                    makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
                     returnType = genTOBuilder.toInstance();
+                    // union builder
+                    GeneratedTOBuilder unionBuilder = new GeneratedTOBuilderImpl(genTOBuilder.getPackageName(),
+                            genTOBuilder.getName() + "Builder");
+                    unionBuilder.setIsUnionBuilder(true);
+                    MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
+                    method.setReturnType(returnType);
+                    method.addParameter(Types.STRING, "defaultValue");
+                    method.setAccessModifier(AccessModifier.PUBLIC);
+                    method.setStatic(true);
+                    Set<Type> types = additionalTypes.get(module);
+                    if (types == null) {
+                        types = Sets.<Type> newHashSet(unionBuilder.toInstance());
+                        additionalTypes.put(module, types);
+                    } else {
+                        types.add(unionBuilder.toInstance());
+                    }
                 } else if (innerTypeDefinition instanceof EnumTypeDefinition) {
+                    // enums are automatically Serializable
                     final EnumTypeDefinition enumTypeDef = (EnumTypeDefinition) innerTypeDefinition;
                     // TODO units for typedef enum
                     returnType = provideTypeForEnum(enumTypeDef, typedefName, typedef);
                 } else if (innerTypeDefinition instanceof BitsTypeDefinition) {
                     final BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) innerTypeDefinition;
                     final GeneratedTOBuilder genTOBuilder = provideGeneratedTOBuilderForBitsTypeDefinition(
-                            basePackageName, bitsTypeDefinition, typedefName);
+                            basePackageName, bitsTypeDefinition, typedefName, module.getName());
                     genTOBuilder.setTypedef(true);
                     addUnitsToGenTO(genTOBuilder, typedef.getUnits());
+                    makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
                     returnType = genTOBuilder.toInstance();
                 } else {
                     final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
                             innerTypeDefinition, typedef);
-                    returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType);
+                    returnType = wrapJavaTypeIntoTO(basePackageName, typedef, javaType, module.getName());
                 }
                 if (returnType != null) {
                     final Map<Date, Map<String, Type>> modulesByDate = genTypeDefsContextMap.get(moduleName);
-                    final Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
-
+                    Map<String, Type> typeMap = modulesByDate.get(moduleRevision);
                     if (typeMap != null) {
+                        if (typeMap.isEmpty()) {
+                            typeMap = new HashMap<>(4);
+                            modulesByDate.put(moduleRevision, typeMap);
+                        }
                         typeMap.put(typedefName, returnType);
                     }
                     return returnType;
@@ -696,11 +757,11 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return generated transfer object which represent<code>javaType</code>
      */
     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
-            final Type javaType) {
+            final Type javaType, final String moduleName) {
         Preconditions.checkNotNull(javaType, "javaType cannot be null");
         final String propertyName = "value";
 
-        final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef);
+        final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
         final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
         genPropBuilder.setReturnType(javaType);
@@ -713,6 +774,7 @@ public final class TypeProviderImpl implements TypeProvider {
         }
         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
         genTOBuilder.setTypedef(true);
+        makeSerializable((GeneratedTOBuilderImpl) genTOBuilder);
         return genTOBuilder.toInstance();
     }
 
@@ -731,16 +793,25 @@ public final class TypeProviderImpl implements TypeProvider {
      *         builders
      */
     public GeneratedTOBuilder provideGeneratedTOBuilderForUnionTypeDef(final String basePackageName,
-            final UnionTypeDefinition typedef, String typeDefName, SchemaNode parentNode) {
+            final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode) {
         final List<GeneratedTOBuilder> genTOBuilders = provideGeneratedTOBuildersForUnionTypeDef(basePackageName,
                 typedef, typeDefName, parentNode);
         GeneratedTOBuilder resultTOBuilder = null;
-        if (!genTOBuilders.isEmpty()) {
-            resultTOBuilder = genTOBuilders.remove(0);
-            for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
-                resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
-            }
+        if (genTOBuilders.isEmpty()) {
+            throw new IllegalStateException("No GeneratedTOBuilder objects generated from union " + typedef);
+        }
+
+        resultTOBuilder = genTOBuilders.remove(0);
+        for (GeneratedTOBuilder genTOBuilder : genTOBuilders) {
+            resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
         }
+
+        final GeneratedPropertyBuilder genPropBuilder = resultTOBuilder.addProperty("value");
+        genPropBuilder.setReturnType(Types.CHAR_ARRAY);
+        resultTOBuilder.addEqualsIdentity(genPropBuilder);
+        resultTOBuilder.addHashIdentity(genPropBuilder);
+        resultTOBuilder.addToStringProperty(genPropBuilder);
+
         return resultTOBuilder;
     }
 
@@ -757,59 +828,62 @@ public final class TypeProviderImpl implements TypeProvider {
      * @param typeDefName
      *            string with name for generated TO
      * @return generated TO builder which represents <code>typedef</code>
-     * @throws IllegalArgumentException
+     * @throws NullPointerException
      *             <ul>
-     *             <li>if <code>basePackageName</code> equals null</li>
-     *             <li>if <code>typedef</code> equals null</li>
-     *             <li>if Q name of <code>typedef</code> equals null</li>
+     *             <li>if <code>basePackageName</code> is null</li>
+     *             <li>if <code>typedef</code> is null</li>
+     *             <li>if Qname of <code>typedef</code> is null</li>
      *             </ul>
      */
     public List<GeneratedTOBuilder> provideGeneratedTOBuildersForUnionTypeDef(final String basePackageName,
             final UnionTypeDefinition typedef, final String typeDefName, final SchemaNode parentNode) {
-        Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
-        Preconditions.checkArgument(typedef != null, "Type Definition cannot be NULL!");
-        Preconditions.checkArgument(typedef.getQName() != null,
-                "Type Definition cannot have non specified QName (QName cannot be NULL!)");
+        Preconditions.checkNotNull(basePackageName, "Base Package Name cannot be NULL!");
+        Preconditions.checkNotNull(typedef, "Type Definition cannot be NULL!");
+        Preconditions.checkNotNull(typedef.getQName(), "Type definition QName cannot be NULL!");
 
         final List<GeneratedTOBuilder> generatedTOBuilders = new ArrayList<>();
+        final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
+        final Module module = findParentModule(schemaContext, parentNode);
+
+        final GeneratedTOBuilderImpl unionGenTOBuilder;
+        if (typeDefName != null && !typeDefName.isEmpty()) {
+            final String typeName = BindingMapping.getClassName(typeDefName);
+            unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+            unionGenTOBuilder.setDescription(typedef.getDescription());
+            unionGenTOBuilder.setReference(typedef.getReference());
+            unionGenTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
+            unionGenTOBuilder.setModuleName(module.getName());
+        } else {
+            unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef, module.getName());
+        }
 
-        if (typedef != null) {
-            final List<TypeDefinition<?>> unionTypes = typedef.getTypes();
-
-            final GeneratedTOBuilder unionGenTOBuilder;
-            if (typeDefName != null && !typeDefName.isEmpty()) {
-                final String typeName = parseToClassName(typeDefName);
-                unionGenTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+        generatedTOBuilders.add(unionGenTOBuilder);
+        unionGenTOBuilder.setIsUnion(true);
+        final List<String> regularExpressions = new ArrayList<String>();
+        for (final TypeDefinition<?> unionType : unionTypes) {
+            final String unionTypeName = unionType.getQName().getLocalName();
+            if (unionType instanceof UnionType) {
+                generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionType) unionType,
+                        basePackageName, parentNode));
+            } else if (unionType instanceof ExtendedType) {
+                resolveExtendedSubtypeAsUnion(unionGenTOBuilder, (ExtendedType) unionType, regularExpressions,
+                        parentNode);
+            } else if (unionType instanceof EnumTypeDefinition) {
+                final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
+                        unionTypeName, unionGenTOBuilder);
+                updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
             } else {
-                unionGenTOBuilder = typedefToTransferObject(basePackageName, typedef);
-            }
-            generatedTOBuilders.add(unionGenTOBuilder);
-            unionGenTOBuilder.setIsUnion(true);
-            final List<String> regularExpressions = new ArrayList<String>();
-            for (final TypeDefinition<?> unionType : unionTypes) {
-                final String unionTypeName = unionType.getQName().getLocalName();
-                if (unionType instanceof UnionType) {
-                    generatedTOBuilders.addAll(resolveUnionSubtypeAsUnion(unionGenTOBuilder, (UnionType) unionType,
-                            basePackageName, parentNode));
-                } else if (unionType instanceof ExtendedType) {
-                    resolveExtendedSubtypeAsUnion(unionGenTOBuilder, (ExtendedType) unionType, unionTypeName,
-                            regularExpressions, parentNode);
-                } else if (unionType instanceof EnumTypeDefinition) {
-                    final Enumeration enumeration = addInnerEnumerationToTypeBuilder((EnumTypeDefinition) unionType,
-                            unionTypeName, unionGenTOBuilder);
-                    updateUnionTypeAsProperty(unionGenTOBuilder, enumeration, unionTypeName);
-                } else {
-                    final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(
-                            unionType, parentNode);
-                    updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
-                }
-            }
-            if (!regularExpressions.isEmpty()) {
-                addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
+                final Type javaType = BaseYangTypes.BASE_YANG_TYPES_PROVIDER.javaTypeForSchemaDefinitionType(unionType,
+                        parentNode);
+                updateUnionTypeAsProperty(unionGenTOBuilder, javaType, unionTypeName);
             }
-
-            storeGenTO(typedef, unionGenTOBuilder, parentNode);
         }
+        if (!regularExpressions.isEmpty()) {
+            addStringRegExAsConstant(unionGenTOBuilder, regularExpressions);
+        }
+
+        storeGenTO(typedef, unionGenTOBuilder, parentNode);
+
         return generatedTOBuilders;
     }
 
@@ -819,7 +893,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *
      * In this case the new generated TO is created for union subtype (recursive
      * call of method
-     * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, TypeDefinition, String)
+     * {@link #provideGeneratedTOBuildersForUnionTypeDef(String, UnionTypeDefinition,
+     * String, SchemaNode)}
      * provideGeneratedTOBuilderForUnionTypeDef} and in parent TO builder
      * <code>parentUnionGenTOBuilder</code> is created property which type is
      * equal to new generated TO.
@@ -842,8 +917,7 @@ public final class TypeProviderImpl implements TypeProvider {
                 basePackageName, unionSubtype, newTOBuilderName, parentNode);
 
         final GeneratedPropertyBuilder propertyBuilder;
-        propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingGeneratorUtil
-                .parseToValidParamName(newTOBuilderName));
+        propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(newTOBuilderName));
         propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
@@ -864,15 +938,16 @@ public final class TypeProviderImpl implements TypeProvider {
      * @param unionSubtype
      *            type definition of the <code>ExtendedType</code> type which
      *            represents union subtype
-     * @param unionTypeName
-     *            string with the name for <code>unionSubtype</code>
      * @param regularExpressions
      *            list of strings with the regular expressions
+     * @param parentNode
+     *            parent Schema Node for Extended Subtype
+     *
      */
     private void resolveExtendedSubtypeAsUnion(final GeneratedTOBuilder parentUnionGenTOBuilder,
-            final ExtendedType unionSubtype, final String unionTypeName, final List<String> regularExpressions,
-            final SchemaNode parentNode) {
-        final Type genTO = findGenTO(unionTypeName, parentNode);
+            final ExtendedType unionSubtype, final List<String> regularExpressions, final SchemaNode parentNode) {
+        final String unionTypeName = unionSubtype.getQName().getLocalName();
+        final Type genTO = findGenTO(unionTypeName, unionSubtype);
         if (genTO != null) {
             updateUnionTypeAsProperty(parentUnionGenTOBuilder, genTO, genTO.getName());
         } else {
@@ -922,7 +997,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *            generated TO builder which is converted to generated TO and
      *            stored
      */
-    private void storeGenTO(TypeDefinition<?> newTypeDef, GeneratedTOBuilder genTOBuilder, SchemaNode parentNode) {
+    private void storeGenTO(final TypeDefinition<?> newTypeDef, final GeneratedTOBuilder genTOBuilder,
+            final SchemaNode parentNode) {
         if (!(newTypeDef instanceof UnionType)) {
 
             final Module parentModule = findParentModule(schemaContext, parentNode);
@@ -951,7 +1027,7 @@ public final class TypeProviderImpl implements TypeProvider {
             final String propertyName) {
         if (unionGenTransObject != null && type != null && !unionGenTransObject.containsProperty(propertyName)) {
             final GeneratedPropertyBuilder propBuilder = unionGenTransObject
-                    .addProperty(parseToValidParamName(propertyName));
+                    .addProperty(BindingMapping.getPropertyName(propertyName));
             propBuilder.setReturnType(type);
 
             unionGenTransObject.addEqualsIdentity(propBuilder);
@@ -970,15 +1046,21 @@ public final class TypeProviderImpl implements TypeProvider {
      * @return generated TO builder which contains data from
      *         <code>typedef</code> and <code>basePackageName</code>
      */
-    private GeneratedTOBuilder typedefToTransferObject(final String basePackageName, final TypeDefinition<?> typedef) {
+    private GeneratedTOBuilderImpl typedefToTransferObject(final String basePackageName,
+            final TypeDefinition<?> typedef, final String moduleName) {
 
         final String packageName = packageNameForGeneratedType(basePackageName, typedef.getPath());
         final String typeDefTOName = typedef.getQName().getLocalName();
 
-        if ((packageName != null) && (typedef != null) && (typeDefTOName != null)) {
-            final String genTOName = parseToClassName(typeDefTOName);
-            final GeneratedTOBuilder newType = new GeneratedTOBuilderImpl(packageName, genTOName);
-            newType.addComment(typedef.getDescription());
+        if ((packageName != null) && (typeDefTOName != null)) {
+            final String genTOName = BindingMapping.getClassName(typeDefTOName);
+            final GeneratedTOBuilderImpl newType = new GeneratedTOBuilderImpl(packageName, genTOName);
+
+            newType.setDescription(typedef.getDescription());
+            newType.setReference(typedef.getReference());
+            newType.setSchemaPath(typedef.getPath().getPathFromRoot());
+            newType.setModuleName(moduleName);
+
             return newType;
         }
         return null;
@@ -1005,7 +1087,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             </ul>
      */
     public GeneratedTOBuilder provideGeneratedTOBuilderForBitsTypeDefinition(final String basePackageName,
-            final TypeDefinition<?> typeDef, String typeDefName) {
+            final TypeDefinition<?> typeDef, final String typeDefName, final String moduleName) {
 
         Preconditions.checkArgument(typeDef != null, "typeDef cannot be NULL!");
         Preconditions.checkArgument(basePackageName != null, "Base Package Name cannot be NULL!");
@@ -1013,14 +1095,20 @@ public final class TypeProviderImpl implements TypeProvider {
         if (typeDef instanceof BitsTypeDefinition) {
             BitsTypeDefinition bitsTypeDefinition = (BitsTypeDefinition) typeDef;
 
-            final String typeName = parseToClassName(typeDefName);
-            final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+            final String typeName = BindingMapping.getClassName(typeDefName);
+            final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, typeName);
+
+            genTOBuilder.setDescription(typeDef.getDescription());
+            genTOBuilder.setReference(typeDef.getReference());
+            genTOBuilder.setSchemaPath(typeDef.getPath().getPathFromRoot());
+            genTOBuilder.setModuleName(moduleName);
+            genTOBuilder.setBaseType(typeDef);
 
             final List<Bit> bitList = bitsTypeDefinition.getBits();
             GeneratedPropertyBuilder genPropertyBuilder;
             for (final Bit bit : bitList) {
                 String name = bit.getName();
-                genPropertyBuilder = genTOBuilder.addProperty(parseToValidParamName(name));
+                genPropertyBuilder = genTOBuilder.addProperty(BindingMapping.getPropertyName(name));
                 genPropertyBuilder.setReadOnly(true);
                 genPropertyBuilder.setReturnType(BaseYangTypes.BOOLEAN_TYPE);
 
@@ -1045,7 +1133,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             if <code>typedef</code> equals null
      *
      */
-    private List<String> resolveRegExpressionsFromTypedef(ExtendedType typedef) {
+    private List<String> resolveRegExpressionsFromTypedef(final ExtendedType typedef) {
         final List<String> regExps = new ArrayList<String>();
         Preconditions.checkArgument(typedef != null, "typedef can't be null");
         final TypeDefinition<?> strTypeDef = baseTypeDefForExtendedType(typedef);
@@ -1080,7 +1168,7 @@ public final class TypeProviderImpl implements TypeProvider {
      *             <li>if <code>regularExpressions</code> equals null</li>
      *             </ul>
      */
-    private void addStringRegExAsConstant(GeneratedTOBuilder genTOBuilder, List<String> regularExpressions) {
+    private void addStringRegExAsConstant(final GeneratedTOBuilder genTOBuilder, final List<String> regularExpressions) {
         if (genTOBuilder == null) {
             throw new IllegalArgumentException("Generated transfer object builder can't be null");
         }
@@ -1103,12 +1191,14 @@ public final class TypeProviderImpl implements TypeProvider {
      * {@link TypeProviderImpl#genTypeDefsContextMap genTypeDefsContextMap} to
      * be possible set it as extended type for the returning generated TO.
      *
+     * @param typedef
+     *            Type Definition
      * @param innerExtendedType
      *            extended type which is part of some other extended type
      * @param basePackageName
      *            string with the package name of the module
-     * @param typedefName
-     *            string with the name for the generated TO
+     * @param moduleName
+     *            Module Name
      * @return generated TO which extends generated TO for
      *         <code>innerExtendedType</code>
      * @throws IllegalArgumentException
@@ -1119,14 +1209,19 @@ public final class TypeProviderImpl implements TypeProvider {
      *             </ul>
      */
     private GeneratedTransferObject provideGeneratedTOFromExtendedType(final TypeDefinition<?> typedef,
-            final ExtendedType innerExtendedType, final String basePackageName) {
+            final ExtendedType innerExtendedType, final String basePackageName, final String moduleName) {
         Preconditions.checkArgument(innerExtendedType != null, "Extended type cannot be NULL!");
         Preconditions.checkArgument(basePackageName != null, "String with base package name cannot be NULL!");
 
         final String typedefName = typedef.getQName().getLocalName();
-        final String classTypedefName = parseToClassName(typedefName);
+        final String classTypedefName = BindingMapping.getClassName(typedefName);
         final String innerTypeDef = innerExtendedType.getQName().getLocalName();
-        final GeneratedTOBuilder genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, classTypedefName);
+        final GeneratedTOBuilderImpl genTOBuilder = new GeneratedTOBuilderImpl(basePackageName, classTypedefName);
+
+        genTOBuilder.setDescription(typedef.getDescription());
+        genTOBuilder.setReference(typedef.getReference());
+        genTOBuilder.setSchemaPath(typedef.getPath().getPathFromRoot());
+        genTOBuilder.setModuleName(moduleName);
         genTOBuilder.setTypedef(true);
         Restrictions r = BindingGeneratorUtil.getRestrictions(typedef);
         genTOBuilder.setRestrictions(r);
@@ -1150,10 +1245,25 @@ public final class TypeProviderImpl implements TypeProvider {
             }
         }
         addUnitsToGenTO(genTOBuilder, typedef.getUnits());
+        makeSerializable(genTOBuilder);
 
         return genTOBuilder.toInstance();
     }
 
+    /**
+     * Add {@link Serializable} to implemented interfaces of this TO. Also
+     * compute and add serialVersionUID property.
+     *
+     * @param gto
+     *            transfer object which needs to be serializable
+     */
+    private void makeSerializable(final GeneratedTOBuilderImpl gto) {
+        gto.addImplementsType(Types.typeForClass(Serializable.class));
+        GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("serialVersionUID");
+        prop.setValue(Long.toString(BindingGeneratorUtil.computeDefaultSUID(gto)));
+        gto.setSUID(prop);
+    }
+
     /**
      * Finds out for each type definition how many immersion (depth) is
      * necessary to get to the base type. Every type definition is inserted to
@@ -1182,10 +1292,10 @@ public final class TypeProviderImpl implements TypeProvider {
             }
             typeDefinitionsConcreteDepth.add(unsortedTypeDefinition);
         }
-        // keys are in ascending order
-        Set<Integer> depths = typeDefinitionsDepths.keySet();
-        for (Integer depth : depths) {
-            sortedTypeDefinition.addAll(typeDefinitionsDepths.get(depth));
+
+        // SortedMap guarantees order corresponding to keys in ascending order
+        for (List<TypeDefinition<?>> v : typeDefinitionsDepths.values()) {
+            sortedTypeDefinition.addAll(v);
         }
 
         return sortedTypeDefinition;
@@ -1233,9 +1343,8 @@ public final class TypeProviderImpl implements TypeProvider {
      *            string with name of augmented node
      * @return string with the number suffix incremented by one (or 1 is added)
      */
-    private String provideAvailableNameForGenTOBuilder(String name) {
-        Pattern searchedPattern = Pattern.compile("[0-9]+\\z");
-        Matcher mtch = searchedPattern.matcher(name);
+    private String provideAvailableNameForGenTOBuilder(final String name) {
+        Matcher mtch = NUMBERS_PATTERN.matcher(name);
         if (mtch.find()) {
             final int newSuffix = Integer.valueOf(name.substring(mtch.start())) + 1;
             return name.substring(0, mtch.start()) + newSuffix;
@@ -1244,7 +1353,7 @@ public final class TypeProviderImpl implements TypeProvider {
         }
     }
 
-    private void addUnitsToGenTO(GeneratedTOBuilder to, String units) {
+    public void addUnitsToGenTO(final GeneratedTOBuilder to, final String units) {
         if (units != null && !units.isEmpty()) {
             to.addConstant(Types.STRING, "_UNITS", "\"" + units + "\"");
             GeneratedPropertyBuilder prop = new GeneratedPropertyBuilderImpl("UNITS");
@@ -1254,11 +1363,11 @@ public final class TypeProviderImpl implements TypeProvider {
     }
 
     @Override
-    public String getTypeDefaultConstruction(LeafSchemaNode node) {
+    public String getTypeDefaultConstruction(final LeafSchemaNode node) {
         return getTypeDefaultConstruction(node, node.getDefault());
     }
 
-    public String getTypeDefaultConstruction(LeafSchemaNode node, String defaultValue) {
+    public String getTypeDefaultConstruction(final LeafSchemaNode node, final String defaultValue) {
         TypeDefinition<?> type = node.getType();
         QName typeQName = type.getQName();
         TypeDefinition<?> base = baseTypeDefForExtendedType(type);
@@ -1273,17 +1382,18 @@ public final class TypeProviderImpl implements TypeProvider {
         } else if (base instanceof BitsTypeDefinition) {
             String parentName;
             String className;
-            YangNode parent = node.getParent();
-            if (parent instanceof Module) {
-                parentName = parseToClassName(((Module) parent).getName()) + "Data";
-                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName((Module) parent);
-                className = basePackageName + "." + parentName + "." + parseToClassName(node.getQName().getLocalName());
+            Module parent = getParentModule(node);
+            Iterator<QName> path = node.getPath().getPathFromRoot().iterator();
+            path.next();
+            if (!(path.hasNext())) {
+                parentName = BindingMapping.getClassName(parent.getName()) + "Data";
+                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parent);
+                className = basePackageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
             } else {
-                Module parentModule = getParentModule(node);
-                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parentModule);
+                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parent);
                 String packageName = packageNameForGeneratedType(basePackageName, type.getPath());
-                parentName = parseToClassName(((SchemaNode) parent).getQName().getLocalName());
-                className = packageName + "." + parentName + "." + parseToClassName(node.getQName().getLocalName());
+                parentName = BindingMapping.getClassName(parent.getName());
+                className = packageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
             }
             result = bitsToDef((BitsTypeDefinition) base, className, defaultValue, type instanceof ExtendedType);
         } else if (base instanceof BooleanTypeDefinition) {
@@ -1299,16 +1409,15 @@ public final class TypeProviderImpl implements TypeProvider {
             String newDefVal = new String(defValArray);
             String className;
             if (type instanceof ExtendedType) {
-                QName qname = type.getPath().getPath().get(0);
-                Module m = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
+                Module m = getParentModule(type);
                 String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(m);
                 String packageName = packageNameForGeneratedType(basePackageName, type.getPath());
-                className = packageName + "." + parseToClassName(typeQName.getLocalName());
+                className = packageName + "." + BindingMapping.getClassName(typeQName);
             } else {
                 Module parentModule = getParentModule(node);
                 String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parentModule);
                 String packageName = packageNameForGeneratedType(basePackageName, node.getPath());
-                className = packageName + "." + parseToClassName(node.getQName().getLocalName());
+                className = packageName + "." + BindingMapping.getClassName(node.getQName());
             }
             result = className + "." + newDefVal;
         } else if (base instanceof IdentityrefTypeDefinition) {
@@ -1324,7 +1433,7 @@ public final class TypeProviderImpl implements TypeProvider {
         } else if (base instanceof Int64) {
             result = typeToDef(Long.class, defaultValue);
         } else if (base instanceof LeafrefTypeDefinition) {
-            result = leafrefToDef(node, (LeafrefTypeDefinition) base);
+            result = leafrefToDef(node, (LeafrefTypeDefinition) base, defaultValue);
         } else if (base instanceof StringTypeDefinition) {
             result = "\"" + defaultValue + "\"";
         } else if (base instanceof Uint8) {
@@ -1336,30 +1445,30 @@ public final class TypeProviderImpl implements TypeProvider {
         } else if (base instanceof Uint64) {
             result = typeToDef(BigInteger.class, defaultValue);
         } else if (base instanceof UnionTypeDefinition) {
-            throw new UnsupportedOperationException("Cannot get default construction for union type");
+            result = unionToDef(node);
         } else {
             result = "";
         }
         sb.append(result);
 
-        if (type instanceof ExtendedType && !(base instanceof LeafrefTypeDefinition)) {
-            QName qname = type.getPath().getPath().get(0);
-            Module m = schemaContext.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
+        if (type instanceof ExtendedType && !(base instanceof LeafrefTypeDefinition)
+                && !(base instanceof EnumerationType) && !(base instanceof UnionTypeDefinition)) {
+            Module m = getParentModule(type);
             String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(m);
             String packageName = packageNameForGeneratedType(basePackageName, type.getPath());
-            String className = packageName + "." + parseToClassName(typeQName.getLocalName());
+            String className = packageName + "." + BindingMapping.getClassName(typeQName);
             sb.insert(0, "new " + className + "(");
-            sb.insert(sb.length(), ")");
+            sb.insert(sb.length(), ')');
         }
 
         return sb.toString();
     }
 
-    private String typeToDef(Class<?> clazz, String defaultValue) {
+    private String typeToDef(final Class<?> clazz, final String defaultValue) {
         return "new " + clazz.getName() + "(\"" + defaultValue + "\")";
     }
 
-    private String binaryToDef(String defaultValue) {
+    private String binaryToDef(final String defaultValue) {
         StringBuilder sb = new StringBuilder();
         BaseEncoding en = BaseEncoding.base64();
         byte[] encoded = en.decode(defaultValue);
@@ -1370,20 +1479,25 @@ public final class TypeProviderImpl implements TypeProvider {
                 sb.append(", ");
             }
         }
-        sb.append("}");
+        sb.append('}');
         return sb.toString();
     }
 
-    private String bitsToDef(BitsTypeDefinition type, String className, String defaultValue, boolean isExt) {
+    private String bitsToDef(final BitsTypeDefinition type, final String className, final String defaultValue,
+            final boolean isExt) {
         List<Bit> bits = new ArrayList<>(type.getBits());
         Collections.sort(bits, new Comparator<Bit>() {
             @Override
-            public int compare(Bit o1, Bit o2) {
+            public int compare(final Bit o1, final Bit o2) {
                 return o1.getName().compareTo(o2.getName());
             }
         });
         StringBuilder sb = new StringBuilder();
-        sb.append(isExt ? "" : "new " + className + "(");
+        if (!isExt) {
+            sb.append("new ");
+            sb.append(className);
+            sb.append('(');
+        }
         for (int i = 0; i < bits.size(); i++) {
             if (bits.get(i).getName().equals(defaultValue)) {
                 sb.append(true);
@@ -1394,37 +1508,20 @@ public final class TypeProviderImpl implements TypeProvider {
                 sb.append(", ");
             }
         }
-        sb.append(isExt ? "" : ")");
+        if (!isExt) {
+            sb.append(')');
+        }
         return sb.toString();
     }
 
-    private Module getParentModule(YangNode node) {
-        if (node instanceof Module) {
-            return (Module) node;
-        }
-
-        YangNode parent = null;
-        if (node instanceof DataSchemaNode) {
-            parent = ((DataSchemaNode) node).getParent();
-        } else if (node instanceof DataNodeContainer) {
-            parent = ((DataNodeContainer) node).getParent();
-        } else {
-            parent = null;
-        }
-
-        while (parent != null && !(parent instanceof Module)) {
-            if (parent instanceof DataSchemaNode) {
-                parent = ((DataSchemaNode) parent).getParent();
-            } else if (parent instanceof DataNodeContainer) {
-                parent = ((DataNodeContainer) parent).getParent();
-            } else {
-                parent = null;
-            }
-        }
-        return (Module) parent;
+    private Module getParentModule(final SchemaNode node) {
+        QName qname = node.getPath().getPathFromRoot().iterator().next();
+        URI namespace = qname.getNamespace();
+        Date revision = qname.getRevision();
+        return schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
     }
 
-    private String leafrefToDef(LeafSchemaNode parentNode, LeafrefTypeDefinition leafrefType) {
+    private String leafrefToDef(final LeafSchemaNode parentNode, final LeafrefTypeDefinition leafrefType, final String defaultValue) {
         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!");
@@ -1433,9 +1530,7 @@ public final class TypeProviderImpl implements TypeProvider {
         final String strXPath = xpath.toString();
 
         if (strXPath != null) {
-            if (strXPath.contains("[")) {
-                return "new java.lang.Object()";
-            } else {
+            if (strXPath.indexOf('[') == -1) {
                 final Module module = findParentModule(schemaContext, parentNode);
                 if (module != null) {
                     final SchemaNode dataNode;
@@ -1444,17 +1539,83 @@ public final class TypeProviderImpl implements TypeProvider {
                     } else {
                         dataNode = findDataSchemaNodeForRelativeXPath(schemaContext, module, parentNode, xpath);
                     }
-                    String result = getTypeDefaultConstruction((LeafSchemaNode) dataNode, parentNode.getDefault());
+                    String result = getTypeDefaultConstruction((LeafSchemaNode) dataNode, defaultValue);
                     return result;
                 }
+            } else {
+                return "new java.lang.Object()";
             }
         }
 
         return null;
     }
 
+    private String unionToDef(final LeafSchemaNode node) {
+        String parentName;
+        String className;
+
+        if (node.getType() instanceof ExtendedType) {
+            ExtendedType type = (ExtendedType) node.getType();
+            QName typeQName = type.getQName();
+            Module module = null;
+            Set<Module> modules = schemaContext.findModuleByNamespace(typeQName.getNamespace());
+            if (modules.size() > 1) {
+                for (Module m : modules) {
+                    if (m.getRevision().equals(typeQName.getRevision())) {
+                        module = m;
+                        break;
+                    }
+                }
+                if (module == null) {
+                    List<Module> modulesList = new ArrayList<>(modules);
+                    Collections.sort(modulesList, new Comparator<Module>() {
+                        @Override
+                        public int compare(final Module o1, final Module o2) {
+                            return o1.getRevision().compareTo(o2.getRevision());
+                        }
+                    });
+                    module = modulesList.get(0);
+                }
+            } else {
+                module = modules.iterator().next();
+            }
+
+            String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(module);
+            className = basePackageName + "." + BindingMapping.getClassName(typeQName);
+        } else {
+            Iterator<QName> path = node.getPath().getPathFromRoot().iterator();
+            QName first = path.next();
+            if (!(path.hasNext())) {
+                URI namespace = first.getNamespace();
+                Date revision = first.getRevision();
+                Module parent = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
+                parentName = BindingMapping.getClassName((parent).getName()) + "Data";
+                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parent);
+                className = basePackageName + "." + parentName + "." + BindingMapping.getClassName(node.getQName());
+            } else {
+                URI namespace = first.getNamespace();
+                Date revision = first.getRevision();
+                Module parentModule = schemaContext.findModuleByNamespaceAndRevision(namespace, revision);
+                String basePackageName = BindingGeneratorUtil.moduleNamespaceToPackageName(parentModule);
+                String packageName = packageNameForGeneratedType(basePackageName, node.getType().getPath());
+                className = packageName + "." + BindingMapping.getClassName(node.getQName());
+            }
+        }
+        return union(className, node.getDefault(), node);
+    }
+
+    private String union(final String className, final String defaultValue, final LeafSchemaNode node) {
+        StringBuilder sb = new StringBuilder();
+        sb.append("new ");
+        sb.append(className);
+        sb.append("(\"");
+        sb.append(defaultValue);
+        sb.append("\".toCharArray())");
+        return sb.toString();
+    }
+
     @Override
-    public String getConstructorPropertyName(SchemaNode node) {
+    public String getConstructorPropertyName(final SchemaNode node) {
         if (node instanceof TypeDefinition<?>) {
             return "value";
         } else {
@@ -1462,4 +1623,9 @@ public final class TypeProviderImpl implements TypeProvider {
         }
     }
 
+    @Override
+    public String getParamNameFromType(final TypeDefinition<?> type) {
+        return BindingMapping.getPropertyName(type.getQName().getLocalName());
+    }
+
 }