View Javadoc
1   /*
2    * *************************************************************************************************************************************************************
3    *
4    * TheseFoolishThings: Miscellaneous utilities
5    * http://tidalwave.it/projects/thesefoolishthings
6    *
7    * Copyright (C) 2009 - 2024 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   }