MethodUtils.java
001 /*
002  * Copyright 2008-2016 the original author or authors.
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  */
016 package org.codehaus.griffon.runtime.injection;
017 
018 import griffon.exceptions.InstanceMethodInvocationException;
019 
020 import javax.annotation.Nonnull;
021 import java.lang.annotation.Annotation;
022 import java.lang.reflect.InvocationTargetException;
023 import java.lang.reflect.Method;
024 import java.security.AccessController;
025 import java.security.PrivilegedAction;
026 import java.util.ArrayList;
027 import java.util.List;
028 
029 /**
030  @author Andres Almiray
031  */
032 public final class MethodUtils {
033     /**
034      @since 2.6.0
035      */
036     public static boolean hasMethodAnnotatedwith(@Nonnull final Object instance, @Nonnull final Class<? extends Annotation> annotation) {
037         Class<?> klass = instance.getClass();
038         while (klass != null) {
039             boolean found = false;
040             for (Method method : klass.getDeclaredMethods()) {
041                 if (method.isAnnotationPresent(annotation&&
042                     method.getParameterTypes().length == 0) {
043                     return true;
044                 }
045             }
046 
047             klass = klass.getSuperclass();
048         }
049 
050         return false;
051     }
052 
053     public static void invokeAnnotatedMethod(@Nonnull final Object instance, @Nonnull final Class<? extends Annotation> annotation) {
054         List<Method> methods = new ArrayList<>();
055         Class<?> klass = instance.getClass();
056         while (klass != null) {
057             boolean found = false;
058             for (Method method : klass.getDeclaredMethods()) {
059                 if (method.isAnnotationPresent(annotation&&
060                     method.getParameterTypes().length == 0) {
061                     if (found) {
062                         throw new InstanceMethodInvocationException(instance, method, buildCause(instance.getClass(), method, methods));
063                     }
064                     methods.add(method);
065                     found = true;
066                 }
067             }
068 
069             klass = klass.getSuperclass();
070         }
071 
072         for (final Method method : methods) {
073             AccessController.doPrivileged(new PrivilegedAction<Object>() {
074                 @Override
075                 public Object run() {
076                     boolean wasAccessible = method.isAccessible();
077                     try {
078                         method.setAccessible(true);
079                         return method.invoke(instance);
080                     catch (IllegalAccessException | IllegalArgumentException e) {
081                         throw new InstanceMethodInvocationException(instance, method.getName(), null, e);
082                     catch (InvocationTargetException e) {
083                         throw new InstanceMethodInvocationException(instance, method.getName(), null, e.getTargetException());
084                     finally {
085                         method.setAccessible(wasAccessible);
086                     }
087                 }
088             });
089         }
090     }
091 
092     @Nonnull
093     private static Throwable buildCause(@Nonnull Class<?> clazz, @Nonnull Method method, @Nonnull List<Method> methods) {
094         StringBuilder b = new StringBuilder("The following methods were found annotated with @PostConstruct on ")
095             .append(clazz);
096         for (Method m : methods) {
097             b.append("\n  ").append(m.toGenericString());
098         }
099         b.append("\n  ").append(method.toGenericString());
100         return new IllegalStateException(b.toString());
101     }
102 }