package com.netflix.governator.internal; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Collections; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import javax.annotation.PostConstruct; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.base.Supplier; import com.netflix.governator.LifecycleAction; import com.netflix.governator.LifecycleFeature; import com.netflix.governator.internal.JSR250LifecycleAction.ValidationMode; import com.netflix.governator.internal.TypeInspector.TypeVisitor; /** * Special LifecycleFeature to support @PostConstruct annotation processing. * Note that this feature is implicit in LifecycleModule and therefore does not * need to be added using the LifecycleFeature multibinding. * * @author elandau */ public final class PostConstructLifecycleFeature implements LifecycleFeature { private static final Logger LOG = LoggerFactory.getLogger(PostConstructLifecycleFeature.class); private final ValidationMode validationMode; public PostConstructLifecycleFeature(ValidationMode validationMode) { this.validationMode = validationMode; } @Override public List<LifecycleAction> getActionsForType(final Class<?> type) { return TypeInspector.accept(type, new PostConstructVisitor()); } @Override public String toString() { return "PostConstruct"; } private class PostConstructVisitor implements TypeVisitor, Supplier<List<LifecycleAction>> { private final Set<String> visitContext; private final LinkedList<LifecycleAction> typeActions; public PostConstructVisitor() { this.visitContext = new HashSet<>(); this.typeActions = new LinkedList<>(); } @Override public boolean visit(final Class<?> clazz) { return !clazz.isInterface(); } @Override public boolean visit(final Method method) { final String methodName = method.getName(); if (method.isAnnotationPresent(PostConstruct.class)) { if (!visitContext.contains(methodName)) { try { LifecycleAction postConstructAction = new JSR250LifecycleAction(PostConstruct.class, method, validationMode); LOG.debug("adding action {}", postConstructAction); this.typeActions.addFirst(postConstructAction); visitContext.add(methodName); } catch (IllegalArgumentException e) { LOG.info("ignoring @PostConstruct method {}.{}() - {}", method.getDeclaringClass().getName(), methodName, e.getMessage()); } } } else if (method.getReturnType() == Void.TYPE && method.getParameterTypes().length == 0 && !Modifier.isFinal(method.getModifiers())) { // method potentially overrides superclass method and annotations visitContext.add(methodName); } return true; } @Override public boolean visit(Field field) { return true; } @Override public List<LifecycleAction> get() { return Collections.unmodifiableList(typeActions); } } }