All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.jqwik.engine.support.JqwikAnnotationSupport Maven / Gradle / Ivy

The newest version!
package net.jqwik.engine.support;

import java.lang.annotation.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.stream.*;

import org.apiguardian.api.*;
import org.junit.platform.commons.support.*;

import net.jqwik.engine.discovery.predicates.*;

/**
 * Provide stuff that org.junit.commons.support.AnnotationSupport does not.
 */
public class JqwikAnnotationSupport {

	/**
	 * Find all annotations in an element, even if they are repeatable or only present through meta-annotations
	 *
	 * @param element the element to check for present annotations
	 * @return a list of all found annotations
	 */
	public static List findAllAnnotations(AnnotatedElement element) {
		List annotations = new ArrayList<>();
		List presentAnnotations = Arrays.asList(getDeclaredAnnotations(element));
		annotations.addAll(presentAnnotations);
		presentAnnotations.forEach(annotation -> appendMetaAnnotations(annotation, annotations));
		return annotations;
	}

	private static Annotation[] getDeclaredAnnotations(AnnotatedElement element) {
		if (element instanceof AnnotatedArrayType) {
			return ((AnnotatedArrayType) element).getAnnotatedGenericComponentType().getAnnotations();
		}
		return element.getAnnotations();
	}

	private static void appendMetaAnnotations(Annotation annotation, List collector) {
		Stream metaAnnotationStream = streamMetaAnnotations(annotation);
		metaAnnotationStream
			.filter(candidate -> !collector.contains(candidate))
			.forEach(metaAnnotation -> {
				collector.add(metaAnnotation);
				appendMetaAnnotations(metaAnnotation, collector);
			});
	}

	public static List allMetaAnnotations(Annotation annotation) {
		List all = new ArrayList<>();
		Stream metaAnnotationStream = streamMetaAnnotations(annotation);
		metaAnnotationStream
			.filter(candidate -> !all.contains(candidate))
			.forEach(metaAnnotation -> {
				all.add(metaAnnotation);
				appendMetaAnnotations(metaAnnotation, all);
			});
		return all;
	}

	private static Stream streamMetaAnnotations(Annotation annotation) {
		Annotation[] metaAnnotationCandidates = annotation.annotationType().getDeclaredAnnotations();
		return Arrays.stream(metaAnnotationCandidates)
					 .filter(candidate -> !isInJavaLangAnnotationPackage(candidate.annotationType()))
					 .filter(candidate -> !isApiAnnotation(candidate.annotationType()));

	}

	private static boolean isApiAnnotation(Class annotationType) {
		return annotationType == API.class;
	}

	private static boolean isInJavaLangAnnotationPackage(Class annotationType) {
		return (annotationType != null && annotationType.getName().startsWith("java.lang.annotation"));
	}

	public static  List findRepeatableAnnotationOnElementOrContainer(
		AnnotatedElement element,
		Class annotationType
	) {
		List annotations = new ArrayList<>(AnnotationSupport.findRepeatableAnnotations(element, annotationType));
		if (element instanceof Member) {
			AnnotatedElement container = ((Member) element).getDeclaringClass();
			annotations.addAll(findRepeatableAnnotationOnElementOrContainer(container, annotationType));
		}
		if (isGroup(element)) {
			AnnotatedElement container = getGroupContainer((Class) element);
			annotations.addAll(findRepeatableAnnotationOnElementOrContainer(container, annotationType));
		}
		return annotations;
	}

	private static AnnotatedElement getGroupContainer(Class group) {
		return group.getDeclaringClass();
	}

	private static boolean isGroup(AnnotatedElement element) {
		if (element instanceof Class) {
			return new IsContainerAGroup().test((Class) element);
		}
		return false;
	}

	/**
	 * Find all annotation instances of a given type on a container class, even if they are repeatable or annotated.
	 * 

* Sort those annotations from closer (directly on class) to more remote (on extended classes and interfaces) */ public static List findContainerAnnotations( Class container, Class annotationType ) { if (isRepeatable(annotationType)) { // Sorting of repeatable annotations is wrong. Reverting makes it better but not perfect. List repeatableAnnotations = new ArrayList<>(AnnotationSupport.findRepeatableAnnotations(container, annotationType)); Collections.reverse(repeatableAnnotations); return repeatableAnnotations; } List collector = new ArrayList<>(); appendContainerAnnotations(container, annotationType, collector); return collector; } private static void appendContainerAnnotations( Class container, Class annotationType, List collector ) { findDeclaredAnnotations(container, annotationType) .forEach(annotation -> { if (!collector.contains(annotation)) { collector.add(annotation); } appendInheritedAnnotations(container, annotationType, collector); }); } private static Stream findDeclaredAnnotations(Class container, Class annotationType) { return JqwikStreamSupport.toStream(AnnotationSupport.findAnnotation(container, annotationType)); } private static void appendInheritedAnnotations( Class container, Class annotationType, List collector ) { if (isInherited(annotationType)) { List inheritedAnnotations = inheritedAnnotations(container, annotationType); for (A inheritedAnnotation : inheritedAnnotations) { if (!collector.contains(inheritedAnnotation)) { collector.add(inheritedAnnotation); } } } } private static List inheritedAnnotations(Class container, Class annotationType) { List inheritedAnnotations = new ArrayList<>(); Class superclass = container.getSuperclass(); if (superclass != null) { appendContainerAnnotations(superclass, annotationType, inheritedAnnotations); } for (Class anInterface : container.getInterfaces()) { appendContainerAnnotations(anInterface, annotationType, inheritedAnnotations); } return inheritedAnnotations; } private static boolean isInherited(Class annotationType) { return annotationType.isAnnotationPresent(Inherited.class); } private static boolean isRepeatable(Class annotationType) { return annotationType.isAnnotationPresent(Repeatable.class); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy