Handle java.util.Map return type 25/85825/15
authorRobert Varga <robert.varga@pantheon.tech>
Mon, 18 Nov 2019 10:48:18 +0000 (11:48 +0100)
committerRobert Varga <robert.varga@pantheon.tech>
Tue, 17 Dec 2019 10:23:16 +0000 (11:23 +0100)
BindingReflections needs to be aware of the fact that return
type may be a Map, not only List. This adds the logic to take
care of that.

JIRA: MDSAL-434
Change-Id: I9e0dd170c03b7849e3d1d307ba03e6dd931663e5
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java

index 89f5cf52983af2a864ed529ae1d9b123ac7b60a9..f056549ba7a348addb0fde2bc279ad1d592d3152 100644 (file)
@@ -20,6 +20,7 @@ import com.google.common.collect.ImmutableSet.Builder;
 import com.google.common.util.concurrent.ListenableFuture;
 import java.lang.reflect.Field;
 import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
 import java.lang.reflect.Type;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -457,7 +458,6 @@ public final class BindingReflections {
         return getChildrenClassToMethod(type, BindingMapping.NONNULL_PREFIX);
     }
 
-    @SuppressWarnings("checkstyle:illegalCatch")
     private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
             final String prefix) {
         final String methodName = method.getName();
@@ -469,19 +469,28 @@ public final class BindingReflections {
         if (DataContainer.class.isAssignableFrom(returnType)) {
             return optionalDataContainer(returnType);
         } else if (List.class.isAssignableFrom(returnType)) {
-            try {
-                return ClassLoaderUtils.callWithClassLoader(method.getDeclaringClass().getClassLoader(), () -> {
-                    return ClassLoaderUtils.getFirstGenericParameter(method.getGenericReturnType()).flatMap(
-                        result -> result instanceof Class ? optionalCast((Class<?>) result) : Optional.empty());
-                });
-            } catch (Exception e) {
-                /*
-                 * It is safe to log this this exception on debug, since this
-                 * method should not fail. Only failures are possible if the
-                 * runtime / backing.
-                 */
-                LOG.debug("Unable to find YANG modeled return type for {}", method, e);
-            }
+            return getYangModeledReturnType(method, 0);
+        } else if (Map.class.isAssignableFrom(returnType)) {
+            return getYangModeledReturnType(method, 1);
+        }
+        return Optional.empty();
+    }
+
+    @SuppressWarnings("checkstyle:illegalCatch")
+    private static Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
+            final int parameterOffset) {
+        try {
+            return ClassLoaderUtils.callWithClassLoader(method.getDeclaringClass().getClassLoader(), () -> {
+                return genericParameter(method.getGenericReturnType(), parameterOffset).flatMap(
+                    result -> result instanceof Class ? optionalCast((Class<?>) result) : Optional.empty());
+            });
+        } catch (Exception e) {
+            /*
+             * It is safe to log this this exception on debug, since this
+             * method should not fail. Only failures are possible if the
+             * runtime / backing.
+             */
+            LOG.debug("Unable to find YANG modeled return type for {}", method, e);
         }
         return Optional.empty();
     }
@@ -494,6 +503,16 @@ public final class BindingReflections {
         return Optional.of(type.asSubclass(DataContainer.class));
     }
 
+    private static Optional<Type> genericParameter(final Type type, final int offset) {
+        if (type instanceof ParameterizedType) {
+            final Type[] parameters = ((ParameterizedType) type).getActualTypeArguments();
+            if (parameters.length > offset) {
+                return Optional.of(parameters[offset]);
+            }
+        }
+        return Optional.empty();
+    }
+
     private static class ClassToQNameLoader extends CacheLoader<Class<?>, Optional<QName>> {
 
         @Override