package com.netflix.governator.guice; import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Module; import com.google.inject.util.Modules; import com.netflix.governator.guice.annotations.Bootstrap; /** * Utility class similar to Guice's Modules that simplifies recipes for * combing Guice modules. * * @author elandau * */ public class ModulesEx { private static final Logger LOG = LoggerFactory.getLogger(ModulesEx.class); public static Module combineAndOverride(Module ... modules) { return combineAndOverride(Arrays.asList(modules)); } /** * Generate a single module that is produced by accumulating and overriding * each module with the next. * * <pre> * {@code * Guice.createInjector(ModuleUtils.combineAndOverride(moduleA, moduleAOverrides, moduleB)); * } * </pre> * * @param modules * @return */ public static Module combineAndOverride(List<? extends Module> modules) { Iterator<? extends Module> iter = modules.iterator(); Module current = Modules.EMPTY_MODULE; if (iter.hasNext()) { current = iter.next(); if (iter.hasNext()) { current = Modules.override(current).with(iter.next()); } } return current; } public static Module fromClass(final Class<?> cls) { return fromClass(cls, true); } /** * Create a single module that derived from all bootstrap annotations * on a class, where that class itself is a module. * * For example, * <pre> * {@code * public class MainApplicationModule extends AbstractModule { * @Override * public void configure() { * // Application specific bindings here * } * * public static void main(String[] args) { * Guice.createInjector(ModulesEx.fromClass(MainApplicationModule.class)); * } * } * } * </pre> * @author elandau */ public static Module fromClass(final Class<?> cls, final boolean override) { List<Module> modules = new ArrayList<>(); // Iterate through all annotations of the main class, create a binding for the annotation // and add the module to the list of modules to install for (final Annotation annot : cls.getDeclaredAnnotations()) { final Class<? extends Annotation> type = annot.annotationType(); Bootstrap bootstrap = type.getAnnotation(Bootstrap.class); if (bootstrap != null) { LOG.info("Adding Module {}", bootstrap.module()); try { modules.add(bootstrap.module().getConstructor(type).newInstance(annot)); } catch (Exception e) { throw new RuntimeException(e); } } } try { if (override) { return Modules.override(combineAndOverride(modules)).with((Module)cls.newInstance()); } else { return Modules.combine(Modules.combine(modules), (Module)cls.newInstance()); } } catch (Exception e) { throw new RuntimeException(e); } } }