Rework inlined union generation 82/71682/8
authorRobert Varga <robert.varga@pantheon.tech>
Fri, 27 Jul 2018 19:32:04 +0000 (21:32 +0200)
committerRobert Varga <nite@hq.sk>
Sat, 28 Jul 2018 08:33:50 +0000 (08:33 +0000)
Unions internal to a leaf union end up being incompletely generated,
as they lack stringValue(), hashCode(), equals() and do not correctly
bind to its enclosing builder -- leading to a generated code not being
compilable.

There are multiple issues here, all of which are addressed in this patch:
- hashCode/equals properties are created in the wrong place
- property return type is set to the builder, not its product
- union builder type is not set as a union
- builders for nested types are not correctly emitted
- Class/InterfaceTemplate use different logic to emit the inner classes

JIRA: MDSAL-320
Change-Id: I626fb4ac42ae6528bc98b809bc33756e8daa08b9
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
13 files changed:
binding/mdsal-binding-generator-api/src/main/java/org/opendaylight/mdsal/binding/model/api/type/builder/GeneratedTOBuilder.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/generator/impl/AbstractTypeGenerator.java
binding/mdsal-binding-generator-impl/src/main/java/org/opendaylight/mdsal/binding/yang/types/AbstractTypeProvider.java
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal320Test.java [new file with mode: 0644]
binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal324Test.java
binding/mdsal-binding-generator-impl/src/test/resources/mdsal320.yang [new file with mode: 0644]
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/AbstractGeneratedTOBuilder.java
binding/mdsal-binding-generator-util/src/main/java/org/opendaylight/mdsal/binding/model/util/generated/type/builder/CodegenGeneratedTOBuilder.java
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/BaseTemplate.xtend
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/ClassTemplate.xtend
binding/mdsal-binding-java-api-generator/src/main/java/org/opendaylight/mdsal/binding/java/api/generator/InterfaceTemplate.xtend
binding/mdsal-binding-java-api-generator/src/test/java/org/opendaylight/mdsal/binding/java/api/generator/test/CompilationTest.java
binding/mdsal-binding-java-api-generator/src/test/resources/compilation/mdsal320/mdsal320.yang [new file with mode: 0644]

index 277ca1f798490cca3fb3b74f9683e27e9bfbe8bc..a604022987f0396f7d49bd1055f8bb27d13e6058 100644 (file)
@@ -90,6 +90,8 @@ public interface GeneratedTOBuilder extends GeneratedTypeBuilderBase<GeneratedTO
      */
     void setBaseType(TypeDefinition<?> typeDef);
 
+    boolean isUnion();
+
     /**
      *
      * @param isUnion
index 06d57f2544793321f4a57b4c4e7fceb8604c2b23..fd242571c98be016cd93b538cd86cf9ce8be6c7c 100644 (file)
@@ -1378,13 +1378,10 @@ abstract class AbstractTypeGenerator {
                 }
                 typeProvider.putReferencedType(leaf.getPath(), returnType);
             } else if (typeDef instanceof UnionTypeDefinition) {
-                GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((UnionTypeDefinition) typeDef, typeBuilder, leaf,
-                    parentModule);
-                if (genTOBuilder != null) {
-                    returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
-                    // Store the inner type within the union so that we can find the reference for it
-                    context.addInnerTypedefType(typeDef.getPath(), returnType);
-                }
+                final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef;
+                returnType = addTOToTypeBuilder(unionDef, typeBuilder, leaf, parentModule);
+                // Store the inner type within the union so that we can find the reference for it
+                context.addInnerTypedefType(typeDef.getPath(), returnType);
             } else if (typeDef instanceof BitsTypeDefinition) {
                 GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((BitsTypeDefinition) typeDef, typeBuilder, leaf,
                     parentModule);
@@ -1587,11 +1584,8 @@ abstract class AbstractTypeGenerator {
                 returnType = new ReferencedTypeImpl(enumBuilder.getIdentifier());
                 typeProvider.putReferencedType(node.getPath(), returnType);
             } else if (typeDef instanceof UnionTypeDefinition) {
-                final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((UnionTypeDefinition)typeDef, typeBuilder,
-                    node, parentModule);
-                if (genTOBuilder != null) {
-                    returnType = createReturnTypeForUnion(genTOBuilder, typeDef, typeBuilder, parentModule);
-                }
+                final UnionTypeDefinition unionDef = (UnionTypeDefinition)typeDef;
+                returnType = addTOToTypeBuilder(unionDef, typeBuilder, node, parentModule);
             } else if (typeDef instanceof BitsTypeDefinition) {
                 final GeneratedTOBuilder genTOBuilder = addTOToTypeBuilder((BitsTypeDefinition)typeDef, typeBuilder,
                     node, parentModule);
@@ -1612,22 +1606,31 @@ abstract class AbstractTypeGenerator {
         return true;
     }
 
-    private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final TypeDefinition<?> typeDef,
+    private Type createReturnTypeForUnion(final GeneratedTOBuilder genTOBuilder, final UnionTypeDefinition typeDef,
             final GeneratedTypeBuilder typeBuilder, final Module parentModule) {
-        final GeneratedTOBuilder returnType = typeProvider.newGeneratedTOBuilder(genTOBuilder.getIdentifier());
-
-        addCodegenInformation(returnType, parentModule, typeDef);
-        returnType.setSchemaPath(typeDef.getPath());
-        returnType.setModuleName(parentModule.getName());
+        final GeneratedTOBuilder returnTypeBuilder = typeProvider.newGeneratedTOBuilder(genTOBuilder.getIdentifier());
+        returnTypeBuilder.setIsUnion(true);
+        addCodegenInformation(returnTypeBuilder, parentModule, typeDef);
+        returnTypeBuilder.setSchemaPath(typeDef.getPath());
+        returnTypeBuilder.setModuleName(parentModule.getName());
+        final GeneratedTransferObject returnType = returnTypeBuilder.build();
 
         genTOBuilder.setTypedef(true);
         genTOBuilder.setIsUnion(true);
         AbstractTypeProvider.addUnitsToGenTO(genTOBuilder, typeDef.getUnits().orElse(null));
 
+        createUnionBuilder(genTOBuilder, typeBuilder, returnType, parentModule);
+        return returnType;
+    }
 
-
-        final GeneratedTOBuilder unionBuilder = createUnionBuilder(genTOBuilder, typeBuilder);
-
+    private void createUnionBuilder(final GeneratedTOBuilder genTOBuilder, final GeneratedTypeBuilder typeBuilder,
+            final GeneratedTransferObject returnType, final Module parentModule) {
+        // Append enclosing path hierarchy without dots
+        final StringBuilder sb = new StringBuilder();
+        genTOBuilder.getIdentifier().localNameComponents().forEach(sb::append);
+        final GeneratedTOBuilder unionBuilder = typeProvider.newGeneratedTOBuilder(
+            JavaTypeName.create(typeBuilder.getPackageName(), sb.append("Builder").toString()));
+        unionBuilder.setIsUnionBuilder(true);
 
         final MethodSignatureBuilder method = unionBuilder.addMethod("getDefaultInstance");
         method.setReturnType(returnType);
@@ -1635,25 +1638,13 @@ abstract class AbstractTypeGenerator {
         method.setAccessModifier(AccessModifier.PUBLIC);
         method.setStatic(true);
 
+        final GeneratedTransferObject unionBuilderType = unionBuilder.build();
         final Set<Type> types = typeProvider.getAdditionalTypes().get(parentModule);
         if (types == null) {
-            typeProvider.getAdditionalTypes().put(parentModule,
-                    Sets.newHashSet(unionBuilder.build()));
+            typeProvider.getAdditionalTypes().put(parentModule, Sets.newHashSet(unionBuilderType));
         } else {
-            types.add(unionBuilder.build());
+            types.add(unionBuilderType);
         }
-        return returnType.build();
-    }
-
-    private GeneratedTOBuilder createUnionBuilder(final GeneratedTOBuilder genTOBuilder,
-            final GeneratedTypeBuilder typeBuilder) {
-        // Append enclosing path hierarchy without dots
-        final StringBuilder sb = new StringBuilder();
-        genTOBuilder.getIdentifier().localNameComponents().forEach(sb::append);
-        final GeneratedTOBuilder unionBuilder = typeProvider.newGeneratedTOBuilder(
-            JavaTypeName.create(typeBuilder.getPackageName(), sb.append("Builder").toString()));
-        unionBuilder.setIsUnionBuilder(true);
-        return unionBuilder;
     }
 
     private GeneratedTypeBuilder addDefaultInterfaceDefinition(final ModuleContext context,
@@ -1667,7 +1658,6 @@ abstract class AbstractTypeGenerator {
         return addDefaultInterfaceDefinition(packageName, schemaNode, baseInterface, context);
     }
 
-
     /**
      * Instantiates generated type builder with <code>packageName</code> and
      * <code>schemaNode</code>.
@@ -1967,7 +1957,7 @@ abstract class AbstractTypeGenerator {
      *            parent module
      * @return generated TO builder for <code>typeDef</code>
      */
-    private GeneratedTOBuilder addTOToTypeBuilder(final UnionTypeDefinition typeDef,
+    private Type addTOToTypeBuilder(final UnionTypeDefinition typeDef,
             final GeneratedTypeBuilder typeBuilder, final DataSchemaNode leaf, final Module parentModule) {
         final List<GeneratedTOBuilder> types = typeProvider.provideGeneratedTOBuildersForUnionTypeDef(
             typeBuilder.getIdentifier().createEnclosed(BindingMapping.getClassName(leaf.getQName())),
@@ -1976,12 +1966,17 @@ abstract class AbstractTypeGenerator {
         checkState(!types.isEmpty(), "No GeneratedTOBuilder objects generated from union %s", typeDef);
         final List<GeneratedTOBuilder> genTOBuilders = new ArrayList<>(types);
         final GeneratedTOBuilder resultTOBuilder = types.remove(0);
-        for (final GeneratedTOBuilder genTOBuilder : types) {
-            resultTOBuilder.addEnclosingTransferObject(genTOBuilder);
+        types.forEach(resultTOBuilder::addEnclosingTransferObject);
+        genTOBuilders.forEach(typeBuilder::addEnclosingTransferObject);
+
+        for (GeneratedTOBuilder builder : types) {
+            if (builder.isUnion()) {
+                final GeneratedTransferObject type = builder.build();
+                createUnionBuilder(builder, typeBuilder, type, parentModule);
+            }
         }
 
-        processEnclosedTOBuilderes(typeBuilder, genTOBuilders);
-        return resultTOBuilder;
+        return createReturnTypeForUnion(resultTOBuilder, typeDef, typeBuilder, parentModule);
     }
 
     /**
@@ -2014,14 +2009,6 @@ abstract class AbstractTypeGenerator {
 
     }
 
-    private static GeneratedTOBuilder processEnclosedTOBuilderes(final GeneratedTypeBuilder typeBuilder,
-            final List<GeneratedTOBuilder> genTOBuilders) {
-        for (final GeneratedTOBuilder genTOBuilder : genTOBuilders) {
-            typeBuilder.addEnclosingTransferObject(genTOBuilder);
-        }
-        return genTOBuilders.get(0);
-    }
-
     /**
      * Adds the implemented types to type builder.
      *
index 11a0e726de8596e23fa7c0fad2c124438e6ba2a7..1e990f5206d360383f2ad5f8ca1588a9e2774381 100644 (file)
@@ -898,11 +898,10 @@ public abstract class AbstractTypeProvider implements TypeProvider {
     private GeneratedTransferObject wrapJavaTypeIntoTO(final String basePackageName, final TypeDefinition<?> typedef,
             final Type javaType, final String moduleName) {
         Preconditions.checkNotNull(javaType, "javaType cannot be null");
-        final String propertyName = "value";
 
         final GeneratedTOBuilder genTOBuilder = typedefToTransferObject(basePackageName, typedef, moduleName);
         genTOBuilder.setRestrictions(BindingGeneratorUtil.getRestrictions(typedef));
-        final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty(propertyName);
+        final GeneratedPropertyBuilder genPropBuilder = genTOBuilder.addProperty("value");
         genPropBuilder.setReturnType(javaType);
         genTOBuilder.addEqualsIdentity(genPropBuilder);
         genTOBuilder.addHashIdentity(genPropBuilder);
@@ -965,12 +964,11 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         final Module module = findParentModule(schemaContext, parentNode);
 
         final GeneratedTOBuilder unionGenTOBuilder = newGeneratedTOBuilder(typeName);
+        unionGenTOBuilder.setIsUnion(true);
         unionGenTOBuilder.setSchemaPath(typedef.getPath());
         unionGenTOBuilder.setModuleName(module.getName());
         addCodegenInformation(unionGenTOBuilder, typedef);
-
         generatedTOBuilders.add(unionGenTOBuilder);
-        unionGenTOBuilder.setIsUnion(true);
 
         // Pattern string is the key, XSD regex is the value. The reason for this choice is that the pattern carries
         // also negation information and hence guarantees uniqueness.
@@ -1030,7 +1028,7 @@ public abstract class AbstractTypeProvider implements TypeProvider {
         final GeneratedPropertyBuilder propertyBuilder;
         propertyBuilder = parentUnionGenTOBuilder.addProperty(BindingMapping.getPropertyName(
             newTOBuilderName.simpleName()));
-        propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0));
+        propertyBuilder.setReturnType(subUnionGenTOBUilders.get(0).build());
         parentUnionGenTOBuilder.addEqualsIdentity(propertyBuilder);
         parentUnionGenTOBuilder.addToStringProperty(propertyBuilder);
 
diff --git a/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal320Test.java b/binding/mdsal-binding-generator-impl/src/test/java/org/opendaylight/mdsal/binding/generator/impl/Mdsal320Test.java
new file mode 100644 (file)
index 0000000..1bc3931
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2018 Pantheon Technologies, s.r.o. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.mdsal.binding.generator.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import com.google.common.collect.Iterables;
+import java.util.List;
+import org.junit.Test;
+import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
+import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.opendaylight.yangtools.yang.test.util.YangParserTestUtils;
+
+public class Mdsal320Test {
+
+    @Test
+    public void mdsal320Test() {
+        final SchemaContext context = YangParserTestUtils.parseYangResource("/mdsal320.yang");
+
+        final List<Type> generateTypes = new BindingGeneratorImpl().generateTypes(context);
+        assertNotNull(generateTypes);
+        assertEquals(4, generateTypes.size());
+
+        final Type fooType = generateTypes.stream().filter(type -> type.getFullyQualifiedName()
+            .equals("org.opendaylight.yang.gen.v1.urn.odl.yt320.norev.Foo")).findFirst().get();
+        assertTrue(fooType instanceof GeneratedType);
+        final GeneratedType foo = (GeneratedType) fooType;
+
+        GeneratedTransferObject bar = null;
+        GeneratedTransferObject bar1 = null;
+        for (GeneratedType enc : foo.getEnclosedTypes()) {
+            switch (enc.getName()) {
+                case "Bar":
+                    assertTrue(enc instanceof GeneratedTransferObject);
+                    bar = (GeneratedTransferObject) enc;
+                    break;
+                case "Bar$1":
+                    assertTrue(enc instanceof GeneratedTransferObject);
+                    bar1 = (GeneratedTransferObject) enc;
+                    break;
+                default:
+                    throw new IllegalStateException("Unexpected type " + enc);
+            }
+        }
+        assertNotNull(bar);
+        assertTrue(bar.isUnionType());
+        assertNotNull(bar1);
+        assertTrue(bar1.isUnionType());
+
+        final MethodSignature getBar = Iterables.getOnlyElement(foo.getMethodDefinitions());
+        final Type getBarType = getBar.getReturnType();
+        assertTrue(getBarType instanceof GeneratedTransferObject);
+        final GeneratedTransferObject getBarTO = (GeneratedTransferObject) getBarType;
+        assertTrue(getBarTO.isUnionType());
+        assertEquals(bar, getBarTO);
+
+        final GeneratedProperty bar1Prop = bar.getProperties().stream().filter(prop -> "bar$1".equals(prop.getName()))
+                .findFirst().get();
+        final Type bar1PropRet = bar1Prop.getReturnType();
+        assertEquals(bar1, bar1PropRet);
+    }
+}
index c5b5aabc3827b90e04596af2cf45caf44cc989f3..914f57f8c235917a319a19674a60830a08df12bd 100644 (file)
@@ -23,6 +23,6 @@ public class Mdsal324Test {
         final SchemaContext context = YangParserTestUtils.parseYangResource("/mdsal324.yang");
         final List<Type> generateTypes = new BindingGeneratorImpl().generateTypes(context);
         assertNotNull(generateTypes);
-        assertEquals(4, generateTypes.size());
+        assertEquals(6, generateTypes.size());
     }
 }
diff --git a/binding/mdsal-binding-generator-impl/src/test/resources/mdsal320.yang b/binding/mdsal-binding-generator-impl/src/test/resources/mdsal320.yang
new file mode 100644 (file)
index 0000000..3c1f66c
--- /dev/null
@@ -0,0 +1,26 @@
+module yt320 {
+    namespace "urn:odl:yt320";
+    prefix yt320;
+
+    container foo {
+        leaf bar {
+            type union {
+                type enumeration {
+                    enum "foo";
+                }
+                type string {
+                    length 2;
+                }
+                type union {
+                    type enumeration {
+                        enum bar;
+                    }
+                    type string {
+                        length 1;
+                    }
+                }
+            }
+        }
+    }
+}
+
index c6786ece75d0181695e3e145413ad7ff92558220..fb2378cef1dccc68ab70c33029ab400eceda4a1d 100644 (file)
@@ -12,9 +12,9 @@ import java.util.Collections;
 import java.util.List;
 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
 import org.opendaylight.mdsal.binding.model.api.Type;
-import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTOBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
@@ -132,6 +132,11 @@ abstract class AbstractGeneratedTOBuilder extends AbstractGeneratedTypeBuilder<G
         this.isUnionType = isUnion;
     }
 
+    @Override
+    public final boolean isUnion() {
+        return isUnionType;
+    }
+
     @Override
     public final void setIsUnionBuilder(final boolean isUnionTypeBuilder) {
         this.isUnionTypeBuilder = isUnionTypeBuilder;
index 798142e3a0e5e5ec787a06b1e8eee8f647ab18c2..36cd6d2c201f106cc1fa2c5e1aef9ddcf6357335 100644 (file)
@@ -9,8 +9,8 @@ package org.opendaylight.mdsal.binding.model.util.generated.type.builder;
 
 import org.opendaylight.mdsal.binding.model.api.GeneratedProperty;
 import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject;
-import org.opendaylight.mdsal.binding.model.api.Restrictions;
 import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.model.api.Restrictions;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@@ -76,7 +76,7 @@ public final class CodegenGeneratedTOBuilder extends AbstractGeneratedTOBuilder
         private final String moduleName;
         private final SchemaPath schemaPath;
 
-        public GTO(final CodegenGeneratedTOBuilder builder) {
+        GTO(final CodegenGeneratedTOBuilder builder) {
             super(builder);
             this.restrictions = builder.restrictions;
             this.reference = builder.reference;
index 403f5ebfefde246f64a92e18760d20cea5c360bd..d8d40a575a14faf2b04d807d8345ff941efadafb 100644 (file)
@@ -487,6 +487,17 @@ abstract class BaseTemplate extends JavaFileTemplate {
         return actualType.restrictions;
     }
 
+    def protected generateInnerClass(GeneratedType innerClass) '''
+        «IF innerClass instanceof GeneratedTransferObject»
+            «val innerJavaType = javaType.getEnclosedType(innerClass.identifier)»
+            «IF innerClass.unionType»
+                «new UnionTemplate(innerJavaType, innerClass).generateAsInnerClass»
+            «ELSE»
+                «new ClassTemplate(innerJavaType, innerClass).generateAsInnerClass»
+            «ENDIF»
+        «ENDIF»
+    '''
+
     def static Restrictions getRestrictions(Type type) {
         if (type instanceof ConcreteType) {
             return type.restrictions
index 7c713e101611609a97eef9c09b1c0c769e9c232c..e34952a04c36b23d4841a441a3fc226922f435a8 100644 (file)
@@ -184,9 +184,7 @@ class ClassTemplate extends BaseTemplate {
     def protected innerClassesDeclarations() '''
         «IF !type.enclosedTypes.empty»
             «FOR innerClass : type.enclosedTypes SEPARATOR "\n"»
-                «IF (innerClass instanceof GeneratedTransferObject)»
-                    «new ClassTemplate(javaType.getEnclosedType(innerClass.identifier), innerClass).generateAsInnerClass»
-                «ENDIF»
+                «generateInnerClass(innerClass)»
             «ENDFOR»
         «ENDIF»
     '''
index 81bd8067577270ed14680aa7c5f486c88cd4a8f3..ba99afceaa2f367773d2b89597c94f90dba19499 100644 (file)
@@ -11,7 +11,6 @@ import java.util.List
 import org.opendaylight.mdsal.binding.model.api.AnnotationType
 import org.opendaylight.mdsal.binding.model.api.Constant
 import org.opendaylight.mdsal.binding.model.api.Enumeration
-import org.opendaylight.mdsal.binding.model.api.GeneratedTransferObject
 import org.opendaylight.mdsal.binding.model.api.GeneratedType
 import org.opendaylight.mdsal.binding.model.api.MethodSignature
 import org.opendaylight.mdsal.binding.model.util.TypeConstants
@@ -122,17 +121,7 @@ class InterfaceTemplate extends BaseTemplate {
     def private generateInnerClasses() '''
         «IF !enclosedGeneratedTypes.empty»
             «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
-                «IF (innerClass instanceof GeneratedTransferObject)»
-                    «val innerJavaType = javaType.getEnclosedType(innerClass.identifier)»
-                    «IF innerClass.unionType»
-                        «val unionTemplate = new UnionTemplate(innerJavaType, innerClass)»
-                        «unionTemplate.generateAsInnerClass»
-                    «ELSE»
-                        «val classTemplate = new ClassTemplate(innerJavaType, innerClass)»
-                        «classTemplate.generateAsInnerClass»
-                    «ENDIF»
-
-                «ENDIF»
+                «generateInnerClass(innerClass)»
             «ENDFOR»
         «ENDIF»
     '''
index 540397e12f399dd604907384da26e2b344cffe4a..344962e2e54064d649a063446c6375606e7dfbee 100644 (file)
@@ -656,6 +656,15 @@ public class CompilationTest extends BaseCompilationTest {
         CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
     }
 
+    @Test
+    public void twoNestedUnionsTest() throws Exception {
+        final File sourcesOutputDir = CompilationTestUtils.generatorOutput("mdsal320");
+        final File compiledOutputDir = CompilationTestUtils.compilerOutput("mdsal320");
+        generateTestSources("/compilation/mdsal320", sourcesOutputDir);
+        CompilationTestUtils.testCompilation(sourcesOutputDir, compiledOutputDir);
+        CompilationTestUtils.cleanUp(sourcesOutputDir, compiledOutputDir);
+    }
+
     private static void testReturnTypeIdentityref(final Class<?> clazz, final String methodName,
             final String returnTypeStr) throws NoSuchMethodException {
         Method method = clazz.getMethod(methodName);
diff --git a/binding/mdsal-binding-java-api-generator/src/test/resources/compilation/mdsal320/mdsal320.yang b/binding/mdsal-binding-java-api-generator/src/test/resources/compilation/mdsal320/mdsal320.yang
new file mode 100644 (file)
index 0000000..3c1f66c
--- /dev/null
@@ -0,0 +1,26 @@
+module yt320 {
+    namespace "urn:odl:yt320";
+    prefix yt320;
+
+    container foo {
+        leaf bar {
+            type union {
+                type enumeration {
+                    enum "foo";
+                }
+                type string {
+                    length 2;
+                }
+                type union {
+                    type enumeration {
+                        enum bar;
+                    }
+                    type string {
+                        length 1;
+                    }
+                }
+            }
+        }
+    }
+}
+