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@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 */ getElements(Module... modules)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 */ getElements(Stage stage, Module... modules)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 */ getElements(Iterable<? extends Module> modules)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 */ getElements(Stage stage, Iterable<? extends Module> modules)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 ElementsAsModule(Iterable<? extends Element> elements)124 ElementsAsModule(Iterable<? extends Element> elements) { 125 this.elements = elements; 126 } 127 128 @Override configure(Binder binder)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 */ getModule(final Iterable<? extends Element> elements)139 public static Module getModule(final Iterable<? extends Element> elements) { 140 return new ElementsAsModule(elements); 141 } 142 143 @SuppressWarnings("unchecked") getInstanceVisitor()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 ModuleInfo(Binder binder, ModuleSource moduleSource, boolean skipScanning)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 RecordingBinder(Stage stage)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}. */ RecordingBinder( RecordingBinder prototype, Object source, SourceProvider sourceProvider)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. */ RecordingBinder(RecordingBinder parent, PrivateElementsImpl privateElements)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 bindInterceptor( Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors)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 bindScope(Class<? extends Annotation> annotationType, Scope scope)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 requestInjection(Object instance)240 public void requestInjection(Object instance) { 241 requestInjection((TypeLiteral<Object>) TypeLiteral.get(instance.getClass()), instance); 242 } 243 244 @Override requestInjection(TypeLiteral<T> type, T instance)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 getMembersInjector(final TypeLiteral<T> typeLiteral)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 getMembersInjector(Class<T> type)258 public <T> MembersInjector<T> getMembersInjector(Class<T> type) { 259 return getMembersInjector(TypeLiteral.get(type)); 260 } 261 bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener)262 public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) { 263 elements.add(new TypeListenerBinding(getElementSource(), listener, typeMatcher)); 264 } 265 bindListener(Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners)266 public void bindListener(Matcher<? super Binding<?>> bindingMatcher, 267 ProvisionListener... listeners) { 268 elements.add(new ProvisionListenerBinding(getElementSource(), bindingMatcher, listeners)); 269 } 270 requestStaticInjection(Class<?>.... types)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 */ scanForAnnotatedMethods()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 install(Module module)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 currentStage()357 public Stage currentStage() { 358 return stage; 359 } 360 addError(String message, Object... arguments)361 public void addError(String message, Object... arguments) { 362 elements.add(new Message(getElementSource(), Errors.format(message, arguments))); 363 } 364 addError(Throwable t)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 addError(Message message)370 public void addError(Message message) { 371 elements.add(message); 372 } 373 bind(Key<T> key)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 bind(TypeLiteral<T> typeLiteral)380 public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) { 381 return bind(Key.get(typeLiteral)); 382 } 383 bind(Class<T> type)384 public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) { 385 return bind(Key.get(type)); 386 } 387 bindConstant()388 public AnnotatedConstantBindingBuilder bindConstant() { 389 return new ConstantBindingBuilderImpl<Void>(this, elements, getElementSource()); 390 } 391 getProvider(final Key<T> key)392 public <T> Provider<T> getProvider(final Key<T> key) { 393 return getProvider(Dependency.get(key)); 394 } 395 getProvider(final Dependency<T> dependency)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 getProvider(Class<T> type)402 public <T> Provider<T> getProvider(Class<T> type) { 403 return getProvider(Key.get(type)); 404 } 405 convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter)406 public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, 407 TypeConverter converter) { 408 elements.add(new TypeConverterBinding(getElementSource(), typeMatcher, converter)); 409 } 410 withSource(final Object source)411 public RecordingBinder withSource(final Object source) { 412 return source == this.source ? this : new RecordingBinder(this, source, null); 413 } 414 skipSources(Class... classesToSkip)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 newPrivateBinder()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 disableCircularProxies()435 public void disableCircularProxies() { 436 elements.add(new DisableCircularProxiesOption(getElementSource())); 437 } 438 439 @Override requireExplicitBindings()440 public void requireExplicitBindings() { 441 elements.add(new RequireExplicitBindingsOption(getElementSource())); 442 } 443 444 @Override requireAtInjectOnConstructors()445 public void requireAtInjectOnConstructors() { 446 elements.add(new RequireAtInjectOnConstructorsOption(getElementSource())); 447 } 448 449 @Override requireExactBindingAnnotations()450 public void requireExactBindingAnnotations() { 451 elements.add(new RequireExactBindingAnnotationsOption(getElementSource())); 452 } 453 454 @Override scanModulesForAnnotatedMethods(ModuleAnnotatedMethodScanner scanner)455 public void scanModulesForAnnotatedMethods(ModuleAnnotatedMethodScanner scanner) { 456 scanners.add(scanner); 457 elements.add(new ModuleAnnotatedMethodScannerBinding(getElementSource(), scanner)); 458 } 459 expose(Key<?> key)460 public void expose(Key<?> key) { 461 exposeInternal(key); 462 } 463 464 @Override expose(Class<?> type)465 public AnnotatedElementBuilder expose(Class<?> type) { 466 return exposeInternal(Key.get(type)); 467 } 468 469 @Override expose(TypeLiteral<?> type)470 public AnnotatedElementBuilder expose(TypeLiteral<?> type) { 471 return exposeInternal(Key.get(type)); 472 } 473 exposeInternal(Key<T> key)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 getModuleSource(Object module)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 getElementSource()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 */ getPartialCallStack(StackTraceElement[] callStack)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 toString()561 @Override public String toString() { 562 return "Binder"; 563 } 564 } 565 } 566