AnnotationUtil.java

package net.morimekta.testing.junit5;

import org.junit.jupiter.api.extension.ExtensionContext;

import java.lang.annotation.Annotation;
import java.util.Optional;
import java.util.stream.Stream;

public final class AnnotationUtil {
    public static <A extends Annotation> boolean isAnnotationPresent(ExtensionContext context, Class<A> annotation) {
        return getTopAnnotation(context, annotation).isPresent();
    }

    public static <A extends Annotation> Optional<A> getTopAnnotation(
            ExtensionContext context, Class<A> annotation) {
        return context
                .getTestMethod()
                .map(m -> m.getDeclaredAnnotation(annotation))
                .or(() -> context.getTestClass().flatMap(t -> getTopAnnotation(t, annotation)));
    }

    public static <T extends Annotation> Stream<T> getAnnotationsBottomUp(
            ExtensionContext context, Class<T> annotation) {
        return Stream.concat(
                context.getTestClass()
                       .stream()
                       .flatMap(t -> getAnnotationsBottomUp(t, annotation)),
                context.getTestMethod()
                       .map(m -> m.getDeclaredAnnotation(annotation))
                       .stream());
    }

    // --- Private ---

    private static <T extends Annotation> Optional<T> getTopAnnotation(
            Class<?> type, Class<T> annotation) {
        return Optional.ofNullable(type.getDeclaredAnnotation(annotation))
                       .or(() -> Optional.ofNullable(type.getSuperclass())
                                         .flatMap(t -> getTopAnnotation(t, annotation)));
    }

    private static <T extends Annotation> Stream<T> getAnnotationsBottomUp(
            Class<?> type, Class<T> annotation) {
        return Stream.concat(
                Optional.ofNullable(type.getSuperclass())
                        .stream()
                        .flatMap(t -> getAnnotationsBottomUp(t, annotation)),
                Optional.ofNullable(type.getDeclaredAnnotation(annotation))
                        .stream());
    }

    private AnnotationUtil() {}
}