1 /* 2 * ************************************************************************************************************************************************************* 3 * 4 * TheseFoolishThings: Miscellaneous utilities 5 * http://tidalwave.it/projects/thesefoolishthings 6 * 7 * Copyright (C) 2009 - 2025 by Tidalwave s.a.s. (http://tidalwave.it) 8 * 9 * ************************************************************************************************************************************************************* 10 * 11 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. 12 * You may obtain a copy of the License at 13 * 14 * http://www.apache.org/licenses/LICENSE-2.0 15 * 16 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 17 * CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 18 * 19 * ************************************************************************************************************************************************************* 20 * 21 * git clone https://bitbucket.org/tidalwave/thesefoolishthings-src 22 * git clone https://github.com/tidalwave-it/thesefoolishthings-src 23 * 24 * ************************************************************************************************************************************************************* 25 */ 26 package it.tidalwave.messagebus.spi; 27 28 import java.lang.annotation.Annotation; 29 import java.lang.reflect.Method; 30 import javax.annotation.Nonnull; 31 import java.util.ArrayList; 32 import java.util.Collections; 33 import java.util.List; 34 35 /*************************************************************************************************************************************************************** 36 * 37 * @author Fabrizio Giudici 38 * 39 **************************************************************************************************************************************************************/ 40 public class ReflectionUtils 41 { 42 /*********************************************************************************************************************************************************** 43 * 44 **********************************************************************************************************************************************************/ 45 public static interface MethodProcessor 46 { 47 enum FilterResult { ACCEPT, IGNORE } 48 49 public FilterResult filter (@Nonnull Class<?> clazz); 50 51 public void process (@Nonnull Method method); 52 } 53 54 /*********************************************************************************************************************************************************** 55 * 56 **********************************************************************************************************************************************************/ 57 public static class MethodProcessorSupport implements MethodProcessor 58 { 59 @Override @Nonnull 60 public FilterResult filter (@Nonnull final Class<?> clazz) 61 { 62 return FilterResult.ACCEPT; 63 } 64 65 @Override 66 public void process (@Nonnull final Method method) 67 { 68 } 69 } 70 71 /*********************************************************************************************************************************************************** 72 * Navigates the hierarchy of the given object, top down, and applies the {@link MethodProcessor} to all the 73 * methods of each class, if not filtered out by the processor itself. 74 * 75 * @param object the object at the bottom of the hierarchy 76 * @param processor the processor 77 **********************************************************************************************************************************************************/ 78 public static void forEachMethodInTopDownHierarchy (@Nonnull final Object object, 79 @Nonnull final MethodProcessor processor) 80 { 81 for (final var clazz : getClassHierarchy(object.getClass())) 82 { 83 for (final var method : clazz.getDeclaredMethods()) 84 { 85 processor.process(method); 86 } 87 } 88 } 89 90 /*********************************************************************************************************************************************************** 91 * Navigates the hierarchy of the given object, bottom up, and applies the {@link MethodProcessor} to all the 92 * methods of each class, if not filtered out by the processor itself. 93 * 94 * @param object the object at the bottom of the hierarchy 95 * @param processor the processor 96 **********************************************************************************************************************************************************/ 97 public static void forEachMethodInBottomUpHierarchy (@Nonnull final Object object, 98 @Nonnull final MethodProcessor processor) 99 { 100 final var hierarchy = getClassHierarchy(object.getClass()); 101 Collections.reverse(hierarchy); 102 103 for (final var clazz : hierarchy) 104 { 105 if (processor.filter(clazz) == MethodProcessor.FilterResult.ACCEPT) 106 { 107 for (final var method : clazz.getDeclaredMethods()) 108 { 109 processor.process(method); 110 } 111 } 112 } 113 } 114 115 /*********************************************************************************************************************************************************** 116 * Returns the hierarchy of the given class, top down. 117 * 118 * @param clazz the clazz at the bottom of the hierarchy 119 * @return the hierarchy 120 **********************************************************************************************************************************************************/ 121 @Nonnull 122 private static List<Class<?>> getClassHierarchy (@Nonnull final Class<?> clazz) 123 { 124 final List<Class<?>> hierarchy = new ArrayList<>(); 125 126 for (var ancestor = clazz; ancestor != null; ancestor = ancestor.getSuperclass()) 127 { 128 hierarchy.add(0, ancestor); 129 } 130 131 return hierarchy; 132 } 133 134 /*********************************************************************************************************************************************************** 135 * Checks whether an array of annotations contains an annotation of the given type. 136 * 137 * @param annotations the annotations to check 138 * @param annotationClass the type of the required annotation 139 * @return true if the annotation is found 140 **********************************************************************************************************************************************************/ 141 public static boolean containsAnnotation (@Nonnull final Annotation[] annotations, 142 @Nonnull final Class<?> annotationClass) 143 { 144 for (final var annotation : annotations) 145 { 146 if (annotationClass.isAssignableFrom(annotation.getClass())) 147 { 148 return true; 149 } 150 } 151 152 return false; 153 } 154 }