@Test public void testGetOverrideHierarchyIncludingInterfaces() { final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class); final Iterator<MethodDescriptor> expected = Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class), new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0]), new MethodDescriptor(GenericConsumer.class, "consume", GenericConsumer.class.getTypeParameters()[0])) .iterator(); for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.INCLUDE)) { assertTrue(expected.hasNext()); final MethodDescriptor md = expected.next(); assertEquals(md.declaringClass, m.getDeclaringClass()); assertEquals(md.name, m.getName()); assertEquals(md.parameterTypes.length, m.getParameterTypes().length); for (int i = 0; i < md.parameterTypes.length; i++) { assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i])); } } assertFalse(expected.hasNext()); }
@Test public void testGetOverrideHierarchyExcludingInterfaces() { final Method method = MethodUtils.getAccessibleMethod(StringParameterizedChild.class, "consume", String.class); final Iterator<MethodDescriptor> expected = Arrays.asList(new MethodDescriptor(StringParameterizedChild.class, "consume", String.class), new MethodDescriptor(GenericParent.class, "consume", GenericParent.class.getTypeParameters()[0])) .iterator(); for (final Method m : MethodUtils.getOverrideHierarchy(method, Interfaces.EXCLUDE)) { assertTrue(expected.hasNext()); final MethodDescriptor md = expected.next(); assertEquals(md.declaringClass, m.getDeclaringClass()); assertEquals(md.name, m.getName()); assertEquals(md.parameterTypes.length, m.getParameterTypes().length); for (int i = 0; i < md.parameterTypes.length; i++) { assertTrue(TypeUtils.equals(md.parameterTypes[i], m.getGenericParameterTypes()[i])); } } assertFalse(expected.hasNext()); }
/** * Get the hierarchy of overridden methods down to {@code result} respecting generics. * * @param method lowest to consider * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false * @return Set<Method> in ascending order from sub- to superclass * @throws NullPointerException if the specified method is {@code null} * @since 3.2 */ public static Set<Method> getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { Validate.notNull(method); final Set<Method> result = new LinkedHashSet<Method>(); result.add(method); final Class<?>[] parameterTypes = method.getParameterTypes(); final Class<?> declaringClass = method.getDeclaringClass(); final Iterator<Class<?>> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); //skip the declaring class :P hierarchy.next(); hierarchyTraversal: while (hierarchy.hasNext()) { final Class<?> c = hierarchy.next(); final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); if (m == null) { continue; } if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { // matches without generics result.add(m); continue; } // necessary to get arguments every time in the case that we are including interfaces final Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); for (int i = 0; i < parameterTypes.length; i++) { final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); if (!TypeUtils.equals(childType, parentType)) { continue hierarchyTraversal; } } result.add(m); } return result; }
/** * Get the hierarchy of overridden methods down to {@code result} respecting generics. * @param method lowest to consider * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false * @return Set<Method> in ascending order from sub- to superclass * @throws NullPointerException if the specified method is {@code null} * @since 3.2 */ public static Set<Method> getOverrideHierarchy(final Method method, Interfaces interfacesBehavior) { Validate.notNull(method); final Set<Method> result = new LinkedHashSet<Method>(); result.add(method); final Class<?>[] parameterTypes = method.getParameterTypes(); final Class<?> declaringClass = method.getDeclaringClass(); final Iterator<Class<?>> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); //skip the declaring class :P hierarchy.next(); hierarchyTraversal: while (hierarchy.hasNext()) { final Class<?> c = hierarchy.next(); final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); if (m == null) { continue; } if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { // matches without generics result.add(m); continue; } // necessary to get arguments every time in the case that we are including interfaces final Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); for (int i = 0; i < parameterTypes.length; i++) { final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); if (!TypeUtils.equals(childType, parentType)) { continue hierarchyTraversal; } } result.add(m); } return result; }
/** * Get the hierarchy of overridden methods down to {@code result} respecting generics. * @param method lowest to consider * @param interfacesBehavior whether to search interfaces, {@code null} {@code implies} false * @return Set<Method> in ascending order from sub- to superclass * @throws NullPointerException if the specified method is {@code null} * @since 3.2 */ public static Set<Method> getOverrideHierarchy(final Method method, final Interfaces interfacesBehavior) { Validate.notNull(method); final Set<Method> result = new LinkedHashSet<>(); result.add(method); final Class<?>[] parameterTypes = method.getParameterTypes(); final Class<?> declaringClass = method.getDeclaringClass(); final Iterator<Class<?>> hierarchy = ClassUtils.hierarchy(declaringClass, interfacesBehavior).iterator(); //skip the declaring class :P hierarchy.next(); hierarchyTraversal: while (hierarchy.hasNext()) { final Class<?> c = hierarchy.next(); final Method m = getMatchingAccessibleMethod(c, method.getName(), parameterTypes); if (m == null) { continue; } if (Arrays.equals(m.getParameterTypes(), parameterTypes)) { // matches without generics result.add(m); continue; } // necessary to get arguments every time in the case that we are including interfaces final Map<TypeVariable<?>, Type> typeArguments = TypeUtils.getTypeArguments(declaringClass, m.getDeclaringClass()); for (int i = 0; i < parameterTypes.length; i++) { final Type childType = TypeUtils.unrollVariables(typeArguments, method.getGenericParameterTypes()[i]); final Type parentType = TypeUtils.unrollVariables(typeArguments, m.getGenericParameterTypes()[i]); if (!TypeUtils.equals(childType, parentType)) { continue hierarchyTraversal; } } result.add(m); } return result; }
@Test public void testHierarchyIncludingInterfaces() { final Iterator<Class<?>> iter = ClassUtils.hierarchy(StringParameterizedChild.class, Interfaces.INCLUDE).iterator(); assertEquals(StringParameterizedChild.class, iter.next()); assertEquals(GenericParent.class, iter.next()); assertEquals(GenericConsumer.class, iter.next()); assertEquals(Object.class, iter.next()); assertFalse(iter.hasNext()); }