Fixed incorrect serialization of multiple nested UnionTypes. 23/14423/1
authorTomas Cere <tcere@cisco.com>
Wed, 21 Jan 2015 17:59:05 +0000 (18:59 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Fri, 23 Jan 2015 11:05:54 +0000 (11:05 +0000)
Change-Id: I2bf4153fc3b931fd6f80f2683b8abb47a1e12c7b
Signed-off-by: Tomas Cere <tcere@cisco.com>
(cherry picked from commit 134bc3f2bb1d71c55aad9014efde1a9a2d252e40)

code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/UnionTypeCodec.java
code-generator/binding-data-codec/src/main/java/org/opendaylight/yangtools/binding/data/codec/impl/ValueTypeCodec.java
code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/UnionTypeTest.java [new file with mode: 0644]
code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/TopLevelBuilder.java [new file with mode: 0644]
code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/UnionTestTypeBuilder.java [new file with mode: 0644]
code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-union-test.yang [new file with mode: 0644]

index f94673c28897baa1eb67d79b12ae18efdb14a017..ed8a2bc80ae37a632f03bb3024d5d129ed202c98 100644 (file)
@@ -16,9 +16,11 @@ import java.util.HashSet;
 import java.util.Set;
 import java.util.concurrent.Callable;
 
+import org.opendaylight.yangtools.concepts.Codec;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
+import org.opendaylight.yangtools.yang.model.util.UnionType;
 
 final class UnionTypeCodec extends ReflectionBasedCodec {
 
@@ -44,7 +46,7 @@ final class UnionTypeCodec extends ReflectionBasedCodec {
                     String methodName = "get" + BindingMapping.getClassName(subtype.getQName());
                     Method valueGetter = unionCls.getMethod(methodName);
                     Class<?> valueType = valueGetter.getReturnType();
-                    SchemaUnawareCodec valueCodec = ValueTypeCodec.getCodecFor(valueType, subtype);
+                    Codec<Object, Object> valueCodec = UnionTypeCodec.getCodecForType(valueType, subtype);
                     values.add(new UnionValueOptionContext(valueType,valueGetter, valueCodec));
                 }
                 return new UnionTypeCodec(unionCls, values);
@@ -52,6 +54,18 @@ final class UnionTypeCodec extends ReflectionBasedCodec {
         };
     }
 
+    private static Codec<Object, Object> getCodecForType(Class valueType, TypeDefinition subtype) {
+        if (subtype.getBaseType() instanceof UnionType) {
+            try {
+                return UnionTypeCodec.loader(valueType, (UnionType) subtype.getBaseType()).call();
+            } catch (final Exception e) {
+                throw new IllegalStateException("Could not construct Union Type Codec");
+            }
+        } else {
+            return ValueTypeCodec.getCodecFor(valueType, subtype);
+        }
+    }
+
     @Override
     public Object deserialize(final Object input) {
         try {
index d8536ee667e9aae07184f25f0e74bf943e72dd31..d327a468d54a1e40c9e1216f8be175cd460a2264 100644 (file)
@@ -97,7 +97,7 @@ abstract class ValueTypeCodec implements Codec<Object, Object> {
         while (rootType.getBaseType() != null) {
             rootType = rootType.getBaseType();
         }
-        if(rootType instanceof EmptyTypeDefinition) {
+        if (rootType instanceof EmptyTypeDefinition) {
             return EMPTY_CODEC;
         }
         return NOOP_CODEC;
diff --git a/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/UnionTypeTest.java b/code-generator/binding-data-codec/src/test/java/org/opendaylight/yangtools/binding/data/codec/test/UnionTypeTest.java
new file mode 100644 (file)
index 0000000..e519892
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.yangtools.binding.data.codec.test;
+
+import javassist.ClassPool;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.TopLevel;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.TopLevelBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.Wrapper;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121.WrapperBuilder;
+import org.opendaylight.yangtools.binding.data.codec.gen.impl.StreamWriterGenerator;
+import org.opendaylight.yangtools.binding.data.codec.impl.BindingNormalizedNodeCodecRegistry;
+import org.opendaylight.yangtools.sal.binding.generator.util.JavassistUtils;
+import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.data.impl.schema.builder.impl.ImmutableContainerNodeBuilder;
+
+public class UnionTypeTest extends AbstractBindingRuntimeTest {
+
+    private static final String testString = "testtesttest";
+
+    public static final QName WRAPPER_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:yangtools:test:union", "2015-01-21", "wrapper");
+    public static final QName WRAP_LEAF_QNAME = QName.create(WRAPPER_QNAME, "wrap");
+
+    private BindingNormalizedNodeCodecRegistry registry;
+
+    @Override
+    public void setup() {
+        super.setup();
+        JavassistUtils utils = JavassistUtils.forClassPool(ClassPool.getDefault());
+        registry = new BindingNormalizedNodeCodecRegistry(StreamWriterGenerator.create(utils));
+        registry.onBindingRuntimeContextUpdated(getRuntimeContext());
+    }
+
+    @Test
+    public void unionTest() {
+        TopLevel topLevel = TopLevelBuilder.getDefaultInstance(testString);
+        Wrapper wrapper = new WrapperBuilder().setWrap(topLevel).build();
+        NormalizedNode<?, ?> topLevelEntry = registry.toNormalizedNode(InstanceIdentifier.builder(Wrapper.class).build(), wrapper).getValue();
+
+        ContainerNode containerNode = ImmutableContainerNodeBuilder.create()
+                .withNodeIdentifier(new YangInstanceIdentifier.NodeIdentifier(WRAPPER_QNAME))
+                .withChild(ImmutableNodes.leafNode(WRAP_LEAF_QNAME, testString))
+                .build();
+        Assert.assertEquals(topLevelEntry, containerNode);
+    }
+}
diff --git a/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/TopLevelBuilder.java b/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/TopLevelBuilder.java
new file mode 100644 (file)
index 0000000..09d8e0d
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121;
+
+/**
+ * The purpose of generated class in src/main/java for Union types is to create new instances of unions from a string representation.
+ * In some cases it is very difficult to automate it since there can be unions such as (uint32 - uint16), or (string - uint32).
+ * The reason behind putting it under src/main/java is:
+ * This class is generated in form of a stub and needs to be finished by the user. This class is generated only once to prevent
+ * loss of user code.
+ */
+public class TopLevelBuilder {
+
+    public static TopLevel getDefaultInstance(java.lang.String defaultValue) {
+        if (defaultValue.length() <= 4) {
+            return new TopLevel(new NonUnionTestType(defaultValue));
+        }
+        else {
+            return new TopLevel(UnionTestTypeBuilder.getDefaultInstance(defaultValue));
+        }
+    }
+
+}
diff --git a/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/UnionTestTypeBuilder.java b/code-generator/binding-test-model/src/main/java/org/opendaylight/yang/gen/v1/urn/opendaylight/params/xml/ns/yang/yangtools/test/union/rev150121/UnionTestTypeBuilder.java
new file mode 100644 (file)
index 0000000..613f2dc
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * Copyright (c) 2015 Cisco Systems, Inc. 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.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.yangtools.test.union.rev150121;
+
+/**
+ * The purpose of generated class in src/main/java for Union types is to create new instances of unions from a string representation.
+ * In some cases it is very difficult to automate it since there can be unions such as (uint32 - uint16), or (string - uint32).
+ * 
+ * The reason behind putting it under src/main/java is:
+ * This class is generated in form of a stub and needs to be finished by the user. This class is generated only once to prevent
+ * loss of user code.
+ * 
+ */
+public class UnionTestTypeBuilder {
+
+    public static UnionTestType getDefaultInstance(java.lang.String defaultValue) {
+        if (defaultValue.length() > 8) {
+            return new UnionTestType(new LowestLevel1(defaultValue));
+        } else {
+            return new UnionTestType(new LowestLevel2(defaultValue));
+        }
+    }
+
+}
diff --git a/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-union-test.yang b/code-generator/binding-test-model/src/main/yang/opendaylight-yangtools-union-test.yang
new file mode 100644 (file)
index 0000000..eea063b
--- /dev/null
@@ -0,0 +1,47 @@
+module opendaylight-yangtools-union-test {
+
+    namespace "urn:opendaylight:params:xml:ns:yang:yangtools:test:union";
+    prefix union-test;
+
+
+    description
+        "This module contains a collection of YANG definitions used for
+        some test cases.";
+
+    revision "2015-01-21" {
+        description
+        "Test model for testing union data types.";
+    }
+
+    typedef lowest-level1 {
+        type string;
+    }
+
+    typedef lowest-level2 {
+        type string;
+    }
+
+    typedef non-union-test-type {
+        type string;
+    }
+
+    typedef union-test-type {
+        type union {
+            type lowest-level1;
+            type lowest-level2;
+        }
+    }
+
+    typedef top-level {
+        type union {
+            type non-union-test-type;
+            type union-test-type;
+        }
+    }
+
+    container wrapper {
+        leaf wrap {
+            type top-level;
+        }
+    }
+}
\ No newline at end of file