1 16 17 package com.google.inject; 18 19 import com.google.inject.InjectorImpl.SingleMemberInjector; 20 import com.google.inject.Key.AnnotationStrategy; 21 import static com.google.inject.Scopes.SINGLETON; 22 import com.google.inject.matcher.Matcher; 23 import com.google.inject.spi.Message; 24 import com.google.inject.spi.SourceProviders; 25 import com.google.inject.util.Annotations; 26 import static com.google.inject.util.Objects.nonNull; 27 import com.google.inject.util.StackTraceElements; 28 import com.google.inject.util.Stopwatch; 29 import java.lang.annotation.Annotation ; 30 import java.lang.reflect.Member ; 31 import java.lang.reflect.Method ; 32 import java.util.ArrayList ; 33 import java.util.Collection ; 34 import java.util.Collections ; 35 import java.util.HashMap ; 36 import java.util.HashSet ; 37 import java.util.List ; 38 import java.util.Map ; 39 import java.util.Set ; 40 import java.util.logging.Level ; 41 import java.util.logging.Logger ; 42 import org.aopalliance.intercept.MethodInterceptor; 43 44 51 class BinderImpl implements Binder { 52 53 static { 54 SourceProviders.skip(BinderImpl.class); 55 } 56 57 private static final Logger logger 58 = Logger.getLogger(BinderImpl.class.getName()); 59 60 final List <BindingBuilderImpl<?>> bindingBuilders 61 = new ArrayList <BindingBuilderImpl<?>>(); 62 final List <ConstantBindingBuilderImpl> constantBindingBuilders 63 = new ArrayList <ConstantBindingBuilderImpl>(); 64 final Map <Class <? extends Annotation >, Scope> scopes = 65 new HashMap <Class <? extends Annotation >, Scope>(); 66 67 final List <StaticInjection> staticInjections 68 = new ArrayList <StaticInjection>(); 69 70 InjectorImpl injector; 71 72 final Stage stage; 73 74 final Collection <Message> errorMessages = new ArrayList <Message>(); 75 76 private static final InternalFactory<Injector> INJECTOR_FACTORY 77 = new InternalFactory<Injector>() { 78 public Injector get(InternalContext context) { 79 return context.getInjectorImpl(); 80 } 81 82 public String toString() { 83 return "Provider<Injector>"; 84 } 85 }; 86 87 private static final InternalFactory<Logger > LOGGER_FACTORY 88 = new InternalFactory<Logger >() { 89 public Logger get(InternalContext context) { 91 Member member = context.getExternalContext().getMember(); 92 return member == null 93 ? Logger.getAnonymousLogger() 94 : Logger.getLogger(member.getDeclaringClass().getName()); 95 } 96 97 public String toString() { 98 return "Provider<Logger>"; 99 } 100 }; 101 102 final ProxyFactoryBuilder proxyFactoryBuilder; 103 104 110 public BinderImpl(Stage stage) { 111 bindScope(Singleton.class, SINGLETON); 112 113 bind(Injector.class).to(INJECTOR_FACTORY); 114 bind(Logger .class).to(LOGGER_FACTORY); 115 bind(Stage.class).toInstance(stage); 116 117 this.proxyFactoryBuilder = new ProxyFactoryBuilder(); 118 119 this.stage = stage; 120 } 121 122 126 public BinderImpl() { 127 this(Stage.DEVELOPMENT); 128 } 129 130 public Stage currentStage() { 131 return stage; 132 } 133 134 final List <CreationListener> creationListeners 135 = new ArrayList <CreationListener>(); 136 final List <CreationListener> instanceInjectors 137 = new ArrayList <CreationListener>(); 138 139 interface CreationListener { 140 void notify(InjectorImpl injector); 141 } 142 143 public void bindInterceptor(Matcher<? super Class <?>> classMatcher, 144 Matcher<? super Method > methodMatcher, MethodInterceptor... interceptors) { 145 proxyFactoryBuilder.intercept(classMatcher, methodMatcher, interceptors); 146 } 147 148 public void bindScope(Class <? extends Annotation > annotationType, 149 Scope scope) { 150 if (!Scopes.isScopeAnnotation(annotationType)) { 151 addError(StackTraceElements.forType(annotationType), 152 ErrorMessages.MISSING_SCOPE_ANNOTATION); 153 } 155 156 if (!Annotations.isRetainedAtRuntime(annotationType)) { 157 addError(StackTraceElements.forType(annotationType), 158 ErrorMessages.MISSING_RUNTIME_RETENTION, source()); 159 } 161 162 Scope existing = scopes.get(nonNull(annotationType, "annotation type")); 163 if (existing != null) { 164 addError(source(), ErrorMessages.DUPLICATE_SCOPES, existing, 165 annotationType, scope); 166 } 167 else { 168 scopes.put(annotationType, nonNull(scope, "scope")); 169 } 170 } 171 172 public <T> BindingBuilderImpl<T> bind(Key<T> key) { 173 BindingBuilderImpl<T> builder = 174 new BindingBuilderImpl<T>(this, key, source()); 175 bindingBuilders.add(builder); 176 return builder; 177 } 178 179 public <T> BindingBuilderImpl<T> bind(TypeLiteral<T> typeLiteral) { 180 return bind(Key.get(typeLiteral)); 181 } 182 183 public <T> BindingBuilderImpl<T> bind(Class <T> clazz) { 184 return bind(Key.get(clazz)); 185 } 186 187 public ConstantBindingBuilderImpl bindConstant() { 188 ConstantBindingBuilderImpl constantBuilder 189 = new ConstantBindingBuilderImpl(this, source()); 190 constantBindingBuilders.add(constantBuilder); 191 return constantBuilder; 192 } 193 194 public void requestStaticInjection(Class <?>... types) { 195 staticInjections.add(new StaticInjection(source(), types)); 196 } 197 198 public void install(Module module) { 199 module.configure(this); 200 } 201 202 public void addError(String message, Object ... arguments) { 203 configurationErrorHandler.handle(source(), message, arguments); 204 } 205 206 public void addError(Throwable t) { 207 Object source = source(); 208 String className = t.getClass().getSimpleName(); 209 String message = ErrorMessages.getRootMessage(t); 210 String logMessage = String.format( 211 ErrorMessages.EXCEPTION_REPORTED_BY_MODULE, message); 212 logger.log(Level.INFO, logMessage, t); 213 addError(source, ErrorMessages.EXCEPTION_REPORTED_BY_MODULE_SEE_LOG, message); 214 } 215 216 void addError(Object source, String message, Object ... arguments) { 217 configurationErrorHandler.handle(source, message, arguments); 218 } 219 220 void addError(Object source, String message) { 221 configurationErrorHandler.handle(source, message); 222 } 223 224 227 void add(Message errorMessage) { 228 errorMessages.add(errorMessage); 229 } 230 231 final Stopwatch stopwatch = new Stopwatch(); 232 233 241 Injector createInjector() throws CreationException { 242 stopwatch.resetAndLog(logger, "Configuration"); 243 244 Map <Key<?>, BindingImpl<?>> bindings = new HashMap <Key<?>, BindingImpl<?>>(); 245 injector = new InjectorImpl( 246 proxyFactoryBuilder.create(), bindings, scopes); 247 injector.setErrorHandler(configurationErrorHandler); 248 249 createConstantBindings(); 250 251 final List <ContextualCallable<Void >> preloaders 253 = new ArrayList <ContextualCallable<Void >>(); 254 255 createBindings(preloaders); 256 257 stopwatch.resetAndLog(logger, "Binding creation"); 258 259 injector.index(); 260 261 stopwatch.resetAndLog(logger, "Binding indexing"); 262 263 for (CreationListener creationListener : creationListeners) { 264 creationListener.notify(injector); 265 } 266 267 stopwatch.resetAndLog(logger, "Validation"); 268 269 for (StaticInjection staticInjection : staticInjections) { 270 staticInjection.createMemberInjectors(injector); 271 } 272 273 stopwatch.resetAndLog(logger, "Static validation"); 274 275 if (!errorMessages.isEmpty()) { 277 throw new CreationException(errorMessages); 278 } 279 280 injector.setErrorHandler(new RuntimeErrorHandler()); 282 283 for (StaticInjection staticInjection : staticInjections) { 285 staticInjection.runMemberInjectors(injector); 286 } 287 288 stopwatch.resetAndLog(logger, "Static member injection"); 289 290 for (CreationListener instanceInjector : instanceInjectors) { 292 instanceInjector.notify(injector); 293 } 294 295 stopwatch.resetAndLog(logger, "Instance injection"); 296 297 runPreloaders(injector, preloaders); 299 300 stopwatch.resetAndLog(logger, "Preloading"); 301 302 return injector; 303 } 304 305 private void runPreloaders(InjectorImpl injector, 306 final List <ContextualCallable<Void >> preloaders) { 307 injector.callInContext(new ContextualCallable<Void >() { 308 public Void call(InternalContext context) { 309 for (ContextualCallable<Void > preloader : preloaders) { 310 preloader.call(context); 311 } 312 return null; 313 } 314 }); 315 } 316 317 private void createBindings(List <ContextualCallable<Void >> preloaders) { 318 for (BindingBuilderImpl<?> builder : bindingBuilders) { 319 createBinding(builder, preloaders); 320 } 321 } 322 323 private <T> void createBinding(BindingBuilderImpl<T> builder, 324 List <ContextualCallable<Void >> preloaders) { 325 final Key<T> key = builder.getKey(); 326 final InternalFactory<? extends T> factory 327 = builder.getInternalFactory(injector); 328 BindingImpl<?> binding 329 = BindingImpl.newInstance(injector, key, builder.getSource(), factory); 330 331 putBinding(binding); 332 333 boolean preload = stage == Stage.PRODUCTION; 335 if (builder.isSingletonScoped()) { 336 if (preload || builder.shouldPreload()) { 337 preloaders.add(new BindingPreloader(key, factory)); 338 } 339 } 340 else { 341 if (builder.shouldPreload()) { 342 addError(builder.getSource(), ErrorMessages.PRELOAD_NOT_ALLOWED); 343 } 344 } 345 } 346 347 private void createConstantBindings() { 348 for (ConstantBindingBuilderImpl builder : constantBindingBuilders) { 349 createConstantBinding(builder); 350 } 351 } 352 353 private void createConstantBinding(ConstantBindingBuilderImpl builder) { 354 if (builder.hasValue()) { 355 putBinding(builder.createBinding(injector)); 356 } 357 else { 358 addError(builder.getSource(), ErrorMessages.MISSING_CONSTANT_VALUE); 359 } 360 } 361 362 private static Set <Class <?>> FORBIDDEN_TYPES = forbiddenTypes(); 363 364 private static Set <Class <?>> forbiddenTypes() { 365 Set <Class <?>> set = new HashSet <Class <?>>(); 366 Collections.addAll(set, 367 368 372 AbstractModule.class, 373 Binder.class, 374 Binding.class, 375 Key.class, 376 Module.class, 377 Provider.class, 378 Scope.class, 379 TypeLiteral.class); 380 return Collections.unmodifiableSet(set); 381 } 382 383 void putBinding(BindingImpl<?> binding) { 384 Key<?> key = binding.getKey(); 385 Map <Key<?>, BindingImpl<?>> bindings = injector.internalBindings(); 386 Binding<?> original = bindings.get(key); 387 388 Class <?> rawType = key.getRawType(); 389 if (FORBIDDEN_TYPES.contains(rawType)) { 390 addError(binding.getSource(), ErrorMessages.CANNOT_BIND_TO_GUICE_TYPE, 391 rawType.getSimpleName()); 392 return; 393 } 394 395 if (bindings.containsKey(key)) { 396 addError(binding.getSource(), ErrorMessages.BINDING_ALREADY_SET, key, 397 original.getSource()); 398 } 399 else { 400 bindings.put(key, binding); 401 } 402 } 403 404 407 Object source() { 408 return SourceProviders.defaultSource(); 409 } 410 411 ErrorHandler configurationErrorHandler = new AbstractErrorHandler() { 412 413 public void handle(Object source, String message) { 414 add(new Message(source, message)); 415 } 416 }; 417 418 421 static class RuntimeErrorHandler extends AbstractErrorHandler { 422 423 static ErrorHandler INSTANCE = new RuntimeErrorHandler(); 424 425 public void handle(Object source, String message) { 426 throw new ConfigurationException("Error at " + source + " " + message); 427 } 428 } 429 430 433 class StaticInjection { 434 435 final Object source; 436 final Class <?>[] types; 437 final List <SingleMemberInjector> memberInjectors 438 = new ArrayList <SingleMemberInjector>(); 439 440 public StaticInjection(Object source, Class <?>[] types) { 441 this.source = source; 442 this.types = types; 443 } 444 445 void createMemberInjectors(final InjectorImpl injector) { 446 injector.withDefaultSource(source, 447 new Runnable () { 448 public void run() { 449 for (Class <?> clazz : types) { 450 injector.addSingleInjectorsForFields( 451 clazz.getDeclaredFields(), true, memberInjectors); 452 injector.addSingleInjectorsForMethods( 453 clazz.getDeclaredMethods(), true, memberInjectors); 454 } 455 } 456 }); 457 } 458 459 void runMemberInjectors(InjectorImpl injector) { 460 injector.callInContext(new ContextualCallable<Void >() { 461 public Void call(InternalContext context) { 462 for (SingleMemberInjector injector : memberInjectors) { 463 injector.inject(context, null); 464 } 465 return null; 466 } 467 }); 468 } 469 } 470 471 static class BindingPreloader implements ContextualCallable<Void > { 472 473 private final Key<?> key; 474 private final InternalFactory<?> factory; 475 476 public BindingPreloader(Key<?> key, InternalFactory<?> factory) { 477 this.key = key; 478 this.factory = factory; 479 } 480 481 public Void call(InternalContext context) { 482 ExternalContext<?> externalContext 483 = ExternalContext.newInstance(null, key, context.getInjectorImpl()); 484 context.setExternalContext(externalContext); 485 try { 486 factory.get(context); 487 return null; 488 } 489 finally { 490 context.setExternalContext(null); 491 } 492 } 493 } 494 } 495 | Popular Tags |