From 5ee9ce6531253d7a1077b06fcc8fd5333984d7f1 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 24 Nov 2022 14:38:08 +0100 Subject: [PATCH] Move BindingReflections.isSubstitutionFor() We have deprecated this method, now move it to its sole user. Change-Id: Id596e9cea546264e848b302a73ba3bb4e82faee7 Signed-off-by: Robert Varga --- .../codec/impl/ChoiceNodeCodecContext.java | 3 +- .../codec/impl/DataContainerCodecContext.java | 67 ++++++++++++++++++ .../codec/impl/DataObjectCodecContext.java | 2 +- .../spec/reflect/BindingReflections.java | 68 ------------------- 4 files changed, 69 insertions(+), 71 deletions(-) diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java index 7fda3cd1b4..7f47b51a12 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/ChoiceNodeCodecContext.java @@ -37,7 +37,6 @@ import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.runtime.api.CaseRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType; import org.opendaylight.mdsal.binding.spec.naming.BindingMapping; -import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; @@ -192,7 +191,7 @@ final class ChoiceNodeCodecContext extends DataContainerCo final Class substitution = loadCase(context, caseType); search: for (final Entry, DataContainerCodecPrototype> real : byClassBuilder.entrySet()) { - if (BindingReflections.isSubstitutionFor(substitution, real.getKey())) { + if (isSubstitutionFor(substitution, real.getKey())) { bySubstitutionBuilder.put(substitution, real.getValue()); break search; } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java index c14693f0d6..e7232499fd 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataContainerCodecContext.java @@ -16,7 +16,10 @@ import java.io.IOException; 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; @@ -34,6 +37,7 @@ import org.opendaylight.mdsal.binding.model.api.Type; import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.RuntimeTypeContainer; +import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.yangtools.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BindingObject; @@ -334,4 +338,67 @@ abstract class DataContainerCodecContext> optionalDataContainer(final Class type) { return Optional.of(type.asSubclass(DataContainer.class)); } + + + /** + * Determines if two augmentation classes or case classes represents same data. + * + *

+ * Two augmentations or cases could be substituted only if and if: + *

    + *
  • Both implements same interfaces
  • + *
  • Both have same children
  • + *
  • If augmentations: Both have same augmentation target class. Target class was generated for data node in a + * grouping.
  • + *
  • If cases: Both are from same choice. Choice class was generated for data node in grouping.
  • + *
+ * + *

+ * Explanation: + * Binding Specification reuses classes generated for groupings as part of normal data tree, this classes from + * grouping could be used at various locations and user may not be aware of it and may use incorrect case or + * augmentation in particular subtree (via copy constructors, etc). + * + * @param potential Class which is potential substitution + * @param target Class which should be used at particular subtree + * @return true if and only if classes represents same data. + * @throws NullPointerException if any argument is {@code null} + */ + // FIXME: MDSAL-785: this really should live in BindingRuntimeTypes and should not be based on reflection. The only + // user is binding-dom-codec and the logic could easily be performed on GeneratedType instead. For + // a particular world this boils down to a matrix, which can be calculated either on-demand or + // when we create BindingRuntimeTypes. Achieving that will bring us one step closer to being able + // to have a pre-compiled Binding Runtime. + @SuppressWarnings({ "rawtypes", "unchecked" }) + static boolean isSubstitutionFor(final Class potential, final Class target) { + Set subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces())); + Set targetImplemented = new HashSet<>(Arrays.asList(target.getInterfaces())); + if (!subImplemented.equals(targetImplemented)) { + return false; + } + if (Augmentation.class.isAssignableFrom(potential) + && !BindingReflections.findAugmentationTarget(potential).equals( + BindingReflections.findAugmentationTarget(target))) { + return false; + } + for (Method potentialMethod : potential.getMethods()) { + if (Modifier.isStatic(potentialMethod.getModifiers())) { + // Skip any static methods, as we are not interested in those + continue; + } + + try { + Method targetMethod = target.getMethod(potentialMethod.getName(), potentialMethod.getParameterTypes()); + if (!potentialMethod.getReturnType().equals(targetMethod.getReturnType())) { + return false; + } + } catch (NoSuchMethodException e) { + // Counterpart method is missing, so classes could not be substituted. + return false; + } catch (SecurityException e) { + throw new IllegalStateException("Could not compare methods", e); + } + } + return true; + } } diff --git a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java index 6ca2ebfb48..a05b48cd1d 100644 --- a/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java +++ b/binding/mdsal-binding-dom-codec/src/main/java/org/opendaylight/mdsal/binding/dom/codec/impl/DataObjectCodecContext.java @@ -351,7 +351,7 @@ public abstract class DataObjectCodecContext realChild : augmentationByStream.values()) { if (Augmentation.class.isAssignableFrom(realChild.getBindingClass()) - && BindingReflections.isSubstitutionFor(childClass, realChild.getBindingClass())) { + && isSubstitutionFor(childClass, realChild.getBindingClass())) { return cacheMismatched(oldMismatched, childClass, realChild); } } diff --git a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java index bc5ba71e38..8c96c2435d 100644 --- a/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java +++ b/binding/mdsal-binding-spec-util/src/main/java/org/opendaylight/mdsal/binding/spec/reflect/BindingReflections.java @@ -21,13 +21,9 @@ import com.google.common.util.concurrent.ListenableFuture; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; import java.lang.reflect.Type; -import java.util.Arrays; -import java.util.HashSet; import java.util.Optional; import java.util.ServiceLoader; -import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -452,68 +448,4 @@ public final class BindingReflections { return module; } } - - /** - * Determines if two augmentation classes or case classes represents same data. - * - *

- * Two augmentations or cases could be substituted only if and if: - *

    - *
  • Both implements same interfaces
  • - *
  • Both have same children
  • - *
  • If augmentations: Both have same augmentation target class. Target class was generated for data node in a - * grouping.
  • - *
  • If cases: Both are from same choice. Choice class was generated for data node in grouping.
  • - *
- * - *

- * Explanation: - * Binding Specification reuses classes generated for groupings as part of normal data tree, this classes from - * grouping could be used at various locations and user may not be aware of it and may use incorrect case or - * augmentation in particular subtree (via copy constructors, etc). - * - * @param potential Class which is potential substitution - * @param target Class which should be used at particular subtree - * @return true if and only if classes represents same data. - * @throws NullPointerException if any argument is {@code null} - * @deprecated This method is used only mdsal-binding-dom-codec and is scheduled for removal. - */ - // FIXME: MDSAL-785: this really should live in BindingRuntimeTypes and should not be based on reflection. The only - // user is binding-dom-codec and the logic could easily be performed on GeneratedType instead. For - // a particular world this boils down to a matrix, which can be calculated either on-demand or - // when we create BindingRuntimeTypes. Achieving that will bring us one step closer to being able - // to have a pre-compiled Binding Runtime. - @Deprecated(since = "10.0.4", forRemoval = true) - @SuppressWarnings({ "rawtypes", "unchecked" }) - public static boolean isSubstitutionFor(final Class potential, final Class target) { - Set subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces())); - Set targetImplemented = new HashSet<>(Arrays.asList(target.getInterfaces())); - if (!subImplemented.equals(targetImplemented)) { - return false; - } - if (Augmentation.class.isAssignableFrom(potential) - && !BindingReflections.findAugmentationTarget(potential).equals( - BindingReflections.findAugmentationTarget(target))) { - return false; - } - for (Method potentialMethod : potential.getMethods()) { - if (Modifier.isStatic(potentialMethod.getModifiers())) { - // Skip any static methods, as we are not interested in those - continue; - } - - try { - Method targetMethod = target.getMethod(potentialMethod.getName(), potentialMethod.getParameterTypes()); - if (!potentialMethod.getReturnType().equals(targetMethod.getReturnType())) { - return false; - } - } catch (NoSuchMethodException e) { - // Counterpart method is missing, so classes could not be substituted. - return false; - } catch (SecurityException e) { - throw new IllegalStateException("Could not compare methods", e); - } - } - return true; - } } -- 2.36.6