001/* 002 * Copyright 2019 Anyware Services 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.ametys.runtime.util; 017 018import java.lang.annotation.Annotation; 019import java.lang.annotation.Inherited; 020import java.util.function.Function; 021import java.util.stream.Stream; 022 023/** 024 * Helper for {@link Annotation}s. 025 */ 026public final class Annotations 027{ 028 private Annotations() 029 { 030 // empty constructor 031 } 032 033 /** 034 * Tests if given {@link Annotation} is present on any of the superclasses or on any of the implemented interfaces. 035 * <br>Unlike {@link Class#isAnnotationPresent}, it also checks into all the implemented interfaces. 036 * <br> The {@link Annotation} must be annotated with {@link Inherited} meta-annotation. 037 * @param classToTest The class to test 038 * @param annotationClass The {@link Annotation} class 039 * @return <code>true</code> if annotation is present on any of the superclasses or on any of the implemented interfaces. 040 */ 041 public static boolean isAnnotationPresent(Class<?> classToTest, Class<? extends Annotation> annotationClass) 042 { 043 return classToTest.isAnnotationPresent(annotationClass) || _isAnnotationPresentOnInterfacesOfSuperclasses(classToTest, annotationClass); 044 } 045 046 private static boolean _isAnnotationPresentOnInterfacesOfSuperclasses(Class<?> classToTest, Class<? extends Annotation> annotationClass) 047 { 048 return _getSuperclassesAndSelf(classToTest) 049 .anyMatch(superclass -> _isAnnotationPresentOnInterfaces(superclass, annotationClass)); 050 } 051 052 private static Stream<Class<?>> _getSuperclassesAndSelf(Class<?> classToTest) 053 { 054 if (classToTest == null) 055 { 056 return Stream.empty(); 057 } 058 else 059 { 060 return Stream.concat( 061 Stream.of(classToTest), 062 _getSuperclassesAndSelf(classToTest.getSuperclass())); 063 } 064 } 065 066 private static boolean _isAnnotationPresentOnInterfaces(Class<?> classToTest, Class<? extends Annotation> annotationClass) 067 { 068 return _getAncestorAndSelfInterfaces(classToTest) 069 .anyMatch(theInterface -> theInterface.isAnnotationPresent(annotationClass)); 070 } 071 072 private static Stream<Class<?>> _getAncestorAndSelfInterfaces(Class<?> classToTest) 073 { 074 return Stream.concat( 075 Stream.of(classToTest), 076 _getAncestorInterfaces(classToTest)); 077 } 078 079 private static Stream<Class<?>> _getAncestorInterfaces(Class<?> classToTest) 080 { 081 return _getSuperInterfaces(classToTest) 082 .map(Annotations::_getAncestorAndSelfInterfaces) 083 .flatMap(Function.identity()); 084 } 085 086 private static Stream<Class<?>> _getSuperInterfaces(Class<?> classToTest) 087 { 088 return Stream.of(classToTest.getInterfaces()); 089 } 090} 091