} else {
throw new IllegalArgumentException("Unsupported leaf node type " + schema.getClass());
}
+ return getCodec(valueType, instantiatedType);
+ }
+
+ Codec<Object, Object> getCodec(final Class<?> valueType, final TypeDefinition<?> instantiatedType) {
if (Class.class.equals(valueType)) {
@SuppressWarnings({ "unchecked", "rawtypes" })
final Codec<Object, Object> casted = (Codec) identityCodec;
return ValueTypeCodec.EMPTY_CODEC;
}
} else if (BindingReflections.isBindingClass(valueType)) {
- return getCodec(valueType, instantiatedType);
+ return getCodecForBindingClass(valueType, instantiatedType);
}
return ValueTypeCodec.NOOP_CODEC;
}
- private Codec<Object, Object> getCodec(final Class<?> valueType, final TypeDefinition<?> instantiatedType) {
+ private Codec<Object, Object> getCodecForBindingClass(final Class<?> valueType, final TypeDefinition<?> instantiatedType) {
@SuppressWarnings("rawtypes")
TypeDefinition rootType = instantiatedType;
while (rootType.getBaseType() != null) {
} else if (rootType instanceof InstanceIdentifierTypeDefinition) {
return ValueTypeCodec.encapsulatedValueCodecFor(valueType, instanceIdentifierCodec);
} else if (rootType instanceof UnionTypeDefinition) {
- final Callable<UnionTypeCodec> loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType);
+ final Callable<UnionTypeCodec> loader = UnionTypeCodec.loader(valueType, (UnionTypeDefinition) rootType, this);
try {
return loader.call();
} catch (final Exception e) {
import com.google.common.collect.ImmutableSet;
import com.google.common.io.BaseEncoding;
+import com.google.common.util.concurrent.ExecutionError;
+import com.google.common.util.concurrent.UncheckedExecutionException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.Callable;
+import javax.annotation.Nullable;
import org.opendaylight.yangtools.concepts.Codec;
import org.opendaylight.yangtools.yang.binding.BindingMapping;
import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
final class UnionTypeCodec extends ReflectionBasedCodec {
+ private final Codec<Object, Object> identityrefCodec;
private final ImmutableSet<UnionValueOptionContext> typeCodecs;
private final Constructor<?> charConstructor;
- private UnionTypeCodec(final Class<?> unionCls,final Set<UnionValueOptionContext> codecs) {
+ private UnionTypeCodec(final Class<?> unionCls,final Set<UnionValueOptionContext> codecs,
+ @Nullable Codec<Object, Object> identityrefCodec) {
super(unionCls);
+ this.identityrefCodec = identityrefCodec;
try {
charConstructor = unionCls.getConstructor(char[].class);
typeCodecs = ImmutableSet.copyOf(codecs);
}
}
- static Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType) {
+ static Callable<UnionTypeCodec> loader(final Class<?> unionCls, final UnionTypeDefinition unionType,
+ BindingCodecContext bindingCodecContext) {
return new Callable<UnionTypeCodec>() {
@Override
public UnionTypeCodec call() throws NoSuchMethodException, SecurityException {
+ Codec<Object, Object> identityrefCodec = null;
Set<UnionValueOptionContext> values = new HashSet<>();
- for(TypeDefinition<?> subtype : unionType.getTypes()) {
+ for (TypeDefinition<?> subtype : unionType.getTypes()) {
String methodName = "get" + BindingMapping.getClassName(subtype.getQName());
Method valueGetter = unionCls.getMethod(methodName);
Class<?> valueType = valueGetter.getReturnType();
- Codec<Object, Object> valueCodec = UnionTypeCodec.getCodecForType(valueType, subtype);
+ Codec<Object, Object> valueCodec = bindingCodecContext.getCodec(valueType, subtype);
+ if (Class.class.equals(valueType)) {
+ identityrefCodec = valueCodec;
+ }
values.add(new UnionValueOptionContext(valueType,valueGetter, valueCodec));
}
- return new UnionTypeCodec(unionCls, values);
+ return new UnionTypeCodec(unionCls, values, identityrefCodec);
}
};
}
- private static Codec<Object, Object> getCodecForType(final Class<?> valueType, final TypeDefinition<?> subtype) {
- if (subtype.getBaseType() instanceof UnionTypeDefinition) {
+ @Override
+ public Object deserialize(final Object input) {
+ if (identityrefCodec != null) {
try {
- return UnionTypeCodec.loader(valueType, (UnionTypeDefinition) subtype.getBaseType()).call();
- } catch (final Exception e) {
- throw new IllegalStateException("Could not construct Union Type Codec");
+ Object identityref = identityrefCodec.deserialize(input);
+ return typeClass.getConstructor(Class.class).newInstance(identityref);
+ } catch (UncheckedExecutionException | ExecutionError e) {
+ // ignore this exception caused by deserialize()
+ } catch (NoSuchMethodException e) {
+ // caused by getContructor(). this case shouldn't happen.
+ throw new IllegalStateException("Could not construct instance", e);
+ } catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
+ // ignore this exception caused by newInstance()
}
- } else {
- return ValueTypeCodec.getCodecFor(valueType, subtype);
}
- }
-
- @Override
- public Object deserialize(final Object input) {
try {
if (input instanceof byte[]) {
return charConstructor.newInstance(BaseEncoding.base64().encode((byte[]) input).toCharArray());
--- /dev/null
+/*
+ * Copyright (c) 2016 Intel Corporation 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 static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Map.Entry;
+import javassist.ClassPool;
+import org.junit.Assert;
+import org.junit.Test;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.OpendaylightBug6006Data;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.UnionNode;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.UnionNodeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.UnionType;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.UnionTypeBuilder;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentOne;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentTwo;
+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.DataObject;
+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 UnionTypeWithIdentityrefTest extends AbstractBindingRuntimeTest {
+ private static final String identOneString = "IdentOne";
+ public static final QName NODE_QNAME = QName.create("urn:opendaylight:params:xml:ns:yang:mdsal:test:bug:6066", "2016-06-07", "union-node");
+ public static final QName NODE_LEAF_QNAME = QName.create(NODE_QNAME, "value");
+
+ 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 bug6006Test() {
+ UnionType unionType = UnionTypeBuilder.getDefaultInstance(identOneString);
+ UnionNode unionNode = new UnionNodeBuilder().setValue(unionType).build();
+ NormalizedNode<?, ?> normalizedUnionNode = registry
+ .toNormalizedNode(InstanceIdentifier.builder(UnionNode.class).build(), unionNode)
+ .getValue();
+
+ Entry<InstanceIdentifier<?>, DataObject> unionNodeEntry = registry.fromNormalizedNode(
+ YangInstanceIdentifier.of(normalizedUnionNode.getNodeType()), normalizedUnionNode);
+ DataObject unionNodeObj = unionNodeEntry.getValue();
+ assertTrue(unionNodeObj instanceof UnionNode);
+ UnionType unionTypeObj = ((UnionNode) unionNodeObj).getValue();
+ assertEquals(null, unionTypeObj.getUint8());
+ assertEquals(IdentOne.class, unionTypeObj.getIdentityref());
+ }
+}
--- /dev/null
+package org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607;
+
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentBase;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentOne;
+import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.mdsal.test.bug._6006.rev160607.IdentTwo;
+
+/**
+ * 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 UnionTypeBuilder {
+
+ public static UnionType getDefaultInstance(java.lang.String defaultValue) {
+ Class<? extends IdentBase> identityref = null;
+ if (defaultValue.equals("IdentOne")) {
+ return new UnionType(IdentOne.class);
+ }
+ if (defaultValue.equals("IdentTwo")) {
+ return new UnionType(IdentTwo.class);
+ }
+ throw new IllegalArgumentException("Unknown UnionType string " + defaultValue);
+ }
+
+}
--- /dev/null
+module opendaylight-bug-6006 {
+ namespace "urn:opendaylight:params:xml:ns:yang:mdsal:test:bug:6006";
+ prefix bug-6006-test;
+
+ description
+ "This module contains test case for bug 6006.
+ https://bugs.opendaylight.org/show_bug.cgi?id=6006";
+
+ revision "2016-06-07" {
+ description
+ "Test model for testing union data types.";
+ }
+
+ identity ident-base;
+ identity ident-one {
+ base ident-base;
+ }
+ identity ident-two {
+ base ident-base;
+ }
+
+ typedef union-type {
+ type union {
+ type uint8;
+ type identityref {
+ base ident-base;
+ }
+ }
+ }
+
+ container union-node {
+ leaf value {
+ type union-type;
+ }
+ }
+}