Home | History | Annotate | Download | only in spi
      1 /**
      2  * Copyright (C) 2008 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject.spi;
     18 
     19 import static com.google.common.base.Preconditions.checkArgument;
     20 import static com.google.inject.internal.InternalFlags.getIncludeStackTraceOption;
     21 
     22 import com.google.common.collect.ImmutableList;
     23 import com.google.common.collect.Lists;
     24 import com.google.common.collect.Maps;
     25 import com.google.common.collect.Sets;
     26 import com.google.inject.AbstractModule;
     27 import com.google.inject.Binder;
     28 import com.google.inject.Binding;
     29 import com.google.inject.Key;
     30 import com.google.inject.MembersInjector;
     31 import com.google.inject.Module;
     32 import com.google.inject.PrivateBinder;
     33 import com.google.inject.PrivateModule;
     34 import com.google.inject.Provider;
     35 import com.google.inject.Scope;
     36 import com.google.inject.Stage;
     37 import com.google.inject.TypeLiteral;
     38 import com.google.inject.binder.AnnotatedBindingBuilder;
     39 import com.google.inject.binder.AnnotatedConstantBindingBuilder;
     40 import com.google.inject.binder.AnnotatedElementBuilder;
     41 import com.google.inject.internal.AbstractBindingBuilder;
     42 import com.google.inject.internal.BindingBuilder;
     43 import com.google.inject.internal.ConstantBindingBuilderImpl;
     44 import com.google.inject.internal.Errors;
     45 import com.google.inject.internal.ExposureBuilder;
     46 import com.google.inject.internal.InternalFlags.IncludeStackTraceOption;
     47 import com.google.inject.internal.MoreTypes;
     48 import com.google.inject.internal.PrivateElementsImpl;
     49 import com.google.inject.internal.ProviderMethodsModule;
     50 import com.google.inject.internal.util.SourceProvider;
     51 import com.google.inject.internal.util.StackTraceElements;
     52 import com.google.inject.matcher.Matcher;
     53 
     54 import java.lang.annotation.Annotation;
     55 import java.lang.reflect.Method;
     56 import java.util.Arrays;
     57 import java.util.Collection;
     58 import java.util.Collections;
     59 import java.util.List;
     60 import java.util.Map;
     61 import java.util.Set;
     62 
     63 /**
     64  * Exposes elements of a module so they can be inspected, validated or {@link
     65  * Element#applyTo(Binder) rewritten}.
     66  *
     67  * @author jessewilson (at) google.com (Jesse Wilson)
     68  * @since 2.0
     69  */
     70 public final class Elements {
     71 
     72   private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR
     73       = new DefaultBindingTargetVisitor<Object, Object>() {
     74     @Override public Object visit(InstanceBinding<?> binding) {
     75       return binding.getInstance();
     76     }
     77 
     78     @Override protected Object visitOther(Binding<?> binding) {
     79       throw new IllegalArgumentException();
     80     }
     81   };
     82 
     83   /**
     84    * Records the elements executed by {@code modules}.
     85    */
     86   public static List<Element> getElements(Module... modules) {
     87     return getElements(Stage.DEVELOPMENT, Arrays.asList(modules));
     88   }
     89 
     90   /**
     91    * Records the elements executed by {@code modules}.
     92    */
     93   public static List<Element> getElements(Stage stage, Module... modules) {
     94     return getElements(stage, Arrays.asList(modules));
     95   }
     96 
     97   /**
     98    * Records the elements executed by {@code modules}.
     99    */
    100   public static List<Element> getElements(Iterable<? extends Module> modules) {
    101     return getElements(Stage.DEVELOPMENT, modules);
    102   }
    103 
    104   /**
    105    * Records the elements executed by {@code modules}.
    106    */
    107   public static List<Element> getElements(Stage stage, Iterable<? extends Module> modules) {
    108     RecordingBinder binder = new RecordingBinder(stage);
    109     for (Module module : modules) {
    110       binder.install(module);
    111     }
    112     binder.scanForAnnotatedMethods();
    113     for (RecordingBinder child : binder.privateBinders) {
    114       child.scanForAnnotatedMethods();
    115     }
    116     // Free the memory consumed by the stack trace elements cache
    117     StackTraceElements.clearCache();
    118     return Collections.unmodifiableList(binder.elements);
    119   }
    120 
    121   private static class ElementsAsModule implements Module {
    122     private final Iterable<? extends Element> elements;
    123 
    124     ElementsAsModule(Iterable<? extends Element> elements) {
    125       this.elements = elements;
    126     }
    127 
    128     @Override
    129     public void configure(Binder binder) {
    130       for (Element element : elements) {
    131         element.applyTo(binder);
    132       }
    133     }
    134   }
    135 
    136   /**
    137    * Returns the module composed of {@code elements}.
    138    */
    139   public static Module getModule(final Iterable<? extends Element> elements) {
    140     return new ElementsAsModule(elements);
    141   }
    142 
    143   @SuppressWarnings("unchecked")
    144   static <T> BindingTargetVisitor<T, T> getInstanceVisitor() {
    145     return (BindingTargetVisitor<T, T>) GET_INSTANCE_VISITOR;
    146   }
    147 
    148   private static class ModuleInfo {
    149     private final Binder binder;
    150     private final ModuleSource moduleSource;
    151     private final boolean skipScanning;
    152 
    153     private ModuleInfo(Binder binder, ModuleSource moduleSource, boolean skipScanning) {
    154       this.binder = binder;
    155       this.moduleSource = moduleSource;
    156       this.skipScanning = skipScanning;
    157     }
    158   }
    159 
    160   private static class RecordingBinder implements Binder, PrivateBinder {
    161     private final Stage stage;
    162     private final Map<Module, ModuleInfo> modules;
    163     private final List<Element> elements;
    164     private final Object source;
    165     /** The current modules stack */
    166     private ModuleSource moduleSource = null;
    167     private final SourceProvider sourceProvider;
    168     private final Set<ModuleAnnotatedMethodScanner> scanners;
    169 
    170     /** The binder where exposed bindings will be created */
    171     private final RecordingBinder parent;
    172     private final PrivateElementsImpl privateElements;
    173 
    174     /** All children private binders, so we can scan through them. */
    175     private final List<RecordingBinder> privateBinders;
    176 
    177     private RecordingBinder(Stage stage) {
    178       this.stage = stage;
    179       this.modules = Maps.newLinkedHashMap();
    180       this.scanners = Sets.newLinkedHashSet();
    181       this.elements = Lists.newArrayList();
    182       this.source = null;
    183       this.sourceProvider = SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses(
    184           Elements.class, RecordingBinder.class, AbstractModule.class,
    185           ConstantBindingBuilderImpl.class, AbstractBindingBuilder.class, BindingBuilder.class);
    186       this.parent = null;
    187       this.privateElements = null;
    188       this.privateBinders = Lists.newArrayList();
    189     }
    190 
    191     /** Creates a recording binder that's backed by {@code prototype}. */
    192     private RecordingBinder(
    193         RecordingBinder prototype, Object source, SourceProvider sourceProvider) {
    194       checkArgument(source == null ^ sourceProvider == null);
    195 
    196       this.stage = prototype.stage;
    197       this.modules = prototype.modules;
    198       this.elements = prototype.elements;
    199       this.scanners = prototype.scanners;
    200       this.source = source;
    201       this.moduleSource = prototype.moduleSource;
    202       this.sourceProvider = sourceProvider;
    203       this.parent = prototype.parent;
    204       this.privateElements = prototype.privateElements;
    205       this.privateBinders = prototype.privateBinders;
    206     }
    207 
    208     /** Creates a private recording binder. */
    209     private RecordingBinder(RecordingBinder parent, PrivateElementsImpl privateElements) {
    210       this.stage = parent.stage;
    211       this.modules = Maps.newLinkedHashMap();
    212       this.scanners = Sets.newLinkedHashSet(parent.scanners);
    213       this.elements = privateElements.getElementsMutable();
    214       this.source = parent.source;
    215       this.moduleSource = parent.moduleSource;
    216       this.sourceProvider = parent.sourceProvider;
    217       this.parent = parent;
    218       this.privateElements = privateElements;
    219       this.privateBinders = parent.privateBinders;
    220     }
    221 
    222     /*if[AOP]*/
    223     @Override
    224     public void bindInterceptor(
    225         Matcher<? super Class<?>> classMatcher,
    226         Matcher<? super Method> methodMatcher,
    227         org.aopalliance.intercept.MethodInterceptor... interceptors) {
    228       elements.add(new InterceptorBinding(
    229           getElementSource(), classMatcher, methodMatcher, interceptors));
    230     }
    231     /*end[AOP]*/
    232 
    233     @Override
    234     public void bindScope(Class<? extends Annotation> annotationType, Scope scope) {
    235       elements.add(new ScopeBinding(getElementSource(), annotationType, scope));
    236     }
    237 
    238     @Override
    239     @SuppressWarnings("unchecked") // it is safe to use the type literal for the raw type
    240     public void requestInjection(Object instance) {
    241       requestInjection((TypeLiteral<Object>) TypeLiteral.get(instance.getClass()), instance);
    242     }
    243 
    244     @Override
    245     public <T> void requestInjection(TypeLiteral<T> type, T instance) {
    246       elements.add(new InjectionRequest<T>(getElementSource(), MoreTypes.canonicalizeForKey(type),
    247           instance));
    248     }
    249 
    250     @Override
    251     public <T> MembersInjector<T> getMembersInjector(final TypeLiteral<T> typeLiteral) {
    252       final MembersInjectorLookup<T> element = new MembersInjectorLookup<T>(getElementSource(),
    253           MoreTypes.canonicalizeForKey(typeLiteral));
    254       elements.add(element);
    255       return element.getMembersInjector();
    256     }
    257 
    258     public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
    259       return getMembersInjector(TypeLiteral.get(type));
    260     }
    261 
    262     public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) {
    263       elements.add(new TypeListenerBinding(getElementSource(), listener, typeMatcher));
    264     }
    265 
    266     public void bindListener(Matcher<? super Binding<?>> bindingMatcher,
    267         ProvisionListener... listeners) {
    268       elements.add(new ProvisionListenerBinding(getElementSource(), bindingMatcher, listeners));
    269     }
    270 
    271     public void requestStaticInjection(Class<?>... types) {
    272       for (Class<?> type : types) {
    273         elements.add(new StaticInjectionRequest(getElementSource(), type));
    274       }
    275     }
    276 
    277     /**
    278      * Applies all scanners to the modules we've installed. We skip certain
    279      * PrivateModules because store them in more than one Modules map and only
    280      * want to process them through one of the maps.  (They're stored in both
    281      * maps to prevent a module from being installed more than once.)
    282      */
    283     void scanForAnnotatedMethods() {
    284       for (ModuleAnnotatedMethodScanner scanner : scanners) {
    285         // Note: we must iterate over a copy of the modules because calling install(..)
    286         // will mutate modules, otherwise causing a ConcurrentModificationException.
    287         for (Map.Entry<Module, ModuleInfo> entry : Maps.newLinkedHashMap(modules).entrySet()) {
    288           Module module = entry.getKey();
    289           ModuleInfo info = entry.getValue();
    290           if (info.skipScanning) {
    291             continue;
    292           }
    293           moduleSource = entry.getValue().moduleSource;
    294           try {
    295             info.binder.install(ProviderMethodsModule.forModule(module, scanner));
    296           } catch(RuntimeException e) {
    297             Collection<Message> messages = Errors.getMessagesFromThrowable(e);
    298             if (!messages.isEmpty()) {
    299               elements.addAll(messages);
    300             } else {
    301               addError(e);
    302             }
    303           }
    304         }
    305       }
    306       moduleSource = null;
    307     }
    308 
    309     public void install(Module module) {
    310       if (!modules.containsKey(module)) {
    311         RecordingBinder binder = this;
    312         boolean unwrapModuleSource = false;
    313         // Update the module source for the new module
    314         if (module instanceof ProviderMethodsModule) {
    315           // There are two reason's we'd want to get the module source in a ProviderMethodsModule.
    316           // ModuleAnnotatedMethodScanner lets users scan their own modules for @Provides-like
    317           // bindings.  If they install the module at a top-level, then moduleSource can be null.
    318           // Also, if they pass something other than 'this' to it, we'd have the wrong source.
    319           Object delegate = ((ProviderMethodsModule) module).getDelegateModule();
    320           if (moduleSource == null
    321               || !moduleSource.getModuleClassName().equals(delegate.getClass().getName())) {
    322             moduleSource = getModuleSource(delegate);
    323             unwrapModuleSource = true;
    324           }
    325         } else {
    326           moduleSource = getModuleSource(module);
    327           unwrapModuleSource = true;
    328         }
    329         boolean skipScanning = false;
    330         if (module instanceof PrivateModule) {
    331           binder = (RecordingBinder) binder.newPrivateBinder();
    332           // Store the module in the private binder too so we scan for it.
    333           binder.modules.put(module, new ModuleInfo(binder, moduleSource, false));
    334           skipScanning = true; // don't scan this module in the parent's module set.
    335         }
    336         // Always store this in the parent binder (even if it was a private module)
    337         // so that we know not to process it again, and so that scanners inherit down.
    338         modules.put(module, new ModuleInfo(binder, moduleSource, skipScanning));
    339         try {
    340           module.configure(binder);
    341         } catch (RuntimeException e) {
    342           Collection<Message> messages = Errors.getMessagesFromThrowable(e);
    343           if (!messages.isEmpty()) {
    344             elements.addAll(messages);
    345           } else {
    346             addError(e);
    347           }
    348         }
    349         binder.install(ProviderMethodsModule.forModule(module));
    350         // We are done with this module, so undo module source change
    351         if (unwrapModuleSource) {
    352           moduleSource = moduleSource.getParent();
    353         }
    354       }
    355     }
    356 
    357     public Stage currentStage() {
    358       return stage;
    359     }
    360 
    361     public void addError(String message, Object... arguments) {
    362       elements.add(new Message(getElementSource(), Errors.format(message, arguments)));
    363     }
    364 
    365     public void addError(Throwable t) {
    366       String message = "An exception was caught and reported. Message: " + t.getMessage();
    367       elements.add(new Message(ImmutableList.of((Object) getElementSource()), message, t));
    368     }
    369 
    370     public void addError(Message message) {
    371       elements.add(message);
    372     }
    373 
    374     public <T> AnnotatedBindingBuilder<T> bind(Key<T> key) {
    375       BindingBuilder<T> builder =
    376           new BindingBuilder<T>(this, elements, getElementSource(), MoreTypes.canonicalizeKey(key));
    377       return builder;
    378     }
    379 
    380     public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
    381       return bind(Key.get(typeLiteral));
    382     }
    383 
    384     public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) {
    385       return bind(Key.get(type));
    386     }
    387 
    388     public AnnotatedConstantBindingBuilder bindConstant() {
    389       return new ConstantBindingBuilderImpl<Void>(this, elements, getElementSource());
    390     }
    391 
    392     public <T> Provider<T> getProvider(final Key<T> key) {
    393       return getProvider(Dependency.get(key));
    394     }
    395 
    396     public <T> Provider<T> getProvider(final Dependency<T> dependency) {
    397       final ProviderLookup<T> element = new ProviderLookup<T>(getElementSource(), dependency);
    398       elements.add(element);
    399       return element.getProvider();
    400     }
    401 
    402     public <T> Provider<T> getProvider(Class<T> type) {
    403       return getProvider(Key.get(type));
    404     }
    405 
    406     public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
    407         TypeConverter converter) {
    408       elements.add(new TypeConverterBinding(getElementSource(), typeMatcher, converter));
    409     }
    410 
    411     public RecordingBinder withSource(final Object source) {
    412       return source == this.source ? this : new RecordingBinder(this, source, null);
    413     }
    414 
    415     public RecordingBinder skipSources(Class... classesToSkip) {
    416       // if a source is specified explicitly, we don't need to skip sources
    417       if (source != null) {
    418         return this;
    419       }
    420 
    421       SourceProvider newSourceProvider = sourceProvider.plusSkippedClasses(classesToSkip);
    422       return new RecordingBinder(this, null, newSourceProvider);
    423     }
    424 
    425     @Override
    426     public PrivateBinder newPrivateBinder() {
    427       PrivateElementsImpl privateElements = new PrivateElementsImpl(getElementSource());
    428       RecordingBinder binder = new RecordingBinder(this, privateElements);
    429       privateBinders.add(binder);
    430       elements.add(privateElements);
    431       return binder;
    432     }
    433 
    434     @Override
    435     public void disableCircularProxies() {
    436       elements.add(new DisableCircularProxiesOption(getElementSource()));
    437     }
    438 
    439     @Override
    440     public void requireExplicitBindings() {
    441       elements.add(new RequireExplicitBindingsOption(getElementSource()));
    442     }
    443 
    444     @Override
    445     public void requireAtInjectOnConstructors() {
    446       elements.add(new RequireAtInjectOnConstructorsOption(getElementSource()));
    447     }
    448 
    449     @Override
    450     public void requireExactBindingAnnotations() {
    451       elements.add(new RequireExactBindingAnnotationsOption(getElementSource()));
    452     }
    453 
    454     @Override
    455     public void scanModulesForAnnotatedMethods(ModuleAnnotatedMethodScanner scanner) {
    456       scanners.add(scanner);
    457       elements.add(new ModuleAnnotatedMethodScannerBinding(getElementSource(), scanner));
    458     }
    459 
    460     public void expose(Key<?> key) {
    461       exposeInternal(key);
    462     }
    463 
    464     @Override
    465     public AnnotatedElementBuilder expose(Class<?> type) {
    466       return exposeInternal(Key.get(type));
    467     }
    468 
    469     @Override
    470     public AnnotatedElementBuilder expose(TypeLiteral<?> type) {
    471       return exposeInternal(Key.get(type));
    472     }
    473 
    474     private <T> AnnotatedElementBuilder exposeInternal(Key<T> key) {
    475       if (privateElements == null) {
    476         addError("Cannot expose %s on a standard binder. "
    477             + "Exposed bindings are only applicable to private binders.", key);
    478         return new AnnotatedElementBuilder() {
    479           @Override
    480           public void annotatedWith(Class<? extends Annotation> annotationType) {}
    481           @Override
    482           public void annotatedWith(Annotation annotation) {}
    483         };
    484       }
    485 
    486       ExposureBuilder<T> builder =
    487           new ExposureBuilder<T>(this, getElementSource(), MoreTypes.canonicalizeKey(key));
    488       privateElements.addExposureBuilder(builder);
    489       return builder;
    490     }
    491 
    492     private ModuleSource getModuleSource(Object module) {
    493       StackTraceElement[] partialCallStack;
    494       if (getIncludeStackTraceOption() == IncludeStackTraceOption.COMPLETE) {
    495         partialCallStack = getPartialCallStack(new Throwable().getStackTrace());
    496       } else {
    497         partialCallStack = new StackTraceElement[0];
    498       }
    499       if (moduleSource == null) {
    500         return new ModuleSource(module, partialCallStack);
    501       }
    502       return moduleSource.createChild(module, partialCallStack);
    503     }
    504 
    505     private ElementSource getElementSource() {
    506       // Full call stack
    507       StackTraceElement[] callStack = null;
    508       // The call stack starts from current top module configure and ends at this method caller
    509       StackTraceElement[] partialCallStack = new StackTraceElement[0];
    510       // The element original source
    511       ElementSource originalSource = null;
    512       // The element declaring source
    513       Object declaringSource = source;
    514       if (declaringSource instanceof ElementSource) {
    515         originalSource = (ElementSource) declaringSource;
    516         declaringSource = originalSource.getDeclaringSource();
    517       }
    518       IncludeStackTraceOption stackTraceOption = getIncludeStackTraceOption();
    519       if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
    520           (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE
    521           && declaringSource == null)) {
    522         callStack = new Throwable().getStackTrace();
    523       }
    524       if (stackTraceOption == IncludeStackTraceOption.COMPLETE) {
    525         partialCallStack = getPartialCallStack(callStack);
    526       }
    527       if (declaringSource == null) {
    528         // So 'source' and 'originalSource' are null otherwise declaringSource has some value
    529         if (stackTraceOption == IncludeStackTraceOption.COMPLETE ||
    530             stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) {
    531           // With the above conditions and assignments 'callStack' is non-null
    532           declaringSource = sourceProvider.get(callStack);
    533         } else { // or if (stackTraceOption == IncludeStackTraceOptions.OFF)
    534           // As neither 'declaring source' nor 'call stack' is available use 'module source'
    535           declaringSource = sourceProvider.getFromClassNames(moduleSource.getModuleClassNames());
    536         }
    537       }
    538       // Build the binding call stack
    539       return new ElementSource(
    540           originalSource, declaringSource, moduleSource, partialCallStack);
    541     }
    542 
    543     /**
    544      * Removes the {@link #moduleSource} call stack from the beginning of current call stack. It
    545      * also removes the last two elements in order to make {@link #install(Module)} the last call
    546      * in the call stack.
    547      */
    548     private StackTraceElement[] getPartialCallStack(StackTraceElement[] callStack) {
    549       int toSkip = 0;
    550       if (moduleSource != null) {
    551         toSkip = moduleSource.getStackTraceSize();
    552       }
    553       // -1 for skipping 'getModuleSource' and 'getElementSource' calls
    554       int chunkSize = callStack.length - toSkip - 1;
    555 
    556       StackTraceElement[] partialCallStack = new StackTraceElement[chunkSize];
    557       System.arraycopy(callStack, 1, partialCallStack, 0, chunkSize);
    558       return partialCallStack;
    559     }
    560 
    561     @Override public String toString() {
    562       return "Binder";
    563     }
    564   }
    565 }
    566