This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/isis.git
commit 0645ecde12e94d416bf858387eeca960cb0bc60a Author: Andi Huber <ahu...@apache.org> AuthorDate: Mon Jan 15 11:15:35 2018 +0100 ISIS-1816 refactoring Annotations + implement hierarchy search --- .../isis/core/metamodel/facets/Annotations.java | 103 ++++++++++++++++----- 1 file changed, 80 insertions(+), 23 deletions(-) diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/Annotations.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/Annotations.java index 5a4a45e..3d24c77 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/Annotations.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/Annotations.java @@ -26,13 +26,13 @@ import java.lang.reflect.Method; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; import java.util.stream.Collectors; import javax.validation.constraints.Pattern; import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; -import com.google.common.collect.Lists; - import org.apache.isis.applib.annotation.Collection; import org.apache.isis.applib.annotation.CollectionLayout; import org.apache.isis.applib.annotation.MemberOrder; @@ -43,6 +43,8 @@ import org.apache.isis.core.commons.lang.ThrowableExtensions; import org.apache.isis.core.metamodel.exceptions.MetaModelException; import org.apache.isis.core.metamodel.methodutils.MethodScope; +import com.google.common.collect.Lists; + public final class Annotations { private Annotations() {} @@ -352,48 +354,103 @@ public final class Annotations { /** * Searches for all no-arg methods or fields with a specified title, returning an - * {@link Evaluator} object that wraps either. Will search up hierarchy also. + * {@link Evaluator} object that wraps either. Will search up hierarchy also, + * including implemented interfaces. */ public static <T extends Annotation> List<Evaluator<T>> getEvaluators( final Class<?> cls, final Class<T> annotationClass) { - List<Evaluator<T>> evaluators = Lists.newArrayList(); - appendEvaluators(cls, annotationClass, evaluators); + final List<Evaluator<T>> evaluators = Lists.newArrayList(); + visitEvaluators(cls, annotationClass, evaluators::add); + + // search implemented interfaces + final Class<?>[] interfaces = cls.getInterfaces(); + for (final Class<?> iface : interfaces) { + visitEvaluators(iface, annotationClass, evaluators::add); + } + return evaluators; } + + /** + * Starting from the current class {@code cls}, we search down the inheritance + * hierarchy (super class, super super class, ...), until we find + * the first class that has at least a field or no-arg method with {@code annotationClass} annotation. + * <br/> + * In this hierarchy traversal, implemented interfaces are not processed. + * @param cls + * @param annotationClass + * @return list of {@link Evaluator} that wraps each annotated member found on the class where + * the search stopped, null otherwise + * + * @since 2.0.0 + */ + public static <T extends Annotation> List<Evaluator<T>> findFirstInHierarchyHaving( + final Class<?> cls, + final Class<T> annotationClass) { + + final List<Evaluator<T>> evaluators = Lists.newArrayList(); + visitEvaluatorsWhile(cls, annotationClass, __->evaluators.isEmpty(), evaluators::add); + + return evaluators; + } - private static <T extends Annotation> void appendEvaluators( + private static <T extends Annotation> void visitEvaluators( + final Class<?> cls, + final Class<T> annotationClass, + final Consumer<Evaluator<T>> visitor) { + visitEvaluatorsWhile(cls, annotationClass, __->true, visitor); + } + + private static <T extends Annotation> void visitEvaluatorsWhile( final Class<?> cls, final Class<T> annotationClass, - final List<Evaluator<T>> evaluators) { + Predicate<Class<?>> filter, + final Consumer<Evaluator<T>> visitor) { + + if(!filter.test(cls)) + return; // stop visitation + + collectMethodEvaluators(cls, annotationClass, visitor); + collectFieldEvaluators(cls, annotationClass, visitor); + + // search super-classes + final Class<?> superclass = cls.getSuperclass(); + if (superclass != null) { + visitEvaluatorsWhile(superclass, annotationClass, filter, visitor); + } - for (Method method : cls.getDeclaredMethods()) { + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static <T extends Annotation> void collectMethodEvaluators( + final Class<?> cls, + final Class<T> annotationClass, + final Consumer<Evaluator<T>> action) { + + for (Method method : cls.getDeclaredMethods()) { if(MethodScope.OBJECT.matchesScopeOf(method) && method.getParameterTypes().length == 0) { final Annotation annotation = method.getAnnotation(annotationClass); if(annotation != null) { - evaluators.add(new MethodEvaluator(method, annotation)); + action.accept(new MethodEvaluator(method, annotation)); } } } - for (final Field field: cls.getDeclaredFields()) { + } + + @SuppressWarnings({ "rawtypes", "unchecked" }) + private static <T extends Annotation> void collectFieldEvaluators( + final Class<?> cls, + final Class<T> annotationClass, + final Consumer<Evaluator<T>> action) { + + for (final Field field: cls.getDeclaredFields()) { final Annotation annotation = field.getAnnotation(annotationClass); if(annotation != null) { - evaluators.add(new FieldEvaluator(field, annotation)); + action.accept(new FieldEvaluator(field, annotation)); } } - - // search superclasses - final Class<?> superclass = cls.getSuperclass(); - if (superclass != null) { - appendEvaluators(superclass, annotationClass, evaluators); - } - - // search implemented interfaces - final Class<?>[] interfaces = cls.getInterfaces(); - for (final Class<?> iface : interfaces) { - appendEvaluators(iface, annotationClass, evaluators); - } } public static abstract class Evaluator<T extends Annotation> { -- To stop receiving notification emails like this one, please contact danhayw...@apache.org.