/** * Finds the fields annotated with the specified annotation and having the specified type, * retrieves the values and passes those to the specified consumer. * * @since 4.13 */ public <T> void collectAnnotatedFieldValues(Object test, Class<? extends Annotation> annotationClass, Class<T> valueClass, MemberValueConsumer<T> consumer) { for (FrameworkField each : getAnnotatedFields(annotationClass)) { try { Object fieldValue = each.get(test); if (valueClass.isInstance(fieldValue)) { consumer.accept(each, valueClass.cast(fieldValue)); } } catch (IllegalAccessException e) { throw new RuntimeException( "How did getFields return a field we couldn't access?", e); } } }
/** * Finds the methods annotated with the specified annotation and returning the specified type, * invokes it and pass the return value to the specified consumer. * * @since 4.13 */ public <T> void collectAnnotatedMethodValues(Object test, Class<? extends Annotation> annotationClass, Class<T> valueClass, MemberValueConsumer<T> consumer) { for (FrameworkMethod each : getAnnotatedMethods(annotationClass)) { try { /* * A method annotated with @Rule may return a @TestRule or a @MethodRule, * we cannot call the method to check whether the return type matches our * expectation i.e. subclass of valueClass. If we do that then the method * will be invoked twice and we do not want to do that. So we first check * whether return type matches our expectation and only then call the method * to fetch the MethodRule */ if (valueClass.isAssignableFrom(each.getReturnType())) { Object fieldValue = each.invokeExplosively(test); consumer.accept(each, valueClass.cast(fieldValue)); } } catch (Throwable e) { throw new RuntimeException( "Exception in " + each.getName(), e); } } }