package ru.vyarus.guice.ext.core.method; import com.google.inject.TypeLiteral; import com.google.inject.spi.InjectionListener; import com.google.inject.spi.TypeEncounter; import com.google.inject.spi.TypeListener; import ru.vyarus.guice.ext.core.util.Utils; import java.lang.annotation.Annotation; import java.lang.reflect.Method; /** * Generic type listener to process annotated methods after bean instantiation. * * @author Vyacheslav Rusakov * @since 30.06.2014 * @param <T> annotation type */ public class AnnotatedMethodTypeListener<T extends Annotation> implements TypeListener { private final Class<T> annotationClass; private final MethodPostProcessor<T> postProcessor; public AnnotatedMethodTypeListener(final Class<T> annotationClass, final MethodPostProcessor<T> postProcessor) { this.annotationClass = annotationClass; this.postProcessor = postProcessor; } @Override @SuppressWarnings("PMD.AvoidInstantiatingObjectsInLoops") public <I> void hear(final TypeLiteral<I> type, final TypeEncounter<I> encounter) { final Class<? super I> actualType = type.getRawType(); if (!Utils.isPackageValid(actualType)) { return; } Class<? super I> investigatingType = actualType; while (investigatingType != null && !investigatingType.equals(Object.class)) { for (final Method method : investigatingType.getDeclaredMethods()) { if (method.isAnnotationPresent(annotationClass)) { encounter.register(new InjectionListener<I>() { @Override public void afterInjection(final I injectee) { try { method.setAccessible(true); postProcessor.process(method.getAnnotation(annotationClass), method, injectee); } catch (Exception ex) { throw new IllegalStateException( String.format("Failed to process annotation %s on method %s of class %s", annotationClass.getSimpleName(), method.getName(), injectee.getClass().getSimpleName()), ex); } } }); } } investigatingType = investigatingType.getSuperclass(); } } }