From aca16b3faf92cc529d8cfbcee871a51043393526 Mon Sep 17 00:00:00 2001 From: Robert Varga Date: Thu, 24 Nov 2022 11:23:21 +0100 Subject: [PATCH] Move BindingReflections.getChildrenClass* These methods are only used by mdsal-binding-dom-codec, move them to their sole users. JIRA: MDSAL-781 Change-Id: I074a8c91f1729194f47310424dd93a9e703ca629 Signed-off-by: Robert Varga --- .../codec/impl/ChoiceNodeCodecContext.java | 29 ++++- .../codec/impl/DataContainerCodecContext.java | 66 ++++++++++ .../codec/impl/DataObjectCodecContext.java | 35 +++++- .../spec/reflect/BindingReflections.java | 115 ------------------ 4 files changed, 126 insertions(+), 119 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 f720b6825f..7fda3cd1b4 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 @@ -19,10 +19,12 @@ import com.google.common.collect.MultimapBuilder.SetMultimapBuilder; import com.google.common.collect.Multimaps; import com.google.common.collect.SetMultimap; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -34,7 +36,9 @@ import org.opendaylight.mdsal.binding.model.api.JavaTypeName; 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; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; @@ -125,7 +129,7 @@ final class ChoiceNodeCodecContext extends DataContainerCo // Updates collection of case children @SuppressWarnings("unchecked") final Class cazeCls = (Class) cazeDef.getBindingClass(); - for (final Class cazeChild : BindingReflections.getChildrenClasses(cazeCls)) { + for (final Class cazeChild : getChildrenClasses(cazeCls)) { childToCase.put(cazeChild, cazeDef); } // Updates collection of YANG instance identifier to case @@ -308,4 +312,27 @@ final class ChoiceNodeCodecContext extends DataContainerCo return childNonNull(result, type, "Class %s is not child of any cases for %s", type, bindingArg()).get(); } + + /** + * 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 + */ + // FIXME: MDSAL-780: replace use of this method + @SuppressWarnings("unchecked") + private static Iterable> getChildrenClasses(final Class type) { + checkArgument(type != null, "Target type must not be null"); + checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer"); + List> ret = new LinkedList<>(); + for (Method method : type.getMethods()) { + Optional> entity = getYangModeledReturnType(method, + BindingMapping.GETTER_PREFIX); + if (entity.isPresent()) { + ret.add((Class) entity.get()); + } + } + return ret; + } } 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 df089fd1fc..c14693f0d6 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 @@ -15,7 +15,10 @@ import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.lang.invoke.MethodHandles; import java.lang.invoke.VarHandle; +import java.lang.reflect.Method; +import java.lang.reflect.ParameterizedType; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.Set; import org.eclipse.jdt.annotation.NonNull; @@ -31,8 +34,10 @@ 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.yangtools.util.ClassLoaderUtils; import org.opendaylight.yangtools.yang.binding.Augmentation; import org.opendaylight.yangtools.yang.binding.BindingObject; +import org.opendaylight.yangtools.yang.binding.DataContainer; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.common.QName; @@ -43,9 +48,12 @@ import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNormalizedNodeStreamWriter; import org.opendaylight.yangtools.yang.data.impl.schema.NormalizedNodeResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; abstract class DataContainerCodecContext extends NodeCodecContext implements BindingDataObjectCodecTreeNode { + private static final Logger LOG = LoggerFactory.getLogger(DataContainerCodecContext.class); private static final VarHandle EVENT_STREAM_SERIALIZER; static { @@ -268,4 +276,62 @@ abstract class DataContainerCodecContext> 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> 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 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> optionalCast(final Class type) { + return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty(); + } + + + // FIXME: MDSAL-780: remove this method + static final Optional> optionalDataContainer(final Class type) { + return Optional.of(type.asSubclass(DataContainer.class)); + } } 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 224ca14173..6ca2ebfb48 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 @@ -37,6 +37,7 @@ import org.opendaylight.mdsal.binding.runtime.api.AugmentableRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.BindingRuntimeContext; import org.opendaylight.mdsal.binding.runtime.api.ChoiceRuntimeType; import org.opendaylight.mdsal.binding.runtime.api.CompositeRuntimeType; +import org.opendaylight.mdsal.binding.spec.naming.BindingMapping; import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections; import org.opendaylight.yangtools.yang.binding.Augmentable; import org.opendaylight.yangtools.yang.binding.Augmentation; @@ -107,8 +108,7 @@ public abstract class DataObjectCodecContext tmpLeaves = factory().getLeafNodes(bindingClass, getType().statement()); - final Map, Method> clsToMethod = - BindingReflections.getChildrenClassToMethod(bindingClass); + final Map, Method> clsToMethod = getChildrenClassToMethod(bindingClass); final Map byYangBuilder = new HashMap<>(); final Map, DataContainerCodecPrototype> byStreamClassBuilder = new HashMap<>(); @@ -152,7 +152,7 @@ public abstract class DataObjectCodecContext new PropertyInfo.GetterAndNonnull( @@ -482,4 +482,33 @@ public abstract class DataObjectCodecContext, Method> getChildrenClassToMethod(final Class type) { + return getChildClassToMethod(type, BindingMapping.GETTER_PREFIX); + } + + // FIXME: MDSAL-780: replace use of this method + private static Map, Method> getChildrenClassToNonnullMethod(final Class type) { + return getChildClassToMethod(type, BindingMapping.NONNULL_PREFIX); + } + + // FIXME: MDSAL-780: replace use of this method + private static Map, 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, Method>(); + for (Method method : type.getMethods()) { + getYangModeledReturnType(method, prefix).ifPresent(entity -> ret.put(entity, method)); + } + return ret; + } } 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 fb4635efdb..0e10689fc6 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,14 +21,9 @@ import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.Arrays; -import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; import java.util.Set; @@ -376,116 +371,6 @@ public final class BindingReflections { && (targetType.getName().endsWith("Input") || targetType.getName().endsWith("Output")); } - /** - * 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 - * @deprecated This method is only used in mdsal-binding-dom-codec and is schedule for removal. - */ - @Deprecated(since = "10.0.4", forRemoval = true) - @SuppressWarnings("unchecked") - public static Iterable> getChildrenClasses(final Class type) { - checkArgument(type != null, "Target type must not be null"); - checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer"); - List> ret = new LinkedList<>(); - for (Method method : type.getMethods()) { - Optional> entity = getYangModeledReturnType(method, - BindingMapping.GETTER_PREFIX); - if (entity.isPresent()) { - ret.add((Class) entity.get()); - } - } - return ret; - } - - /** - * 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 - * @deprecated This method is only used in mdsal-binding-dom-codec and is schedule for removal. - */ - @Deprecated(since = "10.0.4", forRemoval = true) - public static Map, Method> getChildrenClassToMethod(final Class type) { - return getChildClassToMethod(type, BindingMapping.GETTER_PREFIX); - } - - @Beta - @Deprecated(since = "10.0.4", forRemoval = true) - public static Map, Method> getChildrenClassToNonnullMethod(final Class type) { - return getChildClassToMethod(type, BindingMapping.NONNULL_PREFIX); - } - - private static Map, 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); - Map, Method> ret = new HashMap<>(); - for (Method method : type.getMethods()) { - Optional> entity = getYangModeledReturnType(method, prefix); - if (entity.isPresent()) { - ret.put(entity.get(), method); - } - } - return ret; - } - - private static Optional> 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> 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> optionalCast(final Class type) { - return DataContainer.class.isAssignableFrom(type) ? optionalDataContainer(type) : Optional.empty(); - } - - private static Optional> optionalDataContainer(final Class type) { - return Optional.of(type.asSubclass(DataContainer.class)); - } - - private static Optional genericParameter(final Type type, final int offset) { - if (type instanceof ParameterizedType parameterized) { - final Type[] parameters = parameterized.getActualTypeArguments(); - if (parameters.length > offset) { - return Optional.of(parameters[offset]); - } - } - return Optional.empty(); - } - private static class ClassToQNameLoader extends CacheLoader, Optional> { @Override -- 2.36.6