Bug 6006 - UnionTypeCodec fails to handle indentityref
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / yangtools / binding / data / codec / impl / UnionTypeCodec.java
index c483fe7f25cfa169b32e768dd718bdca9d6ec7fb..19f79fa2d120237df3e5abea2b119d11b30bf6ac 100644 (file)
@@ -9,12 +9,15 @@ package org.opendaylight.yangtools.binding.data.codec.impl;
 
 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;
@@ -22,11 +25,14 @@ import org.opendaylight.yangtools.yang.model.api.type.UnionTypeDefinition;
 
 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);
@@ -35,37 +41,43 @@ final class UnionTypeCodec extends ReflectionBasedCodec {
         }
     }
 
-    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());