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;
return opt.orElse(null);
}
- /**
- * Find data hierarchy parent from concrete Data class. This method uses first generic argument of implemented
- * {@link ChildOf} interface.
- *
- * @param childClass
- * child class for which we want to find the parent class.
- * @return Parent class, e.g. class of which the childClass is ChildOf.
- */
- public static Class<?> findHierarchicalParent(final Class<? extends ChildOf<?>> childClass) {
- return ClassLoaderUtils.findFirstGenericArgument(childClass, ChildOf.class).orElse(null);
- }
-
- /**
- * Find data hierarchy parent from concrete Data class. This method is shorthand which gets DataObject class by
- * invoking {@link DataObject#implementedInterface()} and uses {@link #findHierarchicalParent(Class)}.
- *
- * @param child
- * Child object for which the parent needs to be located.
- * @return Parent class, or null if a parent is not found.
- */
- public static Class<?> findHierarchicalParent(final DataObject child) {
- if (child instanceof ChildOf) {
- return ClassLoaderUtils.findFirstGenericArgument(child.implementedInterface(), ChildOf.class).orElse(null);
- }
- return null;
- }
-
/**
* Returns a QName associated to supplied type.
*
/**
* Extracts Output class for RPC method.
*
- * @param targetMethod
- * method to scan
+ * @param targetMethod method to scan
* @return Optional.empty() if result type could not be get, or return type is Void.
+ * @deprecated This method is unused and scheduled for removal
*/
+ @Deprecated(since = "10.0.4", forRemoval = true)
@SuppressWarnings("rawtypes")
public static Optional<Class<?>> resolveRpcOutputClass(final Method targetMethod) {
checkState(isRpcMethod(targetMethod), "Supplied method is not a RPC invocation method");
/**
* Extracts input class for RPC method.
*
- * @param targetMethod
- * method to scan
+ * @param targetMethod method to scan
* @return Optional.empty() if RPC has no input, RPC input type otherwise.
+ * @deprecated This method is unused and scheduled for removal
*/
+ @Deprecated(since = "10.0.4", forRemoval = true)
@SuppressWarnings("rawtypes")
public static Optional<Class<? extends DataContainer>> resolveRpcInputClass(final Method targetMethod) {
for (Class clazz : targetMethod.getParameterTypes()) {
*
* @param potentialNotification class to examine
* @return True if the class represents a Notification.
+ * @deprecated This method is only used internally and is schedule for removal
*/
+ @Deprecated(since = "10.0.4", forRemoval = true)
public static boolean isNotification(final Class<?> potentialNotification) {
checkArgument(potentialNotification != null, "potentialNotification must not be null.");
return Notification.class.isAssignableFrom(potentialNotification);
&& (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
- */
- @SuppressWarnings("unchecked")
- public static Iterable<Class<? extends DataObject>> getChildrenClasses(final Class<? extends DataContainer> type) {
- checkArgument(type != null, "Target type must not be null");
- checkArgument(DataContainer.class.isAssignableFrom(type), "Supplied type must be derived from DataContainer");
- List<Class<? extends DataObject>> ret = new LinkedList<>();
- for (Method method : type.getMethods()) {
- Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method,
- BindingMapping.GETTER_PREFIX);
- if (entity.isPresent()) {
- ret.add((Class<? extends DataObject>) 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
- */
- public static Map<Class<? extends DataContainer>, Method> getChildrenClassToMethod(final Class<?> type) {
- return getChildClassToMethod(type, BindingMapping.GETTER_PREFIX);
- }
-
- @Beta
- public static Map<Class<? extends DataContainer>, Method> getChildrenClassToNonnullMethod(final Class<?> type) {
- return getChildClassToMethod(type, BindingMapping.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);
- Map<Class<? extends DataContainer>, Method> ret = new HashMap<>();
- for (Method method : type.getMethods()) {
- Optional<Class<? extends DataContainer>> entity = getYangModeledReturnType(method, prefix);
- if (entity.isPresent()) {
- ret.put(entity.get(), method);
- }
- }
- return ret;
- }
-
- private static 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<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));
- }
-
- private static Optional<Type> 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<Class<?>, Optional<QName>> {
@Override
}
/**
- * Determines if two augmentation classes or case classes represents same
- * data.
+ * Determines if two augmentation classes or case classes represents same data.
*
* <p>
* Two augmentations or cases could be substituted only if and if:
* <ul>
- * <li>Both implements same interfaces</li>
- * <li>Both have same children</li>
- * <li>If augmentations: Both have same augmentation target class. Target
- * class was generated for data node in grouping.</li>
- * <li>If cases: Both are from same choice. Choice class was generated for
- * data node in grouping.</li>
+ * <li>Both implements same interfaces</li>
+ * <li>Both have same children</li>
+ * <li>If augmentations: Both have same augmentation target class. Target class was generated for data node in a
+ * grouping.</li>
+ * <li>If cases: Both are from same choice. Choice class was generated for data node in grouping.</li>
* </ul>
*
* <p>
- * <b>Explanation:</b> 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).
+ * <b>Explanation:</b>
+ * 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
+ * @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: 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.
+ // 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" })
public static boolean isSubstitutionFor(final Class potential, final Class target) {
Set<Class> subImplemented = new HashSet<>(Arrays.asList(potential.getInterfaces()));