BUG-6028: iterate over component types to instantiate union
[mdsal.git] / binding / mdsal-binding-dom-codec / src / main / java / org / opendaylight / yangtools / binding / data / codec / impl / UnionValueOptionContext.java
index 15ce5a33d8f03e7b3238d6348f7a137b97c50385..b53cd7e4cd8dd07408a6efaae9533211e86055d7 100644 (file)
@@ -14,14 +14,19 @@ import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Method;
 import org.opendaylight.yangtools.concepts.Codec;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 final class UnionValueOptionContext {
     private static final MethodType OBJECT_TYPE = MethodType.methodType(Object.class, Object.class);
+    private static final Logger LOG = LoggerFactory.getLogger(UnionValueOptionContext.class);
+
     private final Class<?> bindingType;
-    private final MethodHandle getter;
     private final Codec<Object,Object> codec;
+    private final MethodHandle getter;
+    private final MethodHandle unionCtor;
 
-    UnionValueOptionContext(final Class<?> valueType, final Method getter, final Codec<Object, Object> codec) {
+    UnionValueOptionContext(final Class<?> unionType, final Class<?> valueType, final Method getter, final Codec<Object, Object> codec) {
         this.bindingType = Preconditions.checkNotNull(valueType);
         this.codec = Preconditions.checkNotNull(codec);
 
@@ -30,15 +35,40 @@ final class UnionValueOptionContext {
         } catch (IllegalAccessException e) {
             throw new IllegalStateException("Failed to access method " + getter, e);
         }
+
+        try {
+            this.unionCtor = MethodHandles.publicLookup().findConstructor(unionType,
+                MethodType.methodType(void.class, valueType)).asType(OBJECT_TYPE);
+        } catch (IllegalAccessException | NoSuchMethodException e) {
+            throw new IllegalStateException(String.format("Failed to access constructor for %s in type %s", valueType,
+                    unionType), e);
+        }
     }
 
     Object serialize(final Object input) {
         final Object baValue = getValueFrom(input);
-        if (baValue == null) {
+        return baValue == null ? null : codec.serialize(baValue);
+    }
+
+    Object deserializeUnion(final Object input) {
+        final Object value;
+
+        try {
+            value = codec.deserialize(input);
+        } catch (Exception e) {
+            LOG.debug("Codec failed to deserialize input {}", input, e);
             return null;
         }
 
-        return codec.serialize(baValue);
+        try {
+            return unionCtor.invokeExact(value);
+        } catch (ClassCastException e) {
+            // This case can happen. e.g. NOOP_CODEC
+            LOG.debug("Codec failed to instantiate {} {}", codec, input);
+            return null;
+        } catch (Throwable e) {
+            throw new IllegalArgumentException("Failed to construct union for value " + value, e);
+        }
     }
 
     Object getValueFrom(final Object input) {
@@ -66,4 +96,4 @@ final class UnionValueOptionContext {
         final UnionValueOptionContext other = (UnionValueOptionContext) obj;
         return bindingType.equals(other.bindingType);
     }
-}
\ No newline at end of file
+}