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

org.perfectable.introspection.query.InheritanceQuery Maven / Gradle / Ivy

There is a newer version: 5.1.0
Show newest version
package org.perfectable.introspection.query;

import java.lang.annotation.Annotation;
import java.util.Comparator;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.checkerframework.checker.nullness.qual.Nullable;

import static java.util.Objects.requireNonNull;

/**
 * Iterable-like container that allows access to supertypes of a class.
 *
 * 

This of course only lists types that are actually defined (transitively) by initially-provided class. Although * wildcard types, type variables might be supertype or supertype of specified type, they are not listed. * *

Instances of this class are immutable, each filtering produces new, modified instance. To obtain query for * specific class, use {@link #of}. * *

To obtain results either iterate this class with {@link #iterator} (or in enhanced-for loop) or use one of * {@link #stream()}, {@link #unique()}, {@link #option()} or {@link #isPresent()}. * *

Example usage, which registers all interfaces that DatabaseService implements that are annotated by Remote *

 *     InheritanceQuery.of(DatabaseService.class)
 *         .annotatedWith(Remote.class)
 *         .onlyInterfaces()
 *         .stream()
 *         .forEach(this::register);
 * 
* * @param lower bound of the searched types */ @SuppressWarnings({ "DesignForExtension", // class is closed because of package-private constructor "ClassDataAbstractionCoupling" }) public abstract class InheritanceQuery extends AbstractQuery, InheritanceQuery> { /** * Creates unrestricted query that will list all the supertypes that this class or interface extends/implements. * * @param type class to start search with * @param upper subtype of all results * @return new, unrestricted inheritance query */ public static InheritanceQuery of(Class type) { return new Complete<>(type); } /** * Creates query which lists the same classes as this one, but only if they have an annotation with provided class. * * @param annotationClass annotation class that will be used * @return query filtered for classes annotated with specified class */ public InheritanceQuery annotatedWith(Class annotationClass) { return annotatedWith(AnnotationFilter.single(annotationClass)); } /** * Creates query which lists the same classes as this one, but only if they have an annotation that matches * specified filter. * * @param annotationFilter annotation filter that will be used * @return query filtered for classes annotated with specific properties */ public InheritanceQuery annotatedWith(AnnotationFilter annotationFilter) { requireNonNull(annotationFilter); return new Annotated<>(this, annotationFilter); } @Override public InheritanceQuery filter(Predicate> filter) { return new Predicated<>(this, filter); } @Override public InheritanceQuery sorted(Comparator> comparator) { return new Sorted<>(this, comparator); } /** * Create query which lists the same classes as this one, but only if they are subtypes of provided type, and are * not this type. * * @param supertype supertype of the filtered classes * @return query filtered for subtypes of specified type, excluding it */ public InheritanceQuery upToExcluding(Class supertype) { return new BoundingExcluded<>(this, supertype); } /** * Create query which lists the same classes as this one, but only if they are subtypes of provided type. * *

Note that each type is its own subtype, so if {@code supertype} is actually supertype of initial class * or interface, it will be included in results. * * @param supertype supertype of the filtered classes * @return query filtered for subtypes of specified type, including it */ public InheritanceQuery upToIncluding(Class supertype) { return new BoundingIncluded<>(this, supertype); } /** * Creates query which lists the same classes as this one, but only if they are actually an interface. * * @return query filtered for interfaces */ public InheritanceQuery onlyInterfaces() { return new InterfacesOnly<>(this); } /** * Creates query which lists the same classes as this one, but only if they are actually a class (not an interface). * * @return query filtered for classes */ public InheritanceQuery onlyClasses() { return new ClassesOnly<>(this); } InheritanceQuery() { // package extension only } private static final class Complete extends InheritanceQuery { private final Class initial; Complete(Class initial) { this.initial = initial; } @Override public Stream> stream() { return Streams.generateSingle(initial, InheritanceQuery::safeGetSupertypes); } @Override public boolean contains(@Nullable Object candidate) { if (!(candidate instanceof Class)) { return false; } @SuppressWarnings("unchecked") Class candidateClass = (Class) candidate; return candidateClass.isAssignableFrom(initial); } } private abstract static class Filtered extends InheritanceQuery { private final InheritanceQuery parent; Filtered(InheritanceQuery parent) { this.parent = parent; } protected abstract boolean matches(Class candidate); @Override public Stream> stream() { return this.parent.stream() .filter(this::matches); } @Override public boolean contains(@Nullable Object candidate) { if (!(candidate instanceof Class)) { return false; } @SuppressWarnings("unchecked") Class candidateClass = (Class) candidate; return matches(candidateClass) && parent.contains(candidate); } } private static final class Annotated extends Filtered { private final AnnotationFilter annotationFilter; Annotated(InheritanceQuery parent, AnnotationFilter annotationFilter) { super(parent); this.annotationFilter = annotationFilter; } @Override protected boolean matches(Class candidate) { return this.annotationFilter.matches(candidate); } } private static final class Predicated extends Filtered { private final Predicate> filter; Predicated(InheritanceQuery parent, Predicate> filter) { super(parent); this.filter = filter; } @Override protected boolean matches(Class candidate) { return filter.test(candidate); } } private static class Sorted extends InheritanceQuery { private final InheritanceQuery parent; private final Comparator> comparator; Sorted(InheritanceQuery parent, Comparator> comparator) { this.parent = parent; this.comparator = comparator; } @Override public InheritanceQuery sorted(Comparator> nextComparator) { @SuppressWarnings("unchecked") Comparator<@Nullable Object> casted = (Comparator<@Nullable Object>) nextComparator; return new Sorted<>(parent, this.comparator.thenComparing(casted)); } @Override public Stream> stream() { return this.parent.stream() .sorted(comparator); } @Override public boolean contains(@Nullable Object candidate) { return parent.contains(candidate); } } private static final class BoundingExcluded extends Filtered { private final Class supertype; BoundingExcluded(InheritanceQuery parent, Class supertype) { super(parent); this.supertype = supertype; } @Override protected boolean matches(Class candidate) { return supertype.isAssignableFrom(candidate) && !supertype.equals(candidate); } } private static final class BoundingIncluded extends Filtered { private final Class supertype; BoundingIncluded(InheritanceQuery parent, Class supertype) { super(parent); this.supertype = supertype; } @Override protected boolean matches(Class candidate) { return supertype.isAssignableFrom(candidate); } } private static final class InterfacesOnly extends Filtered { InterfacesOnly(InheritanceQuery parent) { super(parent); } @Override protected boolean matches(Class candidate) { return candidate.isInterface(); } } private static final class ClassesOnly extends Filtered { ClassesOnly(InheritanceQuery parent) { super(parent); } @Override protected boolean matches(Class candidate) { return !candidate.isInterface(); } } private static Stream> safeGetSupertypes(Class type) { Stream.Builder> builder = Stream.builder(); @SuppressWarnings("unchecked") Class[] interfaceArray = (Class[]) type.getInterfaces(); Stream.of(interfaceArray).forEach(builder); @Nullable Class superclass = type.getSuperclass(); if (superclass != null) { builder.accept(superclass); } return builder.build(); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy