package org.hotswap.agent.annotation.handler; import org.hotswap.agent.annotation.*; import org.hotswap.agent.config.PluginManager; import org.hotswap.agent.logging.AgentLogger; import java.lang.annotation.Annotation; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; /** * Process annotations on a plugin, register appropriate handlers. * * @author Jiri Bubnik */ public class AnnotationProcessor { private static AgentLogger LOGGER = AgentLogger.getLogger(AnnotationProcessor.class); protected PluginManager pluginManager; public AnnotationProcessor(PluginManager pluginManager) { this.pluginManager = pluginManager; init(pluginManager); } protected Map<Class<? extends Annotation>, PluginHandler> handlers = new HashMap<Class<? extends Annotation>, PluginHandler>(); public void init(PluginManager pluginManager) { addAnnotationHandler(Init.class, new InitHandler(pluginManager)); addAnnotationHandler(OnClassLoadEvent.class, new OnClassLoadedHandler(pluginManager)); addAnnotationHandler(OnClassFileEvent.class, new WatchHandler(pluginManager)); addAnnotationHandler(OnResourceFileEvent.class, new WatchHandler(pluginManager)); } public void addAnnotationHandler(Class<? extends Annotation> annotation, PluginHandler handler) { handlers.put(annotation, handler); } /** * Process annotations on the plugin class - only static methods, methods to hook plugin initialization. * * @param processClass class to process annotation * @param pluginClass main plugin class (annotated with @Plugin) * @return true if success */ public boolean processAnnotations(Class processClass, Class pluginClass) { try { for (Field field : processClass.getDeclaredFields()) { if (Modifier.isStatic(field.getModifiers())) if (!processFieldAnnotations(null, field, pluginClass)) return false; } for (Method method : processClass.getDeclaredMethods()) { if (Modifier.isStatic(method.getModifiers())) if (!processMethodAnnotations(null, method, pluginClass)) return false; } // process annotations on all supporting classes in addition to the plugin itself for (Annotation annotation : processClass.getDeclaredAnnotations()) { if (annotation instanceof Plugin) { for (Class supportClass : ((Plugin) annotation).supportClass()) { processAnnotations(supportClass, pluginClass); } } } return true; } catch (Throwable e) { LOGGER.error("Unable to process plugin annotations '{}'", e, pluginClass); return false; } } /** * Process annotations on a plugin - non static fields and methods. * * @param plugin plugin object * @return true if success */ public boolean processAnnotations(Object plugin) { LOGGER.debug("Processing annotations for plugin '" + plugin + "'."); Class pluginClass = plugin.getClass(); for (Field field : pluginClass.getDeclaredFields()) { if (!Modifier.isStatic(field.getModifiers())) if (!processFieldAnnotations(plugin, field, pluginClass)) return false; } for (Method method : pluginClass.getDeclaredMethods()) { if (!Modifier.isStatic(method.getModifiers())) if (!processMethodAnnotations(plugin, method, pluginClass)) return false; } return true; } @SuppressWarnings("unchecked") private boolean processFieldAnnotations(Object plugin, Field field, Class pluginClass) { // for all fields and all handlers for (Annotation annotation : field.getDeclaredAnnotations()) { for (Class<? extends Annotation> handlerAnnotation : handlers.keySet()) { if (annotation.annotationType().equals(handlerAnnotation)) { // initialize PluginAnnotation<?> pluginAnnotation = new PluginAnnotation<>(pluginClass, plugin, annotation, field); if (!handlers.get(handlerAnnotation).initField(pluginAnnotation)) { return false; } } } } return true; } @SuppressWarnings("unchecked") private boolean processMethodAnnotations(Object plugin, Method method, Class pluginClass) { // for all methods and all handlers for (Annotation annotation : method.getDeclaredAnnotations()) { for (Class<? extends Annotation> handlerAnnotation : handlers.keySet()) { if (annotation.annotationType().equals(handlerAnnotation)) { // initialize PluginAnnotation<?> pluginAnnotation = new PluginAnnotation<>(pluginClass, plugin, annotation, method); if (!handlers.get(handlerAnnotation).initMethod(pluginAnnotation)) { return false; } } } } return true; } }