Split up CodecDataObjectAnalysis 53/106753/3
authorRobert Varga <robert.varga@pantheon.tech>
Thu, 29 Jun 2023 14:47:16 +0000 (16:47 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Thu, 29 Jun 2023 19:00:34 +0000 (21:00 +0200)
CodecDataObjectAnalysis contains two things: the indexing of children
and then the generated class. We need to split these up, so we can
actually plugin in YangData (which needs to former) into the mix.

JIRA: MDSAL-805
Change-Id: Ic38cbf1be4b4011ae5dd983d1826e020a67620c4
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataContainerAnalysis.java [new file with mode: 0644]
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceCodecContext.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/CodecDataObjectAnalysis.java
binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java

diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataContainerAnalysis.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/AbstractDataContainerAnalysis.java
new file mode 100644 (file)
index 0000000..d65fa37
--- /dev/null
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2023 PANTHEON.tech, s.r.o. 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.mdsal.binding.dom.codec.impl;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Verify.verify;
+import static com.google.common.base.Verify.verifyNotNull;
+
+import com.google.common.collect.ImmutableMap;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
+import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
+import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
+import org.opendaylight.yangtools.yang.binding.DataContainer;
+import org.opendaylight.yangtools.yang.binding.OpaqueObject;
+import org.opendaylight.yangtools.yang.binding.contract.Naming;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
+import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Analysis of a {@link DataContainer} specialization class. This includes things needed for
+ * {@link DataContainerCodecContext}'s methods as well as the appropriate run-time generated class.
+ */
+abstract class AbstractDataContainerAnalysis<R extends CompositeRuntimeType> {
+    private static final Logger LOG = LoggerFactory.getLogger(AbstractDataContainerAnalysis.class);
+
+    // Needed for DataContainerCodecContext
+    final @NonNull ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byStreamClass;
+    final @NonNull ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byBindingArgClass;
+    final @NonNull ImmutableMap<NodeIdentifier, CodecContextSupplier> byYang;
+    final @NonNull ImmutableMap<String, ValueNodeCodecContext> leafNodes;
+
+    // Needed for generated classes
+    final @NonNull ImmutableMap<Method, ValueNodeCodecContext> leafContexts;
+    final @NonNull ImmutableMap<Class<?>, PropertyInfo> daoProperties;
+
+    AbstractDataContainerAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
+            final CodecItemFactory itemFactory) {
+        leafContexts = factory.getLeafNodes(bindingClass, runtimeType.statement());
+
+        // Reflection-based on the passed class
+        final var clsToMethod = getChildrenClassToMethod(bindingClass);
+
+        // Indexing part: be very careful around what gets done when
+        final var byYangBuilder = new HashMap<NodeIdentifier, CodecContextSupplier>();
+
+        // Step 1: add leaf children
+        var leafBuilder = ImmutableMap.<String, ValueNodeCodecContext>builderWithExpectedSize(leafContexts.size());
+        for (var leaf : leafContexts.values()) {
+            leafBuilder.put(leaf.getSchema().getQName().getLocalName(), leaf);
+            byYangBuilder.put(leaf.getDomPathArgument(), leaf);
+        }
+        leafNodes = leafBuilder.build();
+
+        final var byBindingArgClassBuilder = new HashMap<Class<?>, CommonDataObjectCodecPrototype<?>>();
+        final var byStreamClassBuilder = new HashMap<Class<?>, CommonDataObjectCodecPrototype<?>>();
+        final var daoPropertiesBuilder = new HashMap<Class<?>, PropertyInfo>();
+        for (var childDataObj : clsToMethod.entrySet()) {
+            final var method = childDataObj.getValue();
+            verify(!method.isDefault(), "Unexpected default method %s in %s", method, bindingClass);
+
+            final var retClass = childDataObj.getKey();
+            if (OpaqueObject.class.isAssignableFrom(retClass)) {
+                // Filter OpaqueObjects, they are not containers
+                continue;
+            }
+
+            // Record getter method
+            daoPropertiesBuilder.put(retClass, new PropertyInfo.Getter(method));
+
+            final var childProto = getChildPrototype(runtimeType, factory, itemFactory, retClass);
+            byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
+            byYangBuilder.put(childProto.getYangArg(), childProto);
+
+            // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch
+            //        createInstance() and then we could do an instanceof check instead.
+            if (childProto.getType() instanceof ChoiceRuntimeType) {
+                final var choice = (ChoiceCodecContext<?>) childProto.get();
+                for (var cazeChild : choice.getCaseChildrenClasses()) {
+                    byBindingArgClassBuilder.put(cazeChild, childProto);
+                }
+            }
+        }
+
+        // Snapshot before below processing
+        byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
+
+        // Slight footprint optimization: we do not want to copy byStreamClass, as that would force its entrySet view
+        // to be instantiated. Furthermore the two maps can easily end up being equal -- hence we can reuse
+        // byStreamClass for the purposes of both.
+        byBindingArgClassBuilder.putAll(byStreamClassBuilder);
+        byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? byStreamClass
+            : ImmutableMap.copyOf(byBindingArgClassBuilder);
+
+        // Find all non-default nonnullFoo() methods and update the corresponding property info
+        for (var entry : getChildrenClassToNonnullMethod(bindingClass).entrySet()) {
+            final var method = entry.getValue();
+            if (!method.isDefault()) {
+                daoPropertiesBuilder.compute(entry.getKey(), (key, value) -> new PropertyInfo.GetterAndNonnull(
+                    verifyNotNull(value, "No getter for %s", key).getterMethod(), method));
+            }
+        }
+
+        // At this point all indexing is done: byYangBuilder should not be referenced
+        byYang = ImmutableMap.copyOf(byYangBuilder);
+        daoProperties = ImmutableMap.copyOf(daoPropertiesBuilder);
+    }
+
+    private static @NonNull CommonDataObjectCodecPrototype<?> getChildPrototype(final CompositeRuntimeType type,
+            final CodecContextFactory factory, final CodecItemFactory itemFactory,
+            final Class<? extends DataContainer> childClass) {
+        final var child = type.bindingChild(JavaTypeName.create(childClass));
+        if (child == null) {
+            throw DataContainerCodecContext.childNullException(factory.getRuntimeContext(), childClass,
+                "Node %s does not have child named %s", type, childClass);
+        }
+        final var item = itemFactory.createItem(childClass, child.statement());
+        if (child instanceof ContainerLikeRuntimeType containerLike) {
+            if (child instanceof ContainerRuntimeType container
+                && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class).isEmpty()) {
+                return new StructuralContainerCodecPrototype(item, container, factory);
+            }
+            return new ContainerLikeCodecPrototype(item, containerLike, factory);
+        } else if (child instanceof ListRuntimeType list) {
+            return list.keyType() != null ? new MapCodecPrototype(item, list, factory)
+                : new ListCodecPrototype(item, list, factory);
+        } else if (child instanceof ChoiceRuntimeType choice) {
+            return new ChoiceCodecPrototype(item, choice, factory);
+        } else {
+            throw new UnsupportedOperationException("Unhandled type " + child);
+        }
+    }
+
+
+    // FIXME: MDSAL-780: these methods perform analytics using java.lang.reflect to acquire the basic shape of the
+    //                   class. This is not exactly AOT friendly, as most of the information should be provided by
+    //                   CompositeRuntimeType.
+    //
+    //                   As as first cut, CompositeRuntimeType should provide the mapping between YANG children and the
+    //                   corresponding GETTER_PREFIX/NONNULL_PREFIX method names, If we have that, the use in this
+    //                   class should be fine.
+    //
+    //                   The second cut is binding the actual Method invocations, which is fine here, as this class is
+    //                   all about having a run-time generated class. AOT would be providing an alternative, where the
+    //                   equivalent class would be generated at compile-time and hence would bind to the methods
+    //                   directly -- and AOT equivalent of this class would really be a compile-time generated registry
+    //                   to those classes' entry points.
+
+    /**
+     * Scans supplied class and returns an iterable of all data children classes.
+     *
+     * @param type YANG Modeled Entity derived from DataContainer
+     * @return Iterable of all data children, which have YANG modeled entity
+     */
+    private static Map<Class<? extends DataContainer>, Method> getChildrenClassToMethod(final Class<?> type) {
+        return getChildClassToMethod(type, Naming.GETTER_PREFIX);
+    }
+
+    private static Map<Class<? extends DataContainer>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
+        return getChildClassToMethod(type, Naming.NONNULL_PREFIX);
+    }
+
+    private static Map<Class<? extends DataContainer>, Method> getChildClassToMethod(final Class<?> type,
+            final String prefix) {
+        checkArgument(type != null, "Target type must not be null");
+        checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type %s must be derived from DataContainer",
+            type);
+        final var ret = new HashMap<Class<? extends DataContainer>, Method>();
+        for (Method method : type.getMethods()) {
+            getYangModeledReturnType(method, prefix).ifPresent(entity -> ret.put(entity, method));
+        }
+        return ret;
+    }
+
+    static final Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
+            final String prefix) {
+        final String methodName = method.getName();
+        if ("getClass".equals(methodName) || !methodName.startsWith(prefix) || method.getParameterCount() > 0) {
+            return Optional.empty();
+        }
+
+        final Class<?> returnType = method.getReturnType();
+        if (DataContainer.class.isAssignableFrom(returnType)) {
+            return optionalDataContainer(returnType);
+        } else if (List.class.isAssignableFrom(returnType)) {
+            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(),
+                () -> 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();
+    }
+
+    private static Optional<java.lang.reflect.Type> genericParameter(final java.lang.reflect.Type type,
+            final int offset) {
+        if (type instanceof ParameterizedType parameterized) {
+            final var parameters = parameterized.getActualTypeArguments();
+            if (parameters.length > offset) {
+                return Optional.of(parameters[offset]);
+            }
+        }
+        return Optional.empty();
+    }
+
+    private static Optional<Class<? extends DataContainer>> optionalCast(final Class<?> type) {
+        return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty();
+    }
+
+    private static Optional<Class<? extends DataContainer>> optionalDataContainer(final Class<?> type) {
+        return Optional.of(type.asSubclass(DataContainer.class));
+    }
+}
index 243d0f795f0ee3bb1388de1f7449a394b7276f7b..95c156a4529814e5641f25fdfb1bab586c9db0e1 100644 (file)
@@ -317,10 +317,8 @@ final class ChoiceCodecContext<D extends DataObject> extends CommonDataObjectCod
         checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
         final var ret = new LinkedList<Class<? extends DataObject>>();
         for (var method : type.getMethods()) {
-            final var entity = getYangModeledReturnType(method, Naming.GETTER_PREFIX);
-            if (entity.isPresent()) {
-                ret.add((Class<? extends DataObject>) entity.orElseThrow());
-            }
+            AbstractDataContainerAnalysis.getYangModeledReturnType(method, Naming.GETTER_PREFIX)
+                .ifPresent(entity -> ret.add((Class<? extends DataObject>) entity));
         }
         return ret;
     }
index dcc4e13a26d130eef4b5872824203f266113c7a3..9ecf70678ea98b035e920e11f37cbe7ba895ed8d 100644 (file)
  */
 package org.opendaylight.mdsal.binding.dom.codec.impl;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Verify.verify;
-import static com.google.common.base.Verify.verifyNotNull;
-
 import com.google.common.base.VerifyException;
-import com.google.common.collect.ImmutableMap;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodType;
 import java.lang.reflect.Method;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import org.eclipse.jdt.annotation.NonNull;
-import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType;
 import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerLikeRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ContainerRuntimeType;
-import org.opendaylight.mdsal.binding.runtime.api.ListRuntimeType;
 import org.opendaylight.yangtools.yang.binding.Augmentable;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
 import org.opendaylight.yangtools.yang.binding.DataObject;
-import org.opendaylight.yangtools.yang.binding.OpaqueObject;
-import org.opendaylight.yangtools.yang.binding.contract.Naming;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerNode;
-import org.opendaylight.yangtools.yang.model.api.stmt.PresenceEffectiveStatement;
 
 /**
  * Analysis of a {@link DataObject} specialization class. The primary point of this class is to separate out creation
  * indices needed for {@link #proxyConstructor}. Since we want to perform as much indexing as possible in a single pass,
  * we also end up indexing things that are not strictly required to arrive at that constructor.
  */
-final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> {
+final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> extends AbstractDataContainerAnalysis<R> {
     private static final MethodType CONSTRUCTOR_TYPE = MethodType.methodType(void.class,
         AbstractDataObjectCodecContext.class, DataContainerNode.class);
     private static final MethodType DATAOBJECT_TYPE = MethodType.methodType(DataObject.class,
         AbstractDataObjectCodecContext.class, DataContainerNode.class);
 
-    final @NonNull ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byStreamClass;
-    final @NonNull ImmutableMap<Class<?>, CommonDataObjectCodecPrototype<?>> byBindingArgClass;
-    final @NonNull ImmutableMap<NodeIdentifier, CodecContextSupplier> byYang;
-    final @NonNull ImmutableMap<String, ValueNodeCodecContext> leafNodes;
     final @NonNull Class<? extends CodecDataObject<?>> generatedClass;
     final @NonNull List<AugmentRuntimeType> possibleAugmentations;
     final @NonNull MethodHandle proxyConstructor;
 
     CodecDataObjectAnalysis(final CommonDataObjectCodecPrototype<R> prototype, final CodecItemFactory itemFactory,
             final Method keyMethod) {
-        // Preliminaries from prototype
-        final var bindingClass = prototype.getBindingClass();
-        final var runtimeType = prototype.getType();
-        final var factory = prototype.getFactory();
-        final var leafContexts = factory.getLeafNodes(bindingClass, runtimeType.statement());
-
-        // Reflection-based on the passed class
-        final var clsToMethod = getChildrenClassToMethod(bindingClass);
-
-        // Indexing part: be very careful around what gets done when
-        final var byYangBuilder = new HashMap<NodeIdentifier, CodecContextSupplier>();
-
-        // Step 1: add leaf children
-        var leafBuilder = ImmutableMap.<String, ValueNodeCodecContext>builderWithExpectedSize(leafContexts.size());
-        for (var leaf : leafContexts.values()) {
-            leafBuilder.put(leaf.getSchema().getQName().getLocalName(), leaf);
-            byYangBuilder.put(leaf.getDomPathArgument(), leaf);
-        }
-        leafNodes = leafBuilder.build();
-
-        final var byBindingArgClassBuilder = new HashMap<Class<?>, CommonDataObjectCodecPrototype<?>>();
-        final var byStreamClassBuilder = new HashMap<Class<?>, CommonDataObjectCodecPrototype<?>>();
-        final var daoProperties = new HashMap<Class<?>, PropertyInfo>();
-        for (var childDataObj : clsToMethod.entrySet()) {
-            final var method = childDataObj.getValue();
-            verify(!method.isDefault(), "Unexpected default method %s in %s", method, bindingClass);
-
-            final var retClass = childDataObj.getKey();
-            if (OpaqueObject.class.isAssignableFrom(retClass)) {
-                // Filter OpaqueObjects, they are not containers
-                continue;
-            }
-
-            // Record getter method
-            daoProperties.put(retClass, new PropertyInfo.Getter(method));
-
-            final var childProto = getChildPrototype(runtimeType, factory, itemFactory, retClass);
-            byStreamClassBuilder.put(childProto.getBindingClass(), childProto);
-            byYangBuilder.put(childProto.getYangArg(), childProto);
-
-            // FIXME: It really feels like we should be specializing DataContainerCodecPrototype so as to ditch
-            //        createInstance() and then we could do an instanceof check instead.
-            if (childProto.getType() instanceof ChoiceRuntimeType) {
-                final var choice = (ChoiceCodecContext<?>) childProto.get();
-                for (var cazeChild : choice.getCaseChildrenClasses()) {
-                    byBindingArgClassBuilder.put(cazeChild, childProto);
-                }
-            }
-        }
-
-        // Snapshot before below processing
-        byStreamClass = ImmutableMap.copyOf(byStreamClassBuilder);
+        this(prototype.getBindingClass(), prototype.getType(), prototype.getFactory(), itemFactory, keyMethod);
+    }
 
-        // Slight footprint optimization: we do not want to copy byStreamClass, as that would force its entrySet view
-        // to be instantiated. Furthermore the two maps can easily end up being equal -- hence we can reuse
-        // byStreamClass for the purposes of both.
-        byBindingArgClassBuilder.putAll(byStreamClassBuilder);
-        byBindingArgClass = byStreamClassBuilder.equals(byBindingArgClassBuilder) ? byStreamClass
-            : ImmutableMap.copyOf(byBindingArgClassBuilder);
-
-        // Find all non-default nonnullFoo() methods and update the corresponding property info
-        for (var entry : getChildrenClassToNonnullMethod(bindingClass).entrySet()) {
-            final var method = entry.getValue();
-            if (!method.isDefault()) {
-                daoProperties.compute(entry.getKey(), (key, value) -> new PropertyInfo.GetterAndNonnull(
-                    verifyNotNull(value, "No getter for %s", key).getterMethod(), method));
-            }
-        }
-        // At this point all indexing is done: byYangBuilder should not be referenced
-        byYang = ImmutableMap.copyOf(byYangBuilder);
+    CodecDataObjectAnalysis(final Class<?> bindingClass, final R runtimeType, final CodecContextFactory factory,
+            final CodecItemFactory itemFactory, final Method keyMethod) {
+        super(bindingClass, runtimeType, factory, itemFactory);
 
         // Final bits: generate the appropriate class, As a side effect we identify what Augmentations are possible
         if (Augmentable.class.isAssignableFrom(bindingClass)) {
@@ -157,71 +72,4 @@ final class CodecDataObjectAnalysis<R extends CompositeRuntimeType> {
 
         proxyConstructor = ctor.asType(DATAOBJECT_TYPE);
     }
-
-    private static @NonNull CommonDataObjectCodecPrototype<?> getChildPrototype(final CompositeRuntimeType type,
-            final CodecContextFactory factory, final CodecItemFactory itemFactory,
-            final Class<? extends DataContainer> childClass) {
-        final var child = type.bindingChild(JavaTypeName.create(childClass));
-        if (child == null) {
-            throw DataContainerCodecContext.childNullException(factory.getRuntimeContext(), childClass,
-                "Node %s does not have child named %s", type, childClass);
-        }
-        final var item = itemFactory.createItem(childClass, child.statement());
-        if (child instanceof ContainerLikeRuntimeType containerLike) {
-            if (child instanceof ContainerRuntimeType container
-                && container.statement().findFirstEffectiveSubstatement(PresenceEffectiveStatement.class).isEmpty()) {
-                return new StructuralContainerCodecPrototype(item, container, factory);
-            }
-            return new ContainerLikeCodecPrototype(item, containerLike, factory);
-        } else if (child instanceof ListRuntimeType list) {
-            return list.keyType() != null ? new MapCodecPrototype(item, list, factory)
-                : new ListCodecPrototype(item, list, factory);
-        } else if (child instanceof ChoiceRuntimeType choice) {
-            return new ChoiceCodecPrototype(item, choice, factory);
-        } else {
-            throw new UnsupportedOperationException("Unhandled type " + child);
-        }
-    }
-
-
-    // FIXME: MDSAL-780: these methods perform analytics using java.lang.reflect to acquire the basic shape of the
-    //                   class. This is not exactly AOT friendly, as most of the information should be provided by
-    //                   CompositeRuntimeType.
-    //
-    //                   As as first cut, CompositeRuntimeType should provide the mapping between YANG children and the
-    //                   corresponding GETTER_PREFIX/NONNULL_PREFIX method names, If we have that, the use in this
-    //                   class should be fine.
-    //
-    //                   The second cut is binding the actual Method invocations, which is fine here, as this class is
-    //                   all about having a run-time generated class. AOT would be providing an alternative, where the
-    //                   equivalent class would be generated at compile-time and hence would bind to the methods
-    //                   directly -- and AOT equivalent of this class would really be a compile-time generated registry
-    //                   to those classes' entry points.
-
-    /**
-     * Scans supplied class and returns an iterable of all data children classes.
-     *
-     * @param type YANG Modeled Entity derived from DataContainer
-     * @return Iterable of all data children, which have YANG modeled entity
-     */
-    private static Map<Class<? extends DataContainer>, Method> getChildrenClassToMethod(final Class<?> type) {
-        return getChildClassToMethod(type, Naming.GETTER_PREFIX);
-    }
-
-    private static Map<Class<? extends DataContainer>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
-        return getChildClassToMethod(type, Naming.NONNULL_PREFIX);
-    }
-
-    private static Map<Class<? extends DataContainer>, Method> getChildClassToMethod(final Class<?> type,
-            final String prefix) {
-        checkArgument(type != null, "Target type must not be null");
-        checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type %s must be derived from DataContainer",
-            type);
-        final var ret = new HashMap<Class<? extends DataContainer>, Method>();
-        for (Method method : type.getMethods()) {
-            DataContainerCodecContext.getYangModeledReturnType(method, prefix)
-                .ifPresent(entity -> ret.put(entity, method));
-        }
-        return ret;
-    }
 }
index 2caa3667acb2815b8d6c39a72523f317e162c355..e925b9ecd3304680c9bbc1f12ca231c00d11df5a 100644 (file)
@@ -17,11 +17,9 @@ import java.lang.invoke.MethodHandles;
 import java.lang.invoke.VarHandle;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import org.eclipse.jdt.annotation.NonNull;
@@ -267,63 +265,6 @@ abstract sealed class DataContainerCodecContext<D extends BindingObject & DataCo
         }
     }
 
-    // FIXME: MDSAL-780 replace this method with BindingRuntimeTypes-driven logic
-    static final Optional<Class<? extends DataContainer>> getYangModeledReturnType(final Method method,
-            final String prefix) {
-        final String methodName = method.getName();
-        if ("getClass".equals(methodName) || !methodName.startsWith(prefix) || method.getParameterCount() > 0) {
-            return Optional.empty();
-        }
-
-        final Class<?> returnType = method.getReturnType();
-        if (DataContainer.class.isAssignableFrom(returnType)) {
-            return optionalDataContainer(returnType);
-        } else if (List.class.isAssignableFrom(returnType)) {
-            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(),
-                () -> 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();
-    }
-
-    private static Optional<java.lang.reflect.Type> genericParameter(final java.lang.reflect.Type type,
-            final int offset) {
-        if (type instanceof ParameterizedType parameterized) {
-            final var parameters = parameterized.getActualTypeArguments();
-            if (parameters.length > offset) {
-                return Optional.of(parameters[offset]);
-            }
-        }
-        return Optional.empty();
-    }
-
-    private static Optional<Class<? extends DataContainer>> optionalCast(final Class<?> type) {
-        return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty();
-    }
-
-    // FIXME: MDSAL-780: remove this method
-    static final Optional<Class<? extends DataContainer>> optionalDataContainer(final Class<?> type) {
-        return Optional.of(type.asSubclass(DataContainer.class));
-    }
-
     /**
      * Determines if two augmentation classes or case classes represents same data.
      *