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