diff options
author | Haibo Huang <hhb@google.com> | 2018-08-28 11:18:22 -0700 |
---|---|---|
committer | Haibo Huang <hhb@google.com> | 2018-08-28 11:20:15 -0700 |
commit | bfaaf2b15f18ec4f73641d11539db4829f5b15e2 (patch) | |
tree | cb03f0d7b72d492f6f29457cbe0d5b5eee636f54 /core/src/com | |
parent | 9b878813d48dee9b08a1cdc8c8b607a602752659 (diff) | |
download | guice-bfaaf2b15f18ec4f73641d11539db4829f5b15e2.tar.gz |
Upgrade guice to 4.2
Test: m checkbuild
Change-Id: I7df64e3d67f5b6c586ff444f45636cd7b2935c1f
Diffstat (limited to 'core/src/com')
216 files changed, 11194 insertions, 5289 deletions
diff --git a/core/src/com/google/inject/AbstractModule.java b/core/src/com/google/inject/AbstractModule.java index fafbd121..7fece9f8 100644 --- a/core/src/com/google/inject/AbstractModule.java +++ b/core/src/com/google/inject/AbstractModule.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,15 +27,13 @@ import com.google.inject.spi.Message; import com.google.inject.spi.ProvisionListener; import com.google.inject.spi.TypeConverter; import com.google.inject.spi.TypeListener; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; /** - * A support class for {@link Module}s which reduces repetition and results in - * a more readable configuration. Simply extend this class, implement {@link - * #configure()}, and call the inherited methods which mirror those found in - * {@link Binder}. For example: + * A support class for {@link Module}s which reduces repetition and results in a more readable + * configuration. Simply extend this class, implement {@link #configure()}, and call the inherited + * methods which mirror those found in {@link Binder}. For example: * * <pre> * public class MyModule extends AbstractModule { @@ -54,84 +52,63 @@ public abstract class AbstractModule implements Module { Binder binder; + @Override public final synchronized void configure(Binder builder) { checkState(this.binder == null, "Re-entry is not allowed."); this.binder = checkNotNull(builder, "builder"); try { configure(); - } - finally { + } finally { this.binder = null; } } - /** - * Configures a {@link Binder} via the exposed methods. - */ - protected abstract void configure(); + /** Configures a {@link Binder} via the exposed methods. */ + protected void configure() {} - /** - * Gets direct access to the underlying {@code Binder}. - */ + /** Gets direct access to the underlying {@code Binder}. */ protected Binder binder() { checkState(binder != null, "The binder can only be used inside configure()"); return binder; } - /** - * @see Binder#bindScope(Class, Scope) - */ - protected void bindScope(Class<? extends Annotation> scopeAnnotation, - Scope scope) { + /** @see Binder#bindScope(Class, Scope) */ + protected void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) { binder().bindScope(scopeAnnotation, scope); } - /** - * @see Binder#bind(Key) - */ + /** @see Binder#bind(Key) */ protected <T> LinkedBindingBuilder<T> bind(Key<T> key) { return binder().bind(key); } - /** - * @see Binder#bind(TypeLiteral) - */ + /** @see Binder#bind(TypeLiteral) */ protected <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) { return binder().bind(typeLiteral); } - /** - * @see Binder#bind(Class) - */ + /** @see Binder#bind(Class) */ protected <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) { return binder().bind(clazz); } - /** - * @see Binder#bindConstant() - */ + /** @see Binder#bindConstant() */ protected AnnotatedConstantBindingBuilder bindConstant() { return binder().bindConstant(); } - /** - * @see Binder#install(Module) - */ + /** @see Binder#install(Module) */ protected void install(Module module) { binder().install(module); } - /** - * @see Binder#addError(String, Object[]) - */ + /** @see Binder#addError(String, Object[]) */ protected void addError(String message, Object... arguments) { binder().addError(message, arguments); } - /** - * @see Binder#addError(Throwable) - */ + /** @see Binder#addError(Throwable) */ protected void addError(Throwable t) { binder().addError(t); } @@ -152,9 +129,7 @@ public abstract class AbstractModule implements Module { binder().requestInjection(instance); } - /** - * @see Binder#requestStaticInjection(Class[]) - */ + /** @see Binder#requestStaticInjection(Class[]) */ protected void requestStaticInjection(Class<?>... types) { binder().requestStaticInjection(types); } @@ -162,10 +137,10 @@ public abstract class AbstractModule implements Module { /*if[AOP]*/ /** * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, - * com.google.inject.matcher.Matcher, - * org.aopalliance.intercept.MethodInterceptor[]) + * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) */ - protected void bindInterceptor(Matcher<? super Class<?>> classMatcher, + protected void bindInterceptor( + Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors) { binder().bindInterceptor(classMatcher, methodMatcher, interceptors); @@ -173,10 +148,9 @@ public abstract class AbstractModule implements Module { /*end[AOP]*/ /** - * Adds a dependency from this module to {@code key}. When the injector is - * created, Guice will report an error if {@code key} cannot be injected. - * Note that this requirement may be satisfied by implicit binding, such as - * a public no-arguments constructor. + * Adds a dependency from this module to {@code key}. When the injector is created, Guice will + * report an error if {@code key} cannot be injected. Note that this requirement may be satisfied + * by implicit binding, such as a public no-arguments constructor. * * @since 2.0 */ @@ -185,10 +159,9 @@ public abstract class AbstractModule implements Module { } /** - * Adds a dependency from this module to {@code type}. When the injector is - * created, Guice will report an error if {@code type} cannot be injected. - * Note that this requirement may be satisfied by implicit binding, such as - * a public no-arguments constructor. + * Adds a dependency from this module to {@code type}. When the injector is created, Guice will + * report an error if {@code type} cannot be injected. Note that this requirement may be satisfied + * by implicit binding, such as a public no-arguments constructor. * * @since 2.0 */ @@ -216,13 +189,13 @@ public abstract class AbstractModule implements Module { * @see Binder#convertToTypes * @since 2.0 */ - protected void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter converter) { + protected void convertToTypes( + Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) { binder().convertToTypes(typeMatcher, converter); } /** - * @see Binder#currentStage() + * @see Binder#currentStage() * @since 2.0 */ protected Stage currentStage() { @@ -246,21 +219,19 @@ public abstract class AbstractModule implements Module { } /** - * @see Binder#bindListener(com.google.inject.matcher.Matcher, - * com.google.inject.spi.TypeListener) + * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener) * @since 2.0 */ - protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeListener listener) { + protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) { binder().bindListener(typeMatcher, listener); } - + /** * @see Binder#bindListener(Matcher, ProvisionListener...) * @since 4.0 */ - protected void bindListener(Matcher<? super Binding<?>> bindingMatcher, - ProvisionListener... listener) { + protected void bindListener( + Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listener) { binder().bindListener(bindingMatcher, listener); } } diff --git a/core/src/com/google/inject/Binder.java b/core/src/com/google/inject/Binder.java index e930c3be..e3fab865 100644 --- a/core/src/com/google/inject/Binder.java +++ b/core/src/com/google/inject/Binder.java @@ -26,129 +26,111 @@ import com.google.inject.spi.ModuleAnnotatedMethodScanner; import com.google.inject.spi.ProvisionListener; import com.google.inject.spi.TypeConverter; import com.google.inject.spi.TypeListener; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; -import java.lang.reflect.Proxy; /** - * Collects configuration information (primarily <i>bindings</i>) which will be - * used to create an {@link Injector}. Guice provides this object to your - * application's {@link Module} implementors so they may each contribute - * their own bindings and other registrations. + * Collects configuration information (primarily <i>bindings</i>) which will be used to create an + * {@link Injector}. Guice provides this object to your application's {@link Module} implementors so + * they may each contribute their own bindings and other registrations. * * <h3>The Guice Binding EDSL</h3> * - * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you - * create bindings simply and readably. This approach is great for overall - * usability, but it does come with a small cost: <b>it is difficult to - * learn how to use the Binding EDSL by reading - * method-level javadocs</b>. Instead, you should consult the series of - * examples below. To save space, these examples omit the opening - * {@code binder}, just as you will if your module extends - * {@link AbstractModule}. + * Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you create bindings + * simply and readably. This approach is great for overall usability, but it does come with a small + * cost: <b>it is difficult to learn how to use the Binding EDSL by reading method-level + * javadocs</b>. Instead, you should consult the series of examples below. To save space, these + * examples omit the opening {@code binder}, just as you will if your module extends {@link + * AbstractModule}. * * <pre> * bind(ServiceImpl.class);</pre> * - * This statement does essentially nothing; it "binds the {@code ServiceImpl} - * class to itself" and does not change Guice's default behavior. You may still - * want to use this if you prefer your {@link Module} class to serve as an - * explicit <i>manifest</i> for the services it provides. Also, in rare cases, - * Guice may be unable to validate a binding at injector creation time unless it - * is given explicitly. + * This statement does essentially nothing; it "binds the {@code ServiceImpl} class to itself" and + * does not change Guice's default behavior. You may still want to use this if you prefer your + * {@link Module} class to serve as an explicit <i>manifest</i> for the services it provides. Also, + * in rare cases, Guice may be unable to validate a binding at injector creation time unless it is + * given explicitly. * * <pre> * bind(Service.class).to(ServiceImpl.class);</pre> * - * Specifies that a request for a {@code Service} instance with no binding - * annotations should be treated as if it were a request for a - * {@code ServiceImpl} instance. This <i>overrides</i> the function of any - * {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy} - * annotations found on {@code Service}, since Guice will have already - * "moved on" to {@code ServiceImpl} before it reaches the point when it starts - * looking for these annotations. + * Specifies that a request for a {@code Service} instance with no binding annotations should be + * treated as if it were a request for a {@code ServiceImpl} instance. This <i>overrides</i> the + * function of any {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy} + * annotations found on {@code Service}, since Guice will have already "moved on" to {@code + * ServiceImpl} before it reaches the point when it starts looking for these annotations. * * <pre> * bind(Service.class).toProvider(ServiceProvider.class);</pre> * - * In this example, {@code ServiceProvider} must extend or implement - * {@code Provider<Service>}. This binding specifies that Guice should resolve - * an unannotated injection request for {@code Service} by first resolving an - * instance of {@code ServiceProvider} in the regular way, then calling - * {@link Provider#get get()} on the resulting Provider instance to obtain the - * {@code Service} instance. + * In this example, {@code ServiceProvider} must extend or implement {@code Provider<Service>}. This + * binding specifies that Guice should resolve an unannotated injection request for {@code Service} + * by first resolving an instance of {@code ServiceProvider} in the regular way, then calling {@link + * Provider#get get()} on the resulting Provider instance to obtain the {@code Service} instance. * - * <p>The {@link Provider} you use here does not have to be a "factory"; that - * is, a provider which always <i>creates</i> each instance it provides. - * However, this is generally a good practice to follow. You can then use - * Guice's concept of {@link Scope scopes} to guide when creation should happen - * -- "letting Guice work for you". + * <p>The {@link Provider} you use here does not have to be a "factory"; that is, a provider which + * always <i>creates</i> each instance it provides. However, this is generally a good practice to + * follow. You can then use Guice's concept of {@link Scope scopes} to guide when creation should + * happen -- "letting Guice work for you". * * <pre> * bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);</pre> * - * Like the previous example, but only applies to injection requests that use - * the binding annotation {@code @Red}. If your module also includes bindings - * for particular <i>values</i> of the {@code @Red} annotation (see below), - * then this binding will serve as a "catch-all" for any values of {@code @Red} - * that have no exact match in the bindings. - * + * Like the previous example, but only applies to injection requests that use the binding annotation + * {@code @Red}. If your module also includes bindings for particular <i>values</i> of the + * {@code @Red} annotation (see below), then this binding will serve as a "catch-all" for any values + * of {@code @Red} that have no exact match in the bindings. + * * <pre> * bind(ServiceImpl.class).in(Singleton.class); * // or, alternatively * bind(ServiceImpl.class).in(Scopes.SINGLETON);</pre> * - * Either of these statements places the {@code ServiceImpl} class into - * singleton scope. Guice will create only one instance of {@code ServiceImpl} - * and will reuse it for all injection requests of this type. Note that it is - * still possible to bind another instance of {@code ServiceImpl} if the second - * binding is qualified by an annotation as in the previous example. Guice is - * not overly concerned with <i>preventing</i> you from creating multiple - * instances of your "singletons", only with <i>enabling</i> your application to - * share only one instance if that's all you tell Guice you need. - * - * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that - * was specified with an annotation on the {@code ServiceImpl} class. - * - * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are - * servlet-specific scopes available in - * {@code com.google.inject.servlet.ServletScopes}, and your Modules can - * contribute their own custom scopes for use here as well. + * Either of these statements places the {@code ServiceImpl} class into singleton scope. Guice will + * create only one instance of {@code ServiceImpl} and will reuse it for all injection requests of + * this type. Note that it is still possible to bind another instance of {@code ServiceImpl} if the + * second binding is qualified by an annotation as in the previous example. Guice is not overly + * concerned with <i>preventing</i> you from creating multiple instances of your "singletons", only + * with <i>enabling</i> your application to share only one instance if that's all you tell Guice you + * need. + * + * <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that was specified with + * an annotation on the {@code ServiceImpl} class. + * + * <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are servlet-specific scopes + * available in {@code com.google.inject.servlet.ServletScopes}, and your Modules can contribute + * their own custom scopes for use here as well. * * <pre> * bind(new TypeLiteral<PaymentService<CreditCard>>() {}) * .to(CreditCardPaymentService.class);</pre> * - * This admittedly odd construct is the way to bind a parameterized type. It - * tells Guice how to honor an injection request for an element of type - * {@code PaymentService<CreditCard>}. The class - * {@code CreditCardPaymentService} must implement the - * {@code PaymentService<CreditCard>} interface. Guice cannot currently bind or - * inject a generic type, such as {@code Set<E>}; all type parameters must be - * fully specified. + * This admittedly odd construct is the way to bind a parameterized type. It tells Guice how to + * honor an injection request for an element of type {@code PaymentService<CreditCard>}. The class + * {@code CreditCardPaymentService} must implement the {@code PaymentService<CreditCard>} interface. + * Guice cannot currently bind or inject a generic type, such as {@code Set<E>}; all type parameters + * must be fully specified. * * <pre> * bind(Service.class).toInstance(new ServiceImpl()); * // or, alternatively * bind(Service.class).toInstance(SomeLegacyRegistry.getService());</pre> * - * In this example, your module itself, <i>not Guice</i>, takes responsibility - * for obtaining a {@code ServiceImpl} instance, then asks Guice to always use - * this single instance to fulfill all {@code Service} injection requests. When - * the {@link Injector} is created, it will automatically perform field - * and method injection for this instance, but any injectable constructor on - * {@code ServiceImpl} is simply ignored. Note that using this approach results - * in "eager loading" behavior that you can't control. + * In this example, your module itself, <i>not Guice</i>, takes responsibility for obtaining a + * {@code ServiceImpl} instance, then asks Guice to always use this single instance to fulfill all + * {@code Service} injection requests. When the {@link Injector} is created, it will automatically + * perform field and method injection for this instance, but any injectable constructor on {@code + * ServiceImpl} is simply ignored. Note that using this approach results in "eager loading" behavior + * that you can't control. * * <pre> * bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre> * - * Sets up a constant binding. Constant injections must always be annotated. - * When a constant binding's value is a string, it is eligile for conversion to - * all primitive types, to {@link Enum#valueOf(Class, String) all enums}, and to - * {@link Class#forName class literals}. Conversions for other types can be - * configured using {@link #convertToTypes(Matcher, TypeConverter) + * Sets up a constant binding. Constant injections must always be annotated. When a constant + * binding's value is a string, it is eligile for conversion to all primitive types, to {@link + * Enum#valueOf(Class, String) all enums}, and to {@link Class#forName class literals}. Conversions + * for other types can be configured using {@link #convertToTypes(Matcher, TypeConverter) * convertToTypes()}. * * <pre> @@ -157,46 +139,42 @@ import java.lang.reflect.Proxy; * red = MyModule.class.getDeclaredField("red").getAnnotation(Color.class); * bind(Service.class).annotatedWith(red).to(RedService.class);</pre> * - * If your binding annotation has parameters you can apply different bindings to - * different specific values of your annotation. Getting your hands on the - * right instance of the annotation is a bit of a pain -- one approach, shown - * above, is to apply a prototype annotation to a field in your module class, so - * that you can read this annotation instance and give it to Guice. + * If your binding annotation has parameters you can apply different bindings to different specific + * values of your annotation. Getting your hands on the right instance of the annotation is a bit of + * a pain -- one approach, shown above, is to apply a prototype annotation to a field in your module + * class, so that you can read this annotation instance and give it to Guice. * * <pre> * bind(Service.class) * .annotatedWith(Names.named("blue")) * .to(BlueService.class);</pre> * - * Differentiating by names is a common enough use case that we provided a - * standard annotation, {@link com.google.inject.name.Named @Named}. Because of - * Guice's library support, binding by name is quite easier than in the - * arbitrary binding annotation case we just saw. However, remember that these - * names will live in a single flat namespace with all the other names used in - * your application. + * Differentiating by names is a common enough use case that we provided a standard annotation, + * {@link com.google.inject.name.Named @Named}. Because of Guice's library support, binding by name + * is quite easier than in the arbitrary binding annotation case we just saw. However, remember that + * these names will live in a single flat namespace with all the other names used in your + * application. * * <pre> * Constructor<T> loneCtor = getLoneCtorFromServiceImplViaReflection(); * bind(ServiceImpl.class) * .toConstructor(loneCtor);</pre> * - * In this example, we directly tell Guice which constructor to use in a concrete - * class implementation. It means that we do not need to place {@literal @}Inject - * on any of the constructors and that Guice treats the provided constructor as though - * it were annotated so. It is useful for cases where you cannot modify existing - * classes and is a bit simpler than using a {@link Provider}. - * - * <p>The above list of examples is far from exhaustive. If you can think of - * how the concepts of one example might coexist with the concepts from another, - * you can most likely weave the two together. If the two concepts make no - * sense with each other, you most likely won't be able to do it. In a few - * cases Guice will let something bogus slip by, and will then inform you of - * the problems at runtime, as soon as you try to create your Injector. - * - * <p>The other methods of Binder such as {@link #bindScope}, - * {@link #bindInterceptor}, {@link #install}, {@link #requestStaticInjection}, - * {@link #addError} and {@link #currentStage} are not part of the Binding EDSL; - * you can learn how to use these in the usual way, from the method + * In this example, we directly tell Guice which constructor to use in a concrete class + * implementation. It means that we do not need to place {@literal @}Inject on any of the + * constructors and that Guice treats the provided constructor as though it were annotated so. It is + * useful for cases where you cannot modify existing classes and is a bit simpler than using a + * {@link Provider}. + * + * <p>The above list of examples is far from exhaustive. If you can think of how the concepts of one + * example might coexist with the concepts from another, you can most likely weave the two together. + * If the two concepts make no sense with each other, you most likely won't be able to do it. In a + * few cases Guice will let something bogus slip by, and will then inform you of the problems at + * runtime, as soon as you try to create your Injector. + * + * <p>The other methods of Binder such as {@link #bindScope}, {@link #bindInterceptor}, {@link + * #install}, {@link #requestStaticInjection}, {@link #addError} and {@link #currentStage} are not + * part of the Binding EDSL; you can learn how to use these in the usual way, from the method * documentation. * * @author crazybob@google.com (Bob Lee) @@ -211,51 +189,41 @@ public interface Binder { * eligible for interception if: * * <ul> - * <li>Guice created the instance the method is on</li> - * <li>Neither the enclosing type nor the method is final</li> - * <li>And the method is package-private, protected, or public</li> + * <li>Guice created the instance the method is on + * <li>Neither the enclosing type nor the method is final + * <li>And the method is package-private, protected, or public * </ul> * - * @param classMatcher matches classes the interceptor should apply to. For - * example: {@code only(Runnable.class)}. - * @param methodMatcher matches methods the interceptor should apply to. For - * example: {@code annotatedWith(Transactional.class)}. - * @param interceptors to bind. The interceptors are called in the order they - * are given. + * @param classMatcher matches classes the interceptor should apply to. For example: {@code + * only(Runnable.class)}. + * @param methodMatcher matches methods the interceptor should apply to. For example: {@code + * annotatedWith(Transactional.class)}. + * @param interceptors to bind. The interceptors are called in the order they are given. */ - void bindInterceptor(Matcher<? super Class<?>> classMatcher, + void bindInterceptor( + Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors); /*end[AOP]*/ - /** - * Binds a scope to an annotation. - */ + /** Binds a scope to an annotation. */ void bindScope(Class<? extends Annotation> annotationType, Scope scope); - /** - * See the EDSL examples at {@link Binder}. - */ + /** See the EDSL examples at {@link Binder}. */ <T> LinkedBindingBuilder<T> bind(Key<T> key); - /** - * See the EDSL examples at {@link Binder}. - */ + /** See the EDSL examples at {@link Binder}. */ <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral); - /** - * See the EDSL examples at {@link Binder}. - */ + /** See the EDSL examples at {@link Binder}. */ <T> AnnotatedBindingBuilder<T> bind(Class<T> type); - /** - * See the EDSL examples at {@link Binder}. - */ + /** See the EDSL examples at {@link Binder}. */ AnnotatedConstantBindingBuilder bindConstant(); /** - * Upon successful creation, the {@link Injector} will inject instance fields - * and methods of the given object. + * Upon successful creation, the {@link Injector} will inject instance fields and methods of the + * given object. * * @param type of instance * @param instance for which members will be injected @@ -264,8 +232,8 @@ public interface Binder { <T> void requestInjection(TypeLiteral<T> type, T instance); /** - * Upon successful creation, the {@link Injector} will inject instance fields - * and methods of the given object. + * Upon successful creation, the {@link Injector} will inject instance fields and methods of the + * given object. * * @param instance for which members will be injected * @since 2.0 @@ -273,37 +241,30 @@ public interface Binder { void requestInjection(Object instance); /** - * Upon successful creation, the {@link Injector} will inject static fields - * and methods in the given classes. + * Upon successful creation, the {@link Injector} will inject static fields and methods in the + * given classes. * * @param types for which static members will be injected */ void requestStaticInjection(Class<?>... types); - /** - * Uses the given module to configure more bindings. - */ + /** Uses the given module to configure more bindings. */ void install(Module module); - /** - * Gets the current stage. - */ + /** Gets the current stage. */ Stage currentStage(); /** - * Records an error message which will be presented to the user at a later - * time. Unlike throwing an exception, this enable us to continue - * configuring the Injector and discover more errors. Uses {@link - * String#format(String, Object[])} to insert the arguments into the - * message. + * Records an error message which will be presented to the user at a later time. Unlike throwing + * an exception, this enable us to continue configuring the Injector and discover more errors. + * Uses {@link String#format(String, Object[])} to insert the arguments into the message. */ void addError(String message, Object... arguments); /** - * Records an exception, the full details of which will be logged, and the - * message of which will be presented to the user at a later - * time. If your Module calls something that you worry may fail, you should - * catch the exception and pass it into this. + * Records an exception, the full details of which will be logged, and the message of which will + * be presented to the user at a later time. If your Module calls something that you worry may + * fail, you should catch the exception and pass it into this. */ void addError(Throwable t); @@ -315,32 +276,29 @@ public interface Binder { void addError(Message message); /** - * Returns the provider used to obtain instances for the given injection key. - * The returned provider will not be valid until the {@link Injector} has been - * created. The provider will throw an {@code IllegalStateException} if you - * try to use it beforehand. + * Returns the provider used to obtain instances for the given injection key. The returned + * provider will not be valid until the {@link Injector} has been created. The provider will throw + * an {@code IllegalStateException} if you try to use it beforehand. * * @since 2.0 */ <T> Provider<T> getProvider(Key<T> key); /** - * Returns the provider used to obtain instances for the given injection key. - * The returned provider will be attached to the injection point and will - * follow the nullability specified in the dependency. - * Additionally, the returned provider will not be valid until the {@link Injector} - * has been created. The provider will throw an {@code IllegalStateException} if you - * try to use it beforehand. + * Returns the provider used to obtain instances for the given injection key. The returned + * provider will be attached to the injection point and will follow the nullability specified in + * the dependency. Additionally, the returned provider will not be valid until the {@link + * Injector} has been created. The provider will throw an {@code IllegalStateException} if you try + * to use it beforehand. * * @since 4.0 */ <T> Provider<T> getProvider(Dependency<T> dependency); /** - * Returns the provider used to obtain instances for the given injection type. - * The returned provider will not be valid until the {@link Injector} has been - * created. The provider will throw an {@code IllegalStateException} if you - * try to use it beforehand. + * Returns the provider used to obtain instances for the given injection type. The returned + * provider will not be valid until the {@link Injector} has been created. The provider will throw + * an {@code IllegalStateException} if you try to use it beforehand. * * @since 2.0 */ @@ -369,15 +327,14 @@ public interface Binder { <T> MembersInjector<T> getMembersInjector(Class<T> type); /** - * Binds a type converter. The injector will use the given converter to - * convert string constants to matching types as needed. + * Binds a type converter. The injector will use the given converter to convert string constants + * to matching types as needed. * * @param typeMatcher matches types the converter can handle * @param converter converts values * @since 2.0 */ - void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter converter); + void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter); /** * Registers a listener for injectable types. Guice will notify the listener when it encounters @@ -387,43 +344,38 @@ public interface Binder { * @param listener for injectable types matched by typeMatcher * @since 2.0 */ - void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeListener listener); + void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener); /** - * Registers listeners for provisioned objects. Guice will notify the - * listeners just before and after the object is provisioned. Provisioned - * objects that are also injectable (everything except objects provided - * through Providers) can also be notified through TypeListeners registered in - * {@link #bindListener}. - * - * @param bindingMatcher that matches bindings of provisioned objects the listener - * should be notified of - * @param listeners for provisioned objects matched by bindingMatcher + * Registers listeners for provisioned objects. Guice will notify the listeners just before and + * after the object is provisioned. Provisioned objects that are also injectable (everything + * except objects provided through Providers) can also be notified through TypeListeners + * registered in {@link #bindListener}. + * + * @param bindingMatcher that matches bindings of provisioned objects the listener should be + * notified of + * @param listeners for provisioned objects matched by bindingMatcher * @since 4.0 */ void bindListener(Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners); /** - * Returns a binder that uses {@code source} as the reference location for - * configuration errors. This is typically a {@link StackTraceElement} - * for {@code .java} source but it could any binding source, such as the - * path to a {@code .properties} file. + * Returns a binder that uses {@code source} as the reference location for configuration errors. + * This is typically a {@link StackTraceElement} for {@code .java} source but it could any binding + * source, such as the path to a {@code .properties} file. * - * @param source any object representing the source location and has a - * concise {@link Object#toString() toString()} value + * @param source any object representing the source location and has a concise {@link + * Object#toString() toString()} value * @return a binder that shares its configuration with this binder * @since 2.0 */ Binder withSource(Object source); /** - * Returns a binder that skips {@code classesToSkip} when identify the - * calling code. The caller's {@link StackTraceElement} is used to locate - * the source of configuration errors. + * Returns a binder that skips {@code classesToSkip} when identify the calling code. The caller's + * {@link StackTraceElement} is used to locate the source of configuration errors. * - * @param classesToSkip library classes that create bindings on behalf of - * their clients. + * @param classesToSkip library classes that create bindings on behalf of their clients. * @return a binder that shares its configuration with this binder. * @since 2.0 */ @@ -435,75 +387,69 @@ public interface Binder { * PrivateModule} for details. * * @return a binder that inherits configuration from this binder. Only exposed configuration on - * the returned binder will be visible to this binder. + * the returned binder will be visible to this binder. * @since 2.0 */ PrivateBinder newPrivateBinder(); /** - * Instructs the Injector that bindings must be listed in a Module in order to - * be injected. Classes that are not explicitly bound in a module cannot be - * injected. Bindings created through a linked binding - * (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the - * implicit binding (<code>FooImpl</code>) cannot be directly injected unless - * it is also explicitly bound (<code>bind(FooImpl.class)</code>). - * <p> - * Tools can still retrieve bindings for implicit bindings (bindings created - * through a linked binding) if explicit bindings are required, however - * {@link Binding#getProvider} will fail. - * <p> - * By default, explicit bindings are not required. - * <p> - * If a parent injector requires explicit bindings, then all child injectors - * (and private modules within that injector) also require explicit bindings. - * If a parent does not require explicit bindings, a child injector or private - * module may optionally declare itself as requiring explicit bindings. If it - * does, the behavior is limited only to that child or any grandchildren. No - * siblings of the child will require explicit bindings. - * <p> - * In the absence of an explicit binding for the target, linked bindings in - * child injectors create a binding for the target in the parent. Since this - * behavior can be surprising, it causes an error instead if explicit bindings - * are required. To avoid this error, add an explicit binding for the target, - * either in the child or the parent. - * + * Instructs the Injector that bindings must be listed in a Module in order to be injected. + * Classes that are not explicitly bound in a module cannot be injected. Bindings created through + * a linked binding (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the implicit + * binding (<code>FooImpl</code>) cannot be directly injected unless it is also explicitly bound ( + * <code>bind(FooImpl.class)</code>). + * + * <p>Tools can still retrieve bindings for implicit bindings (bindings created through a linked + * binding) if explicit bindings are required, however {@link Binding#getProvider} will fail. + * + * <p>By default, explicit bindings are not required. + * + * <p>If a parent injector requires explicit bindings, then all child injectors (and private + * modules within that injector) also require explicit bindings. If a parent does not require + * explicit bindings, a child injector or private module may optionally declare itself as + * requiring explicit bindings. If it does, the behavior is limited only to that child or any + * grandchildren. No siblings of the child will require explicit bindings. + * + * <p>In the absence of an explicit binding for the target, linked bindings in child injectors + * create a binding for the target in the parent. Since this behavior can be surprising, it causes + * an error instead if explicit bindings are required. To avoid this error, add an explicit + * binding for the target, either in the child or the parent. + * * @since 3.0 */ void requireExplicitBindings(); - + /** - * Prevents Guice from constructing a {@link Proxy} when a circular dependency - * is found. By default, circular proxies are not disabled. - * <p> - * If a parent injector disables circular proxies, then all child injectors - * (and private modules within that injector) also disable circular proxies. - * If a parent does not disable circular proxies, a child injector or private - * module may optionally declare itself as disabling circular proxies. If it - * does, the behavior is limited only to that child or any grandchildren. No - * siblings of the child will disable circular proxies. - * + * Prevents Guice from injecting dependencies that form a cycle, unless broken by a {@link + * Provider}. By default, circular dependencies are not disabled. + * + * <p>If a parent injector disables circular dependencies, then all child injectors (and private + * modules within that injector) also disable circular dependencies. If a parent does not disable + * circular dependencies, a child injector or private module may optionally declare itself as + * disabling circular dependencies. If it does, the behavior is limited only to that child or any + * grandchildren. No siblings of the child will disable circular dependencies. + * * @since 3.0 */ void disableCircularProxies(); - + /** * Requires that a {@literal @}{@link Inject} annotation exists on a constructor in order for * Guice to consider it an eligible injectable class. By default, Guice will inject classes that * have a no-args constructor if no {@literal @}{@link Inject} annotation exists on any * constructor. - * <p> - * If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still inject - * that constructor regardless of annotations. + * + * <p>If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still + * inject that constructor regardless of annotations. * * @since 4.0 */ void requireAtInjectOnConstructors(); /** - * Requires that Guice finds an exactly matching binding annotation. This disables the - * error-prone feature in Guice where it can substitute a binding for - * <code>{@literal @}Named Foo</code> when attempting to inject - * <code>{@literal @}Named("foo") Foo</code>. + * Requires that Guice finds an exactly matching binding annotation. This disables the error-prone + * feature in Guice where it can substitute a binding for <code>{@literal @}Named Foo</code> when + * attempting to inject <code>{@literal @}Named("foo") Foo</code>. * * @since 4.0 */ diff --git a/core/src/com/google/inject/Binding.java b/core/src/com/google/inject/Binding.java index 332237e6..caf52f0a 100644 --- a/core/src/com/google/inject/Binding.java +++ b/core/src/com/google/inject/Binding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,55 +22,50 @@ import com.google.inject.spi.Element; /** * A mapping from a key (type and optional annotation) to the strategy for getting instances of the - * type. This interface is part of the introspection API and is intended primarily for use by - * tools. + * type. This interface is part of the introspection API and is intended primarily for use by tools. * * <p>Bindings are created in several ways: + * * <ul> - * <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()} - * statements: - * <pre> + * <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()} statements: + * <pre> * bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class); - * bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre></li> - * <li>Implicitly by the Injector by following a type's {@link ImplementedBy - * pointer} {@link ProvidedBy annotations} or by using its {@link Inject annotated} or - * default constructor.</li> - * <li>By converting a bound instance to a different type.</li> - * <li>For {@link Provider providers}, by delegating to the binding for the provided type.</li> - * </ul> + * bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre> * + * <li>Implicitly by the Injector by following a type's {@link ImplementedBy pointer} {@link + * ProvidedBy annotations} or by using its {@link Inject annotated} or default constructor. + * <li>By converting a bound instance to a different type. + * <li>For {@link Provider providers}, by delegating to the binding for the provided type. + * </ul> * * <p>They exist on both modules and on injectors, and their behaviour is different for each: + * * <ul> - * <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances. - * This is because the applicable scopes and interceptors may not be known until an injector - * is created. From a tool's perspective, module bindings are like the injector's source - * code. They can be inspected or rewritten, but this analysis must be done statically.</li> - * <li><strong>Injector bindings</strong> are complete and valid and can be used to provide - * instances. From a tools' perspective, injector bindings are like reflection for an - * injector. They have full runtime information, including the complete graph of injections - * necessary to satisfy a binding.</li> + * <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances. This + * is because the applicable scopes and interceptors may not be known until an injector is + * created. From a tool's perspective, module bindings are like the injector's source code. They + * can be inspected or rewritten, but this analysis must be done statically. + * <li><strong>Injector bindings</strong> are complete and valid and can be used to provide + * instances. From a tools' perspective, injector bindings are like reflection for an injector. + * They have full runtime information, including the complete graph of injections necessary to + * satisfy a binding. * </ul> * * @param <T> the bound type. The injected is always assignable to this type. - * * @author crazybob@google.com (Bob Lee) * @author jessewilson@google.com (Jesse Wilson) */ public interface Binding<T> extends Element { - /** - * Returns the key for this binding. - */ + /** Returns the key for this binding. */ Key<T> getKey(); /** - * Returns the scoped provider guice uses to fulfill requests for this - * binding. + * Returns the scoped provider guice uses to fulfill requests for this binding. * - * @throws UnsupportedOperationException when invoked on a {@link Binding} - * created via {@link com.google.inject.spi.Elements#getElements}. This - * method is only supported on {@link Binding}s returned from an injector. + * @throws UnsupportedOperationException when invoked on a {@link Binding} created via {@link + * com.google.inject.spi.Elements#getElements}. This method is only supported on {@link + * Binding}s returned from an injector. */ Provider<T> getProvider(); diff --git a/core/src/com/google/inject/BindingAnnotation.java b/core/src/com/google/inject/BindingAnnotation.java index 2d373e43..5a2050e9 100644 --- a/core/src/com/google/inject/BindingAnnotation.java +++ b/core/src/com/google/inject/BindingAnnotation.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,9 +23,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * Annotates annotations which are used for binding. Only one such annotation - * may apply to a single injection point. You must also annotate binder - * annotations with {@code @Retention(RUNTIME)}. For example: + * Annotates annotations which are used for binding. Only one such annotation may apply to a single + * injection point. You must also annotate binder annotations with {@code @Retention(RUNTIME)}. For + * example: * * <pre> * {@code @}Retention(RUNTIME) diff --git a/core/src/com/google/inject/ConfigurationException.java b/core/src/com/google/inject/ConfigurationException.java index e298cff8..3d3b73cc 100644 --- a/core/src/com/google/inject/ConfigurationException.java +++ b/core/src/com/google/inject/ConfigurationException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,10 +18,8 @@ package com.google.inject; import static com.google.common.base.Preconditions.checkState; -import com.google.common.collect.ImmutableSet; -import com.google.inject.internal.Errors; +import com.google.inject.internal.Messages; import com.google.inject.spi.Message; - import java.util.Collection; /** @@ -33,13 +31,13 @@ import java.util.Collection; */ public final class ConfigurationException extends RuntimeException { - private final ImmutableSet<Message> messages; + private final com.google.common.collect.ImmutableSet<Message> messages; private Object partialValue = null; /** Creates a ConfigurationException containing {@code messages}. */ public ConfigurationException(Iterable<Message> messages) { - this.messages = ImmutableSet.copyOf(messages); - initCause(Errors.getOnlyCause(this.messages)); + this.messages = com.google.common.collect.ImmutableSet.copyOf(messages); + initCause(Messages.getOnlyCause(this.messages)); } /** Returns a copy of this configuration exception with the specified partial value. */ @@ -57,20 +55,23 @@ public final class ConfigurationException extends RuntimeException { } /** - * Returns a value that was only partially computed due to this exception. The caller can use - * this while collecting additional configuration problems. + * Returns a value that was only partially computed due to this exception. The caller can use this + * while collecting additional configuration problems. * * @return the partial value, or {@code null} if none was set. The type of the partial value is - * specified by the throwing method. + * specified by the throwing method. */ - @SuppressWarnings("unchecked") // this is *extremely* unsafe. We trust the caller here. + @SuppressWarnings({ + "unchecked", + "TypeParameterUnusedInFormals" + }) // this is *extremely* unsafe. We trust the caller here. public <E> E getPartialValue() { return (E) partialValue; } @Override public String getMessage() { - return Errors.format("Guice configuration errors", messages); + return Messages.formatMessages("Guice configuration errors", messages); } private static final long serialVersionUID = 0; -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/CreationException.java b/core/src/com/google/inject/CreationException.java index 4f84c22c..38e82819 100644 --- a/core/src/com/google/inject/CreationException.java +++ b/core/src/com/google/inject/CreationException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,9 +19,8 @@ package com.google.inject; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.collect.ImmutableSet; -import com.google.inject.internal.Errors; +import com.google.inject.internal.Messages; import com.google.inject.spi.Message; - import java.util.Collection; /** @@ -38,7 +37,7 @@ public class CreationException extends RuntimeException { public CreationException(Collection<Message> messages) { this.messages = ImmutableSet.copyOf(messages); checkArgument(!this.messages.isEmpty()); - initCause(Errors.getOnlyCause(this.messages)); + initCause(Messages.getOnlyCause(this.messages)); } /** Returns messages for the errors that caused this exception. */ @@ -46,8 +45,9 @@ public class CreationException extends RuntimeException { return messages; } - @Override public String getMessage() { - return Errors.format("Unable to create injector, see the following errors", messages); + @Override + public String getMessage() { + return Messages.formatMessages("Unable to create injector, see the following errors", messages); } private static final long serialVersionUID = 0; diff --git a/core/src/com/google/inject/Exposed.java b/core/src/com/google/inject/Exposed.java index 45a448fe..9e2e4418 100644 --- a/core/src/com/google/inject/Exposed.java +++ b/core/src/com/google/inject/Exposed.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,5 +30,7 @@ import java.lang.annotation.Target; * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 */ -@Target(ElementType.METHOD) @Retention(RUNTIME) @Documented +@Target(ElementType.METHOD) +@Retention(RUNTIME) +@Documented public @interface Exposed {} diff --git a/core/src/com/google/inject/Guice.java b/core/src/com/google/inject/Guice.java index 703187f8..ae8d43b2 100644 --- a/core/src/com/google/inject/Guice.java +++ b/core/src/com/google/inject/Guice.java @@ -17,19 +17,17 @@ package com.google.inject; import com.google.inject.internal.InternalInjectorCreator; - import java.util.Arrays; /** - * The entry point to the Guice framework. Creates {@link Injector}s from - * {@link Module}s. + * The entry point to the Guice framework. Creates {@link Injector}s from {@link Module}s. + * + * <p>Guice supports a model of development that draws clear boundaries between APIs, + * Implementations of these APIs, Modules which configure these implementations, and finally + * Applications which consist of a collection of Modules. It is the Application, which typically + * defines your {@code main()} method, that bootstraps the Guice Injector using the {@code Guice} + * class, as in this example: * - * <p>Guice supports a model of development that draws clear boundaries between - * APIs, Implementations of these APIs, Modules which configure these - * implementations, and finally Applications which consist of a collection of - * Modules. It is the Application, which typically defines your {@code main()} - * method, that bootstraps the Guice Injector using the {@code Guice} class, as - * in this example: * <pre> * public class FooApplication { * public static void main(String[] args) { @@ -52,50 +50,40 @@ public final class Guice { private Guice() {} /** - * Creates an injector for the given set of modules. This is equivalent to - * calling {@link #createInjector(Stage, Module...)} with Stage.DEVELOPMENT. + * Creates an injector for the given set of modules. This is equivalent to calling {@link + * #createInjector(Stage, Module...)} with Stage.DEVELOPMENT. * - * @throws CreationException if one or more errors occur during injector - * construction + * @throws CreationException if one or more errors occur during injector construction */ public static Injector createInjector(Module... modules) { return createInjector(Arrays.asList(modules)); } /** - * Creates an injector for the given set of modules. This is equivalent to - * calling {@link #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT. + * Creates an injector for the given set of modules. This is equivalent to calling {@link + * #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT. * - * @throws CreationException if one or more errors occur during injector - * creation + * @throws CreationException if one or more errors occur during injector creation */ public static Injector createInjector(Iterable<? extends Module> modules) { return createInjector(Stage.DEVELOPMENT, modules); } /** - * Creates an injector for the given set of modules, in a given development - * stage. + * Creates an injector for the given set of modules, in a given development stage. * - * @throws CreationException if one or more errors occur during injector - * creation. + * @throws CreationException if one or more errors occur during injector creation. */ public static Injector createInjector(Stage stage, Module... modules) { return createInjector(stage, Arrays.asList(modules)); } /** - * Creates an injector for the given set of modules, in a given development - * stage. + * Creates an injector for the given set of modules, in a given development stage. * - * @throws CreationException if one or more errors occur during injector - * construction + * @throws CreationException if one or more errors occur during injector construction */ - public static Injector createInjector(Stage stage, - Iterable<? extends Module> modules) { - return new InternalInjectorCreator() - .stage(stage) - .addModules(modules) - .build(); + public static Injector createInjector(Stage stage, Iterable<? extends Module> modules) { + return new InternalInjectorCreator().stage(stage).addModules(modules).build(); } } diff --git a/core/src/com/google/inject/ImplementedBy.java b/core/src/com/google/inject/ImplementedBy.java index 464a279e..f19bb860 100644 --- a/core/src/com/google/inject/ImplementedBy.java +++ b/core/src/com/google/inject/ImplementedBy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,8 +31,6 @@ import java.lang.annotation.Target; @Target(TYPE) public @interface ImplementedBy { - /** - * The implementation type. - */ + /** The implementation type. */ Class<?> value(); } diff --git a/core/src/com/google/inject/Inject.java b/core/src/com/google/inject/Inject.java index 535c0a42..3c4b396a 100644 --- a/core/src/com/google/inject/Inject.java +++ b/core/src/com/google/inject/Inject.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,44 +26,37 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * Annotates members of your implementation class (constructors, methods - * and fields) into which the {@link Injector} should inject values. - * The Injector fulfills injection requests for: + * Annotates members of your implementation class (constructors, methods and fields) into which the + * {@link Injector} should inject values. The Injector fulfills injection requests for: * * <ul> - * <li>Every instance it constructs. The class being constructed must have - * exactly one of its constructors marked with {@code @Inject} or must have a - * constructor taking no parameters. The Injector then proceeds to perform - * field and method injections. - * - * <li>Pre-constructed instances passed to {@link Injector#injectMembers}, - * {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and - * {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}. - * In this case all constructors are, of course, ignored. - * - * <li>Static fields and methods of classes which any {@link Module} has - * specifically requested static injection for, using - * {@link Binder#requestStaticInjection}. + * <li>Every instance it constructs. The class being constructed must have exactly one of its + * constructors marked with {@code @Inject} or must have a constructor taking no parameters. The + * Injector then proceeds to perform field and method injections. + * <li>Pre-constructed instances passed to {@link Injector#injectMembers}, {@link + * com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and {@link + * com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}. In this + * case all constructors are, of course, ignored. + * <li>Static fields and methods of classes which any {@link Module} has specifically requested + * static injection for, using {@link Binder#requestStaticInjection}. * </ul> * - * In all cases, a member can be injected regardless of its Java access - * specifier (private, default, protected, public). + * In all cases, a member can be injected regardless of its Java access specifier (private, default, + * protected, public). * * @author crazybob@google.com (Bob Lee) */ -@Target({ METHOD, CONSTRUCTOR, FIELD }) +@Target({METHOD, CONSTRUCTOR, FIELD}) @Retention(RUNTIME) @Documented public @interface Inject { /** - * If true, and the appropriate binding is not found, - * the Injector will skip injection of this method or field rather than - * produce an error. When applied to a field, any default value already - * assigned to the field will remain (guice will not actively null out the - * field). When applied to a method, the method will only be invoked if - * bindings for <i>all</i> parameters are found. When applied to a - * constructor, an error will result upon Injector creation. + * If true, and the appropriate binding is not found, the Injector will skip injection of this + * method or field rather than produce an error. When applied to a field, any default value + * already assigned to the field will remain (guice will not actively null out the field). When + * applied to a method, the method will only be invoked if bindings for <i>all</i> parameters are + * found. When applied to a constructor, an error will result upon Injector creation. */ boolean optional() default false; } diff --git a/core/src/com/google/inject/Injector.java b/core/src/com/google/inject/Injector.java index 42c7331d..d2ac4980 100644 --- a/core/src/com/google/inject/Injector.java +++ b/core/src/com/google/inject/Injector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,6 @@ package com.google.inject; import com.google.inject.spi.TypeConverterBinding; - import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; @@ -64,9 +63,8 @@ public interface Injector { * you, you'll never need to use this method. * * @param instance to inject members on - * * @see Binder#getMembersInjector(Class) for a preferred alternative that supports checks before - * run time + * run time */ void injectMembers(Object instance); @@ -76,7 +74,7 @@ public interface Injector { * * @param typeLiteral type to get members injector for * @see Binder#getMembersInjector(TypeLiteral) for an alternative that offers up front error - * detection + * detection * @since 2.0 */ <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral); @@ -87,8 +85,7 @@ public interface Injector { * instead to get increased up front error detection. * * @param type type to get members injector for - * @see Binder#getMembersInjector(Class) for an alternative that offers up front error - * detection + * @see Binder#getMembersInjector(Class) for an alternative that offers up front error detection * @since 2.0 */ <T> MembersInjector<T> getMembersInjector(Class<T> type); @@ -97,9 +94,9 @@ public interface Injector { * Returns this injector's <strong>explicit</strong> bindings. * * <p>The returned map does not include bindings inherited from a {@link #getParent() parent - * injector}, should one exist. The returned map is guaranteed to iterate (for example, with - * its {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in - * which bindings appear in user Modules. + * injector}, should one exist. The returned map is guaranteed to iterate (for example, with its + * {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in which + * bindings appear in user Modules. * * <p>This method is part of the Guice SPI and is intended for use by tools and extensions. */ @@ -108,14 +105,15 @@ public interface Injector { /** * Returns a snapshot of this injector's bindings, <strong>both explicit and * just-in-time</strong>. The returned map is immutable; it contains only the bindings that were - * present when {@code getAllBindings()} was invoked. Subsequent calls may return a map with - * additional just-in-time bindings. + * present when {@code getAllBindings()} was invoked. Just-in-time bindings are only present if + * they have been requested at least once. Subsequent calls may return a map with additional + * just-in-time bindings. * * <p>The returned map does not include bindings inherited from a {@link #getParent() parent * injector}, should one exist. * * <p>This method is part of the Guice SPI and is intended for use by tools and extensions. - * + * * @since 3.0 */ Map<Key<?>, Binding<?>> getAllBindings(); @@ -142,17 +140,17 @@ public interface Injector { * @since 2.0 */ <T> Binding<T> getBinding(Class<T> type); - + /** - * Returns the binding if it already exists, or null if does not exist. Unlike - * {@link #getBinding(Key)}, this does not attempt to create just-in-time bindings - * for keys that aren't bound. - * - * <p> This method is part of the Guice SPI and is intended for use by tools and extensions. - * + * Returns the binding if it already exists, or null if does not exist. Unlike {@link + * #getBinding(Key)}, this does not attempt to create just-in-time bindings for keys that aren't + * bound. + * + * <p>This method is part of the Guice SPI and is intended for use by tools and extensions. + * * @since 3.0 */ - <T> Binding<T> getExistingBinding(Key<T> key); + <T> Binding<T> getExistingBinding(Key<T> key); /** * Returns all explicit bindings for {@code type}. @@ -171,8 +169,8 @@ public interface Injector { <T> Provider<T> getProvider(Key<T> key); /** - * Returns the provider used to obtain instances for the given type. When feasible, avoid - * using this method, in favor of having Guice inject your dependencies ahead of time. + * Returns the provider used to obtain instances for the given type. When feasible, avoid using + * this method, in favor of having Guice inject your dependencies ahead of time. * * @throws ConfigurationException if this injector cannot find or create the provider. * @see Binder#getProvider(Class) for an alternative that offers up front error detection @@ -213,9 +211,9 @@ public interface Injector { * * <p>Just-in-time bindings created for child injectors will be created in an ancestor injector * whenever possible. This allows for scoped instances to be shared between injectors. Use - * explicit bindings to prevent bindings from being shared with the parent injector. Optional - * injections in just-in-time bindings (created in the parent injector) may be silently - * ignored if the optional dependencies are from the child injector. + * explicit bindings to prevent bindings from being shared with the parent injector. Optional + * injections in just-in-time bindings (created in the parent injector) may be silently ignored if + * the optional dependencies are from the child injector. * * <p>No key may be bound by both an injector and one of its ancestors. This includes just-in-time * bindings. The lone exception is the key for {@code Injector.class}, which is bound by each @@ -243,12 +241,12 @@ public interface Injector { Injector createChildInjector(Module... modules); /** - * Returns a map containing all scopes in the injector. The maps keys are scoping annotations - * like {@code Singleton.class}, and the values are scope instances, such as {@code - * Scopes.SINGLETON}. The returned map is immutable. + * Returns a map containing all scopes in the injector. The maps keys are scoping annotations like + * {@code Singleton.class}, and the values are scope instances, such as {@code Scopes.SINGLETON}. + * The returned map is immutable. * * <p>This method is part of the Guice SPI and is intended for use by tools and extensions. - * + * * @since 3.0 */ Map<Class<? extends Annotation>, Scope> getScopeBindings(); @@ -258,7 +256,7 @@ public interface Injector { * immutable. * * <p>This method is part of the Guice SPI and is intended for use by tools and extensions. - * + * * @since 3.0 */ Set<TypeConverterBinding> getTypeConverterBindings(); diff --git a/core/src/com/google/inject/Key.java b/core/src/com/google/inject/Key.java index c93dabfe..55779f3b 100644 --- a/core/src/com/google/inject/Key.java +++ b/core/src/com/google/inject/Key.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,20 +21,16 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.inject.internal.Annotations.generateAnnotation; import static com.google.inject.internal.Annotations.isAllDefaultMethods; -import com.google.common.base.Supplier; -import com.google.common.base.Suppliers; import com.google.inject.internal.Annotations; import com.google.inject.internal.MoreTypes; - import java.lang.annotation.Annotation; import java.lang.reflect.Type; /** - * Binding key consisting of an injection type and an optional annotation. - * Matches the type and annotation at a point of injection. + * Binding key consisting of an injection type and an optional annotation. Matches the type and + * annotation at a point of injection. * - * <p>For example, {@code Key.get(Service.class, Transactional.class)} will - * match: + * <p>For example, {@code Key.get(Service.class, Transactional.class)} will match: * * <pre> * {@literal @}Inject @@ -43,12 +39,11 @@ import java.lang.reflect.Type; * } * </pre> * - * <p>{@code Key} supports generic types via subclassing just like {@link - * TypeLiteral}. + * <p>{@code Key} supports generic types via subclassing just like {@link TypeLiteral}. * - * <p>Keys do not differentiate between primitive types (int, char, etc.) and - * their corresponding wrapper types (Integer, Character, etc.). Primitive - * types will be replaced with their wrapper types when keys are created. + * <p>Keys do not differentiate between primitive types (int, char, etc.) and their corresponding + * wrapper types (Integer, Character, etc.). Primitive types will be replaced with their wrapper + * types when keys are created. * * @author crazybob@google.com (Bob Lee) */ @@ -58,38 +53,37 @@ public class Key<T> { private final TypeLiteral<T> typeLiteral; private final int hashCode; - private final Supplier<String> toStringSupplier; + // This field is updated using the 'Data-Race-Ful' lazy intialization pattern + // See http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html for a detailed + // explanation. + private String toString; /** * Constructs a new key. Derives the type from this class's type parameter. * - * <p>Clients create an empty anonymous subclass. Doing so embeds the type - * parameter in the anonymous class's type hierarchy so we can reconstitute it - * at runtime despite erasure. + * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the + * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure. * - * <p>Example usage for a binding of type {@code Foo} annotated with - * {@code @Bar}: + * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}: * * <p>{@code new Key<Foo>(Bar.class) {}}. */ @SuppressWarnings("unchecked") protected Key(Class<? extends Annotation> annotationType) { this.annotationStrategy = strategyFor(annotationType); - this.typeLiteral = MoreTypes.canonicalizeForKey( - (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); + this.typeLiteral = + MoreTypes.canonicalizeForKey( + (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); this.hashCode = computeHashCode(); - this.toStringSupplier = createToStringSupplier(); } /** * Constructs a new key. Derives the type from this class's type parameter. * - * <p>Clients create an empty anonymous subclass. Doing so embeds the type - * parameter in the anonymous class's type hierarchy so we can reconstitute it - * at runtime despite erasure. + * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the + * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure. * - * <p>Example usage for a binding of type {@code Foo} annotated with - * {@code @Bar}: + * <p>Example usage for a binding of type {@code Foo} annotated with {@code @Bar}: * * <p>{@code new Key<Foo>(new Bar()) {}}. */ @@ -97,18 +91,17 @@ public class Key<T> { protected Key(Annotation annotation) { // no usages, not test-covered this.annotationStrategy = strategyFor(annotation); - this.typeLiteral = MoreTypes.canonicalizeForKey( - (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); + this.typeLiteral = + MoreTypes.canonicalizeForKey( + (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); this.hashCode = computeHashCode(); - this.toStringSupplier = createToStringSupplier(); } /** * Constructs a new key. Derives the type from this class's type parameter. * - * <p>Clients create an empty anonymous subclass. Doing so embeds the type - * parameter in the anonymous class's type hierarchy so we can reconstitute it - * at runtime despite erasure. + * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the + * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure. * * <p>Example usage for a binding of type {@code Foo}: * @@ -117,21 +110,18 @@ public class Key<T> { @SuppressWarnings("unchecked") protected Key() { this.annotationStrategy = NullAnnotationStrategy.INSTANCE; - this.typeLiteral = MoreTypes.canonicalizeForKey( - (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); + this.typeLiteral = + MoreTypes.canonicalizeForKey( + (TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass())); this.hashCode = computeHashCode(); - this.toStringSupplier = createToStringSupplier(); } - /** - * Unsafe. Constructs a key from a manually specified type. - */ + /** Unsafe. Constructs a key from a manually specified type. */ @SuppressWarnings("unchecked") private Key(Type type, AnnotationStrategy annotationStrategy) { this.annotationStrategy = annotationStrategy; this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type)); this.hashCode = computeHashCode(); - this.toStringSupplier = createToStringSupplier(); } /** Constructs a key from a manually specified type. */ @@ -139,46 +129,24 @@ public class Key<T> { this.annotationStrategy = annotationStrategy; this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral); this.hashCode = computeHashCode(); - this.toStringSupplier = createToStringSupplier(); } - /** - * Computes the hash code for this key. - */ + /** Computes the hash code for this key. */ private int computeHashCode() { return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode(); } - /** - * @return a {@link Supplier} which memoizes the value for lazy initialization. - */ - private Supplier<String> createToStringSupplier() { - // The performance hit on access is acceptable since the intended use is for non-performance- - // critical applications such as debugging and logging. - return Suppliers.memoize(new Supplier<String>() { - @Override public String get() { - return "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]"; - } - }); - } - - /** - * Gets the key type. - */ + /** Gets the key type. */ public final TypeLiteral<T> getTypeLiteral() { return typeLiteral; } - /** - * Gets the annotation type. - */ + /** Gets the annotation type. */ public final Class<? extends Annotation> getAnnotationType() { return annotationStrategy.getAnnotationType(); } - /** - * Gets the annotation. - */ + /** Gets the annotation. */ public final Annotation getAnnotation() { return annotationStrategy.getAnnotation(); } @@ -201,14 +169,13 @@ public class Key<T> { return typeLiteral.getRawType(); } - /** - * Gets the key of this key's provider. - */ + /** Gets the key of this key's provider. */ Key<Provider<T>> providerKey() { return ofType(typeLiteral.providerType()); } - @Override public final boolean equals(Object o) { + @Override + public final boolean equals(Object o) { if (o == this) { return true; } @@ -220,92 +187,76 @@ public class Key<T> { && typeLiteral.equals(other.typeLiteral); } - @Override public final int hashCode() { + @Override + public final int hashCode() { return this.hashCode; } - @Override public final String toString() { - return toStringSupplier.get(); + @Override + public final String toString() { + // Note: to not introduce dangerous data races the field should only be read once in this + // method. + String local = toString; + if (local == null) { + local = "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]"; + toString = local; + } + return local; } - /** - * Gets a key for an injection type and an annotation strategy. - */ - static <T> Key<T> get(Class<T> type, - AnnotationStrategy annotationStrategy) { + /** Gets a key for an injection type and an annotation strategy. */ + static <T> Key<T> get(Class<T> type, AnnotationStrategy annotationStrategy) { return new Key<T>(type, annotationStrategy); } - /** - * Gets a key for an injection type. - */ + /** Gets a key for an injection type. */ public static <T> Key<T> get(Class<T> type) { return new Key<T>(type, NullAnnotationStrategy.INSTANCE); } - /** - * Gets a key for an injection type and an annotation type. - */ - public static <T> Key<T> get(Class<T> type, - Class<? extends Annotation> annotationType) { + /** Gets a key for an injection type and an annotation type. */ + public static <T> Key<T> get(Class<T> type, Class<? extends Annotation> annotationType) { return new Key<T>(type, strategyFor(annotationType)); } - /** - * Gets a key for an injection type and an annotation. - */ + /** Gets a key for an injection type and an annotation. */ public static <T> Key<T> get(Class<T> type, Annotation annotation) { return new Key<T>(type, strategyFor(annotation)); } - /** - * Gets a key for an injection type. - */ + /** Gets a key for an injection type. */ public static Key<?> get(Type type) { return new Key<Object>(type, NullAnnotationStrategy.INSTANCE); } - /** - * Gets a key for an injection type and an annotation type. - */ - public static Key<?> get(Type type, - Class<? extends Annotation> annotationType) { + /** Gets a key for an injection type and an annotation type. */ + public static Key<?> get(Type type, Class<? extends Annotation> annotationType) { return new Key<Object>(type, strategyFor(annotationType)); } - /** - * Gets a key for an injection type and an annotation. - */ + /** Gets a key for an injection type and an annotation. */ public static Key<?> get(Type type, Annotation annotation) { return new Key<Object>(type, strategyFor(annotation)); } - /** - * Gets a key for an injection type. - */ + /** Gets a key for an injection type. */ public static <T> Key<T> get(TypeLiteral<T> typeLiteral) { return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE); } - /** - * Gets a key for an injection type and an annotation type. - */ - public static <T> Key<T> get(TypeLiteral<T> typeLiteral, - Class<? extends Annotation> annotationType) { + /** Gets a key for an injection type and an annotation type. */ + public static <T> Key<T> get( + TypeLiteral<T> typeLiteral, Class<? extends Annotation> annotationType) { return new Key<T>(typeLiteral, strategyFor(annotationType)); } - /** - * Gets a key for an injection type and an annotation. - */ - public static <T> Key<T> get(TypeLiteral<T> typeLiteral, - Annotation annotation) { + /** Gets a key for an injection type and an annotation. */ + public static <T> Key<T> get(TypeLiteral<T> typeLiteral, Annotation annotation) { return new Key<T>(typeLiteral, strategyFor(annotation)); } /** - * Returns a new key of the specified type with the same annotation as this - * key. + * Returns a new key of the specified type with the same annotation as this key. * * @since 3.0 */ @@ -314,8 +265,7 @@ public class Key<T> { } /** - * Returns a new key of the specified type with the same annotation as this - * key. + * Returns a new key of the specified type with the same annotation as this key. * * @since 3.0 */ @@ -324,8 +274,7 @@ public class Key<T> { } /** - * Returns a new key of the specified type with the same annotation as this - * key. + * Returns a new key of the specified type with the same annotation as this key. * * @since 3.0 */ @@ -343,8 +292,7 @@ public class Key<T> { } /** - * Returns this key without annotation attributes, i.e. with only the - * annotation type. + * Returns this key without annotation attributes, i.e. with only the annotation type. * * @since 3.0 */ @@ -354,14 +302,15 @@ public class Key<T> { interface AnnotationStrategy { Annotation getAnnotation(); + Class<? extends Annotation> getAnnotationType(); + boolean hasAttributes(); + AnnotationStrategy withoutAttributes(); } - /** - * Gets the strategy for an annotation. - */ + /** Gets the strategy for an annotation. */ static AnnotationStrategy strategyFor(Annotation annotation) { checkNotNull(annotation, "annotation"); Class<? extends Annotation> annotationType = annotation.annotationType(); @@ -375,9 +324,7 @@ public class Key<T> { return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation)); } - /** - * Gets the strategy for an annotation type. - */ + /** Gets the strategy for an annotation type. */ static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) { annotationType = Annotations.canonicalizeIfNamed(annotationType); if (isAllDefaultMethods(annotationType)) { @@ -388,18 +335,18 @@ public class Key<T> { ensureRetainedAtRuntime(annotationType); ensureIsBindingAnnotation(annotationType); return new AnnotationTypeStrategy(annotationType, null); - } - private static void ensureRetainedAtRuntime( - Class<? extends Annotation> annotationType) { - checkArgument(Annotations.isRetainedAtRuntime(annotationType), + private static void ensureRetainedAtRuntime(Class<? extends Annotation> annotationType) { + checkArgument( + Annotations.isRetainedAtRuntime(annotationType), "%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).", annotationType.getName()); } private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) { - checkArgument(Annotations.isBindingAnnotation(annotationType), + checkArgument( + Annotations.isBindingAnnotation(annotationType), "%s is not a binding annotation. Please annotate it with @BindingAnnotation.", annotationType.getName()); } @@ -407,23 +354,28 @@ public class Key<T> { static enum NullAnnotationStrategy implements AnnotationStrategy { INSTANCE; + @Override public boolean hasAttributes() { return false; } + @Override public AnnotationStrategy withoutAttributes() { throw new UnsupportedOperationException("Key already has no attributes."); } + @Override public Annotation getAnnotation() { return null; } + @Override public Class<? extends Annotation> getAnnotationType() { return null; } - @Override public String toString() { + @Override + public String toString() { return "[none]"; } } @@ -437,23 +389,28 @@ public class Key<T> { this.annotation = checkNotNull(annotation, "annotation"); } + @Override public boolean hasAttributes() { return true; } + @Override public AnnotationStrategy withoutAttributes() { return new AnnotationTypeStrategy(getAnnotationType(), annotation); } + @Override public Annotation getAnnotation() { return annotation; } + @Override public Class<? extends Annotation> getAnnotationType() { return annotation.annotationType(); } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (!(o instanceof AnnotationInstanceStrategy)) { return false; } @@ -462,11 +419,13 @@ public class Key<T> { return annotation.equals(other.annotation); } - @Override public int hashCode() { + @Override + public int hashCode() { return annotation.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return annotation.toString(); } } @@ -478,29 +437,33 @@ public class Key<T> { // Keep the instance around if we have it so the client can request it. final Annotation annotation; - AnnotationTypeStrategy(Class<? extends Annotation> annotationType, - Annotation annotation) { + AnnotationTypeStrategy(Class<? extends Annotation> annotationType, Annotation annotation) { this.annotationType = checkNotNull(annotationType, "annotation type"); this.annotation = annotation; } + @Override public boolean hasAttributes() { return false; } + @Override public AnnotationStrategy withoutAttributes() { throw new UnsupportedOperationException("Key already has no attributes."); } + @Override public Annotation getAnnotation() { return annotation; } + @Override public Class<? extends Annotation> getAnnotationType() { return annotationType; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (!(o instanceof AnnotationTypeStrategy)) { return false; } @@ -509,11 +472,13 @@ public class Key<T> { return annotationType.equals(other.annotationType); } - @Override public int hashCode() { + @Override + public int hashCode() { return annotationType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "@" + annotationType.getName(); } } diff --git a/core/src/com/google/inject/MembersInjector.java b/core/src/com/google/inject/MembersInjector.java index b50dedbe..349eb0da 100644 --- a/core/src/com/google/inject/MembersInjector.java +++ b/core/src/com/google/inject/MembersInjector.java @@ -21,7 +21,6 @@ package com.google.inject; * presence or absence of an injectable constructor. * * @param <T> type to inject members of - * * @author crazybob@google.com (Bob Lee) * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 diff --git a/core/src/com/google/inject/Module.java b/core/src/com/google/inject/Module.java index f22d93f8..52cdd306 100644 --- a/core/src/com/google/inject/Module.java +++ b/core/src/com/google/inject/Module.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,18 +17,16 @@ package com.google.inject; /** - * A module contributes configuration information, typically interface - * bindings, which will be used to create an {@link Injector}. A Guice-based - * application is ultimately composed of little more than a set of - * {@code Module}s and some bootstrapping code. + * A module contributes configuration information, typically interface bindings, which will be used + * to create an {@link Injector}. A Guice-based application is ultimately composed of little more + * than a set of {@code Module}s and some bootstrapping code. * - * <p>Your Module classes can use a more streamlined syntax by extending - * {@link AbstractModule} rather than implementing this interface directly. + * <p>Your Module classes can use a more streamlined syntax by extending {@link AbstractModule} + * rather than implementing this interface directly. * - * <p>In addition to the bindings configured via {@link #configure}, bindings - * will be created for all methods annotated with {@literal @}{@link Provides}. - * Use scope and binding annotations on these methods to configure the - * bindings. + * <p>In addition to the bindings configured via {@link #configure}, bindings will be created for + * all methods annotated with {@literal @}{@link Provides}. Use scope and binding annotations on + * these methods to configure the bindings. */ public interface Module { diff --git a/core/src/com/google/inject/OutOfScopeException.java b/core/src/com/google/inject/OutOfScopeException.java index 430fa237..7199b6b6 100644 --- a/core/src/com/google/inject/OutOfScopeException.java +++ b/core/src/com/google/inject/OutOfScopeException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,8 +17,8 @@ package com.google.inject; /** - * Thrown from {@link Provider#get} when an attempt is made to access a scoped - * object while the scope in question is not currently active. + * Thrown from {@link Provider#get} when an attempt is made to access a scoped object while the + * scope in question is not currently active. * * @author kevinb@google.com (Kevin Bourrillion) * @since 2.0 diff --git a/core/src/com/google/inject/PrivateBinder.java b/core/src/com/google/inject/PrivateBinder.java index 21a833f6..9e7fcd36 100644 --- a/core/src/com/google/inject/PrivateBinder.java +++ b/core/src/com/google/inject/PrivateBinder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,7 @@ import com.google.inject.binder.AnnotatedElementBuilder; /** * Returns a binder whose configuration information is hidden from its environment by default. See * {@link com.google.inject.PrivateModule PrivateModule} for details. - * + * * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 */ @@ -32,8 +32,8 @@ public interface PrivateBinder extends Binder { /** * Makes a binding for {@code type} available to the enclosing environment. Use {@link - * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a - * binding annotation. + * com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to + * expose {@code type} with a binding annotation. */ AnnotatedElementBuilder expose(Class<?> type); @@ -44,7 +44,9 @@ public interface PrivateBinder extends Binder { */ AnnotatedElementBuilder expose(TypeLiteral<?> type); + @Override PrivateBinder withSource(Object source); + @Override PrivateBinder skipSources(Class... classesToSkip); } diff --git a/core/src/com/google/inject/PrivateModule.java b/core/src/com/google/inject/PrivateModule.java index ba2f7223..e43e1f94 100644 --- a/core/src/com/google/inject/PrivateModule.java +++ b/core/src/com/google/inject/PrivateModule.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,7 +27,6 @@ import com.google.inject.spi.Message; import com.google.inject.spi.ProvisionListener; import com.google.inject.spi.TypeConverter; import com.google.inject.spi.TypeListener; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; @@ -37,14 +36,14 @@ import java.lang.reflect.Method; * This module may expose the bindings it creates and the bindings of the modules it installs. * * <p>A private module can be nested within a regular module or within another private module using - * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings, - * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you + * {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings, + * type converters, scopes, and interceptors from the surrounding ("parent") environment. When you * nest multiple private modules, the result is a tree of environments where the injector's * environment is the root. * * <p>Guice EDSL bindings can be exposed with {@link #expose(Class) expose()}. {@literal @}{@link - * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link - * Exposed} annotation: + * com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link Exposed} + * annotation: * * <pre> * public class FooBarBazModule extends PrivateModule { @@ -69,7 +68,7 @@ import java.lang.reflect.Method; * <p>Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent * injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the * root environment. Such bindings are shared among all environments in the tree. - * + * * <p>The scope of a binding is constrained to its environment. A singleton bound in a private * module will be unique to its environment. But a binding for the same type in a different private * module will yield a different instance. @@ -79,6 +78,7 @@ import java.lang.reflect.Method; * gets access to all bindings in the child environment. * * <p>To promote a just-in-time binding to an explicit binding, bind it: + * * <pre> * bind(FooImpl.class); * </pre> @@ -91,6 +91,7 @@ public abstract class PrivateModule implements Module { /** Like abstract module, the binder of the current private module */ private PrivateBinder binder; + @Override public final synchronized void configure(Binder binder) { checkState(this.binder == null, "Re-entry is not allowed."); @@ -134,155 +135,120 @@ public abstract class PrivateModule implements Module { // everything below is copied from AbstractModule - /** - * Returns the current binder. - */ + /** Returns the current binder. */ protected final PrivateBinder binder() { checkState(binder != null, "The binder can only be used inside configure()"); return binder; } - /** - * @see Binder#bindScope(Class, Scope) - */ + /** @see Binder#bindScope(Class, Scope) */ protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) { binder().bindScope(scopeAnnotation, scope); } - /** - * @see Binder#bind(Key) - */ + /** @see Binder#bind(Key) */ protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) { return binder().bind(key); } - /** - * @see Binder#bind(TypeLiteral) - */ + /** @see Binder#bind(TypeLiteral) */ protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) { return binder().bind(typeLiteral); } - /** - * @see Binder#bind(Class) - */ + /** @see Binder#bind(Class) */ protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) { return binder().bind(clazz); } - /** - * @see Binder#bindConstant() - */ + /** @see Binder#bindConstant() */ protected final AnnotatedConstantBindingBuilder bindConstant() { return binder().bindConstant(); } - /** - * @see Binder#install(Module) - */ + /** @see Binder#install(Module) */ protected final void install(Module module) { binder().install(module); } - /** - * @see Binder#addError(String, Object[]) - */ + /** @see Binder#addError(String, Object[]) */ protected final void addError(String message, Object... arguments) { binder().addError(message, arguments); } - /** - * @see Binder#addError(Throwable) - */ + /** @see Binder#addError(Throwable) */ protected final void addError(Throwable t) { binder().addError(t); } - /** - * @see Binder#addError(Message) - */ + /** @see Binder#addError(Message) */ protected final void addError(Message message) { binder().addError(message); } - /** - * @see Binder#requestInjection(Object) - */ + /** @see Binder#requestInjection(Object) */ protected final void requestInjection(Object instance) { binder().requestInjection(instance); } - /** - * @see Binder#requestStaticInjection(Class[]) - */ + /** @see Binder#requestStaticInjection(Class[]) */ protected final void requestStaticInjection(Class<?>... types) { binder().requestStaticInjection(types); } /*if[AOP]*/ /** - * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) + * @see Binder#bindInterceptor(com.google.inject.matcher.Matcher, + * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) */ - protected final void bindInterceptor(Matcher<? super Class<?>> classMatcher, + protected final void bindInterceptor( + Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors) { binder().bindInterceptor(classMatcher, methodMatcher, interceptors); } /*end[AOP]*/ - /** - * Instructs Guice to require a binding to the given key. - */ + /** Instructs Guice to require a binding to the given key. */ protected final void requireBinding(Key<?> key) { binder().getProvider(key); } - /** - * Instructs Guice to require a binding to the given type. - */ + /** Instructs Guice to require a binding to the given type. */ protected final void requireBinding(Class<?> type) { binder().getProvider(type); } - /** - * @see Binder#getProvider(Key) - */ + /** @see Binder#getProvider(Key) */ protected final <T> Provider<T> getProvider(Key<T> key) { return binder().getProvider(key); } - - /** - * @see Binder#getProvider(Class) - */ + + /** @see Binder#getProvider(Class) */ protected final <T> Provider<T> getProvider(Class<T> type) { return binder().getProvider(type); } /** - * @see Binder#convertToTypes(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeConverter) + * @see Binder#convertToTypes(com.google.inject.matcher.Matcher, + * com.google.inject.spi.TypeConverter) */ - protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter converter) { + protected final void convertToTypes( + Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) { binder().convertToTypes(typeMatcher, converter); } - /** - * @see Binder#currentStage() - */ + /** @see Binder#currentStage() */ protected final Stage currentStage() { return binder().currentStage(); } - /** - * @see Binder#getMembersInjector(Class) - */ + /** @see Binder#getMembersInjector(Class) */ protected <T> MembersInjector<T> getMembersInjector(Class<T> type) { return binder().getMembersInjector(type); } - /** - * @see Binder#getMembersInjector(TypeLiteral) - */ + /** @see Binder#getMembersInjector(TypeLiteral) */ protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) { return binder().getMembersInjector(type); } @@ -290,17 +256,16 @@ public abstract class PrivateModule implements Module { /** * @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener) */ - protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeListener listener) { + protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) { binder().bindListener(typeMatcher, listener); } - + /** * @see Binder#bindListener(Matcher, ProvisionListener...) * @since 4.0 */ - protected void bindListener(Matcher<? super Binding<?>> bindingMatcher, - ProvisionListener... listeners) { + protected void bindListener( + Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) { binder().bindListener(bindingMatcher, listeners); } } diff --git a/core/src/com/google/inject/ProvidedBy.java b/core/src/com/google/inject/ProvidedBy.java index 7ad12f78..bb924314 100644 --- a/core/src/com/google/inject/ProvidedBy.java +++ b/core/src/com/google/inject/ProvidedBy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,8 +31,6 @@ import java.lang.annotation.Target; @Target(TYPE) public @interface ProvidedBy { - /** - * The implementation type. - */ - Class<? extends Provider<?>> value(); + /** The implementation type. */ + Class<? extends javax.inject.Provider<?>> value(); } diff --git a/core/src/com/google/inject/Provider.java b/core/src/com/google/inject/Provider.java index 3295a2b0..4ce1e315 100644 --- a/core/src/com/google/inject/Provider.java +++ b/core/src/com/google/inject/Provider.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,35 +22,32 @@ package com.google.inject; * * <ul> * <li>When the default means for obtaining instances (an injectable or parameterless constructor) - * is insufficient for a particular binding, the module can specify a custom {@code Provider} - * instead, to control exactly how Guice creates or obtains instances for the binding. - * + * is insufficient for a particular binding, the module can specify a custom {@code Provider} + * instead, to control exactly how Guice creates or obtains instances for the binding. * <li>An implementation class may always choose to have a {@code Provider<T>} instance injected, - * rather than having a {@code T} injected directly. This may give you access to multiple - * instances, instances you wish to safely mutate and discard, instances which are out of scope - * (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or - * instances that will be initialized lazily. - * + * rather than having a {@code T} injected directly. This may give you access to multiple + * instances, instances you wish to safely mutate and discard, instances which are out of scope + * (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or + * instances that will be initialized lazily. * <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides - * when to delegate to the backing provider and when to provide the instance some other way. - * - * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests - * for a given key, via the {@link Injector#getProvider} methods. + * when to delegate to the backing provider and when to provide the instance some other way. + * <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests for + * a given key, via the {@link Injector#getProvider} methods. * </ul> * * @param <T> the type of object this provides - * * @author crazybob@google.com (Bob Lee) */ public interface Provider<T> extends javax.inject.Provider<T> { /** - * Provides an instance of {@code T}. Must never return {@code null}. + * Provides an instance of {@code T}. * * @throws OutOfScopeException when an attempt is made to access a scoped object while the scope * in question is not currently active * @throws ProvisionException if an instance cannot be provided. Such exceptions include messages * and throwables to describe why provision failed. */ + @Override T get(); } diff --git a/core/src/com/google/inject/Provides.java b/core/src/com/google/inject/Provides.java index c66a428a..ba8f72b2 100644 --- a/core/src/com/google/inject/Provides.java +++ b/core/src/com/google/inject/Provides.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,5 +30,7 @@ import java.lang.annotation.Target; * @author crazybob@google.com (Bob Lee) * @since 2.0 */ -@Documented @Target(METHOD) @Retention(RUNTIME) +@Documented +@Target(METHOD) +@Retention(RUNTIME) public @interface Provides {} diff --git a/core/src/com/google/inject/ProvisionException.java b/core/src/com/google/inject/ProvisionException.java index 3c590b99..0c132c5e 100644 --- a/core/src/com/google/inject/ProvisionException.java +++ b/core/src/com/google/inject/ProvisionException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,14 +19,14 @@ package com.google.inject; import static com.google.common.base.Preconditions.checkArgument; import com.google.common.collect.ImmutableSet; -import com.google.inject.internal.Errors; +import com.google.inject.internal.Messages; import com.google.inject.spi.Message; - import java.util.Collection; /** * Indicates that there was a runtime failure while providing an instance. * + * * @author kevinb@google.com (Kevin Bourrillion) * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 @@ -39,7 +39,7 @@ public final class ProvisionException extends RuntimeException { public ProvisionException(Iterable<Message> messages) { this.messages = ImmutableSet.copyOf(messages); checkArgument(!this.messages.isEmpty()); - initCause(Errors.getOnlyCause(this.messages)); + initCause(Messages.getOnlyCause(this.messages)); } public ProvisionException(String message, Throwable cause) { @@ -56,8 +56,9 @@ public final class ProvisionException extends RuntimeException { return messages; } - @Override public String getMessage() { - return Errors.format("Unable to provision, see the following errors", messages); + @Override + public String getMessage() { + return Messages.formatMessages("Unable to provision, see the following errors", messages); } private static final long serialVersionUID = 0; diff --git a/core/src/com/google/inject/Scope.java b/core/src/com/google/inject/Scope.java index 949270c8..331d9c34 100644 --- a/core/src/com/google/inject/Scope.java +++ b/core/src/com/google/inject/Scope.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,13 +17,11 @@ package com.google.inject; /** - * A scope is a level of visibility that instances provided by Guice may have. - * By default, an instance created by the {@link Injector} has <i>no scope</i>, - * meaning it has no state from the framework's perspective -- the - * {@code Injector} creates it, injects it once into the class that required it, - * and then immediately forgets it. Associating a scope with a particular - * binding allows the created instance to be "remembered" and possibly used - * again for other injections. + * A scope is a level of visibility that instances provided by Guice may have. By default, an + * instance created by the {@link Injector} has <i>no scope</i>, meaning it has no state from the + * framework's perspective -- the {@code Injector} creates it, injects it once into the class that + * required it, and then immediately forgets it. Associating a scope with a particular binding + * allows the created instance to be "remembered" and possibly used again for other injections. * * <p>An example of a scope is {@link Scopes#SINGLETON}. * @@ -32,28 +30,24 @@ package com.google.inject; public interface Scope { /** - * Scopes a provider. The returned provider returns objects from this scope. - * If an object does not exist in this scope, the provider can use the given - * unscoped provider to retrieve one. + * Scopes a provider. The returned provider returns objects from this scope. If an object does not + * exist in this scope, the provider can use the given unscoped provider to retrieve one. * - * <p>Scope implementations are strongly encouraged to override - * {@link Object#toString} in the returned provider and include the backing - * provider's {@code toString()} output. + * <p>Scope implementations are strongly encouraged to override {@link Object#toString} in the + * returned provider and include the backing provider's {@code toString()} output. * * @param key binding key - * @param unscoped locates an instance when one doesn't already exist in this - * scope. - * @return a new provider which only delegates to the given unscoped provider - * when an instance of the requested object doesn't already exist in this - * scope + * @param unscoped locates an instance when one doesn't already exist in this scope. + * @return a new provider which only delegates to the given unscoped provider when an instance of + * the requested object doesn't already exist in this scope */ public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped); /** - * A short but useful description of this scope. For comparison, the standard - * scopes that ship with guice use the descriptions - * {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and + * A short but useful description of this scope. For comparison, the standard scopes that ship + * with guice use the descriptions {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and * {@code "ServletScopes.REQUEST"}. */ + @Override String toString(); } diff --git a/core/src/com/google/inject/ScopeAnnotation.java b/core/src/com/google/inject/ScopeAnnotation.java index 8f869a09..c0b651a2 100644 --- a/core/src/com/google/inject/ScopeAnnotation.java +++ b/core/src/com/google/inject/ScopeAnnotation.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,9 +23,9 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * Annotates annotations which are used for scoping. Only one such annotation - * may apply to a single implementation class. You must also annotate scope - * annotations with {@code @Retention(RUNTIME)}. For example: + * Annotates annotations which are used for scoping. Only one such annotation may apply to a single + * implementation class. You must also annotate scope annotations with {@code @Retention(RUNTIME)}. + * For example: * * <pre> * {@code @}Retention(RUNTIME) diff --git a/core/src/com/google/inject/Scopes.java b/core/src/com/google/inject/Scopes.java index 6c893e52..20be1022 100644 --- a/core/src/com/google/inject/Scopes.java +++ b/core/src/com/google/inject/Scopes.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ import com.google.inject.internal.LinkedBindingImpl; import com.google.inject.internal.SingletonScope; import com.google.inject.spi.BindingScopingVisitor; import com.google.inject.spi.ExposedBinding; - import java.lang.annotation.Annotation; /** @@ -33,47 +32,51 @@ public class Scopes { private Scopes() {} - /** - * One instance per {@link Injector}. Also see {@code @}{@link Singleton}. - */ + /** One instance per {@link Injector}. Also see {@code @}{@link Singleton}. */ public static final Scope SINGLETON = new SingletonScope(); /** - * No scope; the same as not applying any scope at all. Each time the - * Injector obtains an instance of an object with "no scope", it injects this - * instance then immediately forgets it. When the next request for the same - * binding arrives it will need to obtain the instance over again. + * No scope; the same as not applying any scope at all. Each time the Injector obtains an instance + * of an object with "no scope", it injects this instance then immediately forgets it. When the + * next request for the same binding arrives it will need to obtain the instance over again. * - * <p>This exists only in case a class has been annotated with a scope - * annotation such as {@link Singleton @Singleton}, and you need to override - * this to "no scope" in your binding. + * <p>This exists only in case a class has been annotated with a scope annotation such as {@link + * Singleton @Singleton}, and you need to override this to "no scope" in your binding. * * @since 2.0 */ - public static final Scope NO_SCOPE = new Scope() { - public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { - return unscoped; - } - @Override public String toString() { - return "Scopes.NO_SCOPE"; - } - }; - - private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR - = new BindingScopingVisitor<Boolean>() { + public static final Scope NO_SCOPE = + new Scope() { + @Override + public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { + return unscoped; + } + + @Override + public String toString() { + return "Scopes.NO_SCOPE"; + } + }; + + private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR = + new BindingScopingVisitor<Boolean>() { + @Override public Boolean visitNoScoping() { return false; } + @Override public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) { return scopeAnnotation == Singleton.class || scopeAnnotation == javax.inject.Singleton.class; } + @Override public Boolean visitScope(Scope scope) { return scope == Scopes.SINGLETON; } + @Override public Boolean visitEagerSingleton() { return true; } @@ -101,8 +104,8 @@ public class Scopes { binding = injector.getBinding(linkedBinding.getLinkedKey()); continue; } - } else if(binding instanceof ExposedBinding) { - ExposedBinding<?> exposedBinding = (ExposedBinding)binding; + } else if (binding instanceof ExposedBinding) { + ExposedBinding<?> exposedBinding = (ExposedBinding) binding; Injector injector = exposedBinding.getPrivateElements().getInjector(); if (injector != null) { binding = injector.getBinding(exposedBinding.getKey()); @@ -115,7 +118,6 @@ public class Scopes { } /** - * Returns true if {@code binding} has the given scope. If the binding is a {@link * com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it * was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will @@ -126,26 +128,32 @@ public class Scopes { * @param scopeAnnotation scope annotation class * @since 4.0 */ - public static boolean isScoped(Binding<?> binding, final Scope scope, - final Class<? extends Annotation> scopeAnnotation) { + public static boolean isScoped( + Binding<?> binding, final Scope scope, final Class<? extends Annotation> scopeAnnotation) { do { - boolean matches = binding.acceptScopingVisitor(new BindingScopingVisitor<Boolean>() { - public Boolean visitNoScoping() { - return false; - } - - public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) { - return visitedAnnotation == scopeAnnotation; - } - - public Boolean visitScope(Scope visitedScope) { - return visitedScope == scope; - } - - public Boolean visitEagerSingleton() { - return false; - } - }); + boolean matches = + binding.acceptScopingVisitor( + new BindingScopingVisitor<Boolean>() { + @Override + public Boolean visitNoScoping() { + return false; + } + + @Override + public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) { + return visitedAnnotation == scopeAnnotation; + } + + @Override + public Boolean visitScope(Scope visitedScope) { + return visitedScope == scope; + } + + @Override + public Boolean visitEagerSingleton() { + return false; + } + }); if (matches) { return true; @@ -158,8 +166,8 @@ public class Scopes { binding = injector.getBinding(linkedBinding.getLinkedKey()); continue; } - } else if(binding instanceof ExposedBinding) { - ExposedBinding<?> exposedBinding = (ExposedBinding)binding; + } else if (binding instanceof ExposedBinding) { + ExposedBinding<?> exposedBinding = (ExposedBinding) binding; Injector injector = exposedBinding.getPrivateElements().getInjector(); if (injector != null) { binding = injector.getBinding(exposedBinding.getKey()); @@ -172,12 +180,11 @@ public class Scopes { } /** - * Returns true if the object is a proxy for a circular dependency, - * constructed by Guice because it encountered a circular dependency. Scope - * implementations should be careful to <b>not cache circular proxies</b>, - * because the proxies are not intended for general purpose use. (They are - * designed just to fulfill the immediate injection, not all injections. - * Caching them can lead to IllegalArgumentExceptions or ClassCastExceptions.) + * Returns true if the object is a proxy for a circular dependency, constructed by Guice because + * it encountered a circular dependency. Scope implementations should be careful to <b>not cache + * circular proxies</b>, because the proxies are not intended for general purpose use. (They are + * designed just to fulfill the immediate injection, not all injections. Caching them can lead to + * IllegalArgumentExceptions or ClassCastExceptions.) * * @since 4.0 */ diff --git a/core/src/com/google/inject/Singleton.java b/core/src/com/google/inject/Singleton.java index 0ea9a14d..59a2b44d 100644 --- a/core/src/com/google/inject/Singleton.java +++ b/core/src/com/google/inject/Singleton.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,12 +23,12 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; /** - * Apply this to implementation classes when you want only one instance - * (per {@link Injector}) to be reused for all injections for that binding. + * Apply this to implementation classes when you want only one instance (per {@link Injector}) to be + * reused for all injections for that binding. * * @author crazybob@google.com (Bob Lee) */ -@Target({ ElementType.TYPE, ElementType.METHOD }) +@Target({ElementType.TYPE, ElementType.METHOD}) @Retention(RUNTIME) @ScopeAnnotation public @interface Singleton {} diff --git a/core/src/com/google/inject/Stage.java b/core/src/com/google/inject/Stage.java index f9b4e357..19f256e0 100644 --- a/core/src/com/google/inject/Stage.java +++ b/core/src/com/google/inject/Stage.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,8 +26,8 @@ public enum Stage { /** * We're running in a tool (an IDE plugin for example). We need binding meta data but not a * functioning Injector. Do not inject members of instances. Do not load eager singletons. Do as - * little as possible so our tools run nice and snappy. Injectors created in this stage cannot - * be used to satisfy injections. + * little as possible so our tools run nice and snappy. Injectors created in this stage cannot be + * used to satisfy injections. */ TOOL, @@ -37,8 +37,6 @@ public enum Stage { */ DEVELOPMENT, - /** - * We want to catch errors as early as possible and take performance hits up front. - */ + /** We want to catch errors as early as possible and take performance hits up front. */ PRODUCTION } diff --git a/core/src/com/google/inject/TypeLiteral.java b/core/src/com/google/inject/TypeLiteral.java index d18087d2..0f928da5 100644 --- a/core/src/com/google/inject/TypeLiteral.java +++ b/core/src/com/google/inject/TypeLiteral.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import static com.google.inject.internal.MoreTypes.canonicalize; import com.google.common.collect.ImmutableList; import com.google.inject.internal.MoreTypes; import com.google.inject.util.Types; - import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.GenericArrayType; @@ -36,26 +35,25 @@ import java.lang.reflect.WildcardType; import java.util.List; /** - * Represents a generic type {@code T}. Java doesn't yet provide a way to - * represent generic types, so this class does. Forces clients to create a - * subclass of this class which enables retrieval the type information even at - * runtime. + * Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types, + * so this class does. Forces clients to create a subclass of this class which enables retrieval of + * the type information even at runtime. * - * <p>For example, to create a type literal for {@code List<String>}, you can - * create an empty anonymous inner class: + * <p>For example, to create a type literal for {@code List<String>}, you can create an empty + * anonymous inner class: * - * <p> - * {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};} + * <p>{@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};} * - * <p>Along with modeling generic types, this class can resolve type parameters. - * For example, to figure out what type {@code keySet()} returns on a {@code - * Map<Integer, String>}, use this code:<pre> {@code + * <p>Along with modeling generic types, this class can resolve type parameters. For example, to + * figure out what type {@code keySet()} returns on a {@code Map<Integer, String>}, use this code: * - * TypeLiteral<Map<Integer, String>> mapType - * = new TypeLiteral<Map<Integer, String>>() {}; - * TypeLiteral<?> keySetType - * = mapType.getReturnType(Map.class.getMethod("keySet")); - * System.out.println(keySetType); // prints "Set<Integer>"}</pre> + * <pre>{@code + * TypeLiteral<Map<Integer, String>> mapType + * = new TypeLiteral<Map<Integer, String>>() {}; + * TypeLiteral<?> keySetType + * = mapType.getReturnType(Map.class.getMethod("keySet")); + * System.out.println(keySetType); // prints "Set<Integer>" + * }</pre> * * @author crazybob@google.com (Bob Lee) * @author jessewilson@google.com (Jesse Wilson) @@ -67,12 +65,10 @@ public class TypeLiteral<T> { final int hashCode; /** - * Constructs a new type literal. Derives represented class from type - * parameter. + * Constructs a new type literal. Derives represented class from type parameter. * - * <p>Clients create an empty anonymous subclass. Doing so embeds the type - * parameter in the anonymous class's type hierarchy so we can reconstitute it - * at runtime despite erasure. + * <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the + * anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure. */ @SuppressWarnings("unchecked") protected TypeLiteral() { @@ -81,9 +77,7 @@ public class TypeLiteral<T> { this.hashCode = type.hashCode(); } - /** - * Unsafe. Constructs a type literal manually. - */ + /** Unsafe. Constructs a type literal manually. */ @SuppressWarnings("unchecked") TypeLiteral(Type type) { this.type = canonicalize(checkNotNull(type, "type")); @@ -104,32 +98,26 @@ public class TypeLiteral<T> { return canonicalize(parameterized.getActualTypeArguments()[0]); } - /** - * Gets type literal from super class's type parameter. - */ + /** Gets type literal from super class's type parameter. */ static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) { return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass)); } /** * Returns the raw (non-generic) type for this type. - * + * * @since 2.0 */ public final Class<? super T> getRawType() { return rawType; } - /** - * Gets underlying {@code Type} instance. - */ + /** Gets underlying {@code Type} instance. */ public final Type getType() { return type; } - /** - * Gets the type of this type's provider. - */ + /** Gets the type of this type's provider. */ @SuppressWarnings("unchecked") final TypeLiteral<Provider<T>> providerType() { // This cast is safe and wouldn't generate a warning if Type had a type @@ -137,34 +125,31 @@ public class TypeLiteral<T> { return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType())); } - @Override public final int hashCode() { + @Override + public final int hashCode() { return this.hashCode; } - @Override public final boolean equals(Object o) { - return o instanceof TypeLiteral<?> - && MoreTypes.equals(type, ((TypeLiteral) o).type); + @Override + public final boolean equals(Object o) { + return o instanceof TypeLiteral<?> && MoreTypes.equals(type, ((TypeLiteral) o).type); } - @Override public final String toString() { + @Override + public final String toString() { return MoreTypes.typeToString(type); } - /** - * Gets type literal for the given {@code Type} instance. - */ + /** Gets type literal for the given {@code Type} instance. */ public static TypeLiteral<?> get(Type type) { return new TypeLiteral<Object>(type); } - /** - * Gets type literal for the given {@code Class} instance. - */ + /** Gets type literal for the given {@code Class} instance. */ public static <T> TypeLiteral<T> get(Class<T> type) { return new TypeLiteral<T>(type); } - /** Returns an immutable list of the resolved types. */ private List<TypeLiteral<?>> resolveAll(Type[] types) { TypeLiteral<?>[] result = new TypeLiteral<?>[types.length]; @@ -174,9 +159,7 @@ public class TypeLiteral<T> { return ImmutableList.copyOf(result); } - /** - * Resolves known type parameters in {@code toResolve} and returns the result. - */ + /** Resolves known type parameters in {@code toResolve} and returns the result. */ TypeLiteral<?> resolve(Type toResolve) { return TypeLiteral.get(resolveType(toResolve)); } @@ -195,9 +178,7 @@ public class TypeLiteral<T> { GenericArrayType original = (GenericArrayType) toResolve; Type componentType = original.getGenericComponentType(); Type newComponentType = resolveType(componentType); - return componentType == newComponentType - ? original - : Types.arrayOf(newComponentType); + return componentType == newComponentType ? original : Types.arrayOf(newComponentType); } else if (toResolve instanceof ParameterizedType) { ParameterizedType original = (ParameterizedType) toResolve; @@ -254,8 +235,8 @@ public class TypeLiteral<T> { * @since 2.0 */ public TypeLiteral<?> getSupertype(Class<?> supertype) { - checkArgument(supertype.isAssignableFrom(rawType), - "%s is not a supertype of %s", supertype, this.type); + checkArgument( + supertype.isAssignableFrom(rawType), "%s is not a supertype of %s", supertype, this.type); return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype)); } @@ -266,8 +247,11 @@ public class TypeLiteral<T> { * @since 2.0 */ public TypeLiteral<?> getFieldType(Field field) { - checkArgument(field.getDeclaringClass().isAssignableFrom(rawType), - "%s is not defined by a supertype of %s", field, type); + checkArgument( + field.getDeclaringClass().isAssignableFrom(rawType), + "%s is not defined by a supertype of %s", + field, + type); return resolve(field.getGenericType()); } @@ -282,14 +266,20 @@ public class TypeLiteral<T> { if (methodOrConstructor instanceof Method) { Method method = (Method) methodOrConstructor; - checkArgument(method.getDeclaringClass().isAssignableFrom(rawType), - "%s is not defined by a supertype of %s", method, type); + checkArgument( + method.getDeclaringClass().isAssignableFrom(rawType), + "%s is not defined by a supertype of %s", + method, + type); genericParameterTypes = method.getGenericParameterTypes(); } else if (methodOrConstructor instanceof Constructor) { Constructor<?> constructor = (Constructor<?>) methodOrConstructor; - checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType), - "%s does not construct a supertype of %s", constructor, type); + checkArgument( + constructor.getDeclaringClass().isAssignableFrom(rawType), + "%s does not construct a supertype of %s", + constructor, + type); genericParameterTypes = constructor.getGenericParameterTypes(); } else { @@ -310,14 +300,20 @@ public class TypeLiteral<T> { if (methodOrConstructor instanceof Method) { Method method = (Method) methodOrConstructor; - checkArgument(method.getDeclaringClass().isAssignableFrom(rawType), - "%s is not defined by a supertype of %s", method, type); + checkArgument( + method.getDeclaringClass().isAssignableFrom(rawType), + "%s is not defined by a supertype of %s", + method, + type); genericExceptionTypes = method.getGenericExceptionTypes(); } else if (methodOrConstructor instanceof Constructor) { Constructor<?> constructor = (Constructor<?>) methodOrConstructor; - checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType), - "%s does not construct a supertype of %s", constructor, type); + checkArgument( + constructor.getDeclaringClass().isAssignableFrom(rawType), + "%s does not construct a supertype of %s", + constructor, + type); genericExceptionTypes = constructor.getGenericExceptionTypes(); } else { @@ -334,8 +330,11 @@ public class TypeLiteral<T> { * @since 2.0 */ public TypeLiteral<?> getReturnType(Method method) { - checkArgument(method.getDeclaringClass().isAssignableFrom(rawType), - "%s is not defined by a supertype of %s", method, type); + checkArgument( + method.getDeclaringClass().isAssignableFrom(rawType), + "%s is not defined by a supertype of %s", + method, + type); return resolve(method.getGenericReturnType()); } } diff --git a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java index 5b430c38..62ac3d4b 100644 --- a/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java +++ b/core/src/com/google/inject/binder/AnnotatedBindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,14 +25,9 @@ import java.lang.annotation.Annotation; */ public interface AnnotatedBindingBuilder<T> extends LinkedBindingBuilder<T> { - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ - LinkedBindingBuilder<T> annotatedWith( - Class<? extends Annotation> annotationType); + /** See the EDSL examples at {@link com.google.inject.Binder}. */ + LinkedBindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ LinkedBindingBuilder<T> annotatedWith(Annotation annotation); } diff --git a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java index 417027f3..fa57d781 100644 --- a/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java +++ b/core/src/com/google/inject/binder/AnnotatedConstantBindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,14 +25,9 @@ import java.lang.annotation.Annotation; */ public interface AnnotatedConstantBindingBuilder { - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ - ConstantBindingBuilder annotatedWith( - Class<? extends Annotation> annotationType); + /** See the EDSL examples at {@link com.google.inject.Binder}. */ + ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ ConstantBindingBuilder annotatedWith(Annotation annotation); } diff --git a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java index f6feddf4..04b22812 100644 --- a/core/src/com/google/inject/binder/AnnotatedElementBuilder.java +++ b/core/src/com/google/inject/binder/AnnotatedElementBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,13 +26,9 @@ import java.lang.annotation.Annotation; */ public interface AnnotatedElementBuilder { - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ void annotatedWith(Class<? extends Annotation> annotationType); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ void annotatedWith(Annotation annotation); } diff --git a/core/src/com/google/inject/binder/ConstantBindingBuilder.java b/core/src/com/google/inject/binder/ConstantBindingBuilder.java index 7ddbcf9d..cf1274bd 100644 --- a/core/src/com/google/inject/binder/ConstantBindingBuilder.java +++ b/core/src/com/google/inject/binder/ConstantBindingBuilder.java @@ -16,65 +16,43 @@ package com.google.inject.binder; -/** - * Binds to a constant value. - */ +/** Binds to a constant value. */ public interface ConstantBindingBuilder { - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(String value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(int value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(long value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(boolean value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(double value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(float value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(short value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(char value); /** * Binds constant to the given value. - * + * * @since 3.0 */ void to(byte value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ void to(Class<?> value); - /** - * Binds constant to the given value. - */ + /** Binds constant to the given value. */ <E extends Enum<E>> void to(E value); } diff --git a/core/src/com/google/inject/binder/LinkedBindingBuilder.java b/core/src/com/google/inject/binder/LinkedBindingBuilder.java index 99ea1854..219e145a 100644 --- a/core/src/com/google/inject/binder/LinkedBindingBuilder.java +++ b/core/src/com/google/inject/binder/LinkedBindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,6 @@ package com.google.inject.binder; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.TypeLiteral; - import java.lang.reflect.Constructor; /** @@ -29,19 +28,13 @@ import java.lang.reflect.Constructor; */ public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder { - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ ScopedBindingBuilder to(Class<? extends T> implementation); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ ScopedBindingBuilder to(TypeLiteral<? extends T> implementation); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ ScopedBindingBuilder to(Key<? extends T> targetKey); /** @@ -57,7 +50,7 @@ public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder { * @see com.google.inject.Injector#injectMembers */ ScopedBindingBuilder toProvider(Provider<? extends T> provider); - + /** * See the EDSL examples at {@link com.google.inject.Binder}. * @@ -66,34 +59,26 @@ public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder { */ ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ - ScopedBindingBuilder toProvider( - Class<? extends javax.inject.Provider<? extends T>> providerType); + /** See the EDSL examples at {@link com.google.inject.Binder}. */ + ScopedBindingBuilder toProvider(Class<? extends javax.inject.Provider<? extends T>> providerType); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ ScopedBindingBuilder toProvider( TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ - ScopedBindingBuilder toProvider( - Key<? extends javax.inject.Provider<? extends T>> providerKey); + /** See the EDSL examples at {@link com.google.inject.Binder}. */ + ScopedBindingBuilder toProvider(Key<? extends javax.inject.Provider<? extends T>> providerKey); /** * See the EDSL examples at {@link com.google.inject.Binder}. - * + * * @since 3.0 */ <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor); /** * See the EDSL examples at {@link com.google.inject.Binder}. - * + * * @since 3.0 */ <S extends T> ScopedBindingBuilder toConstructor( diff --git a/core/src/com/google/inject/binder/ScopedBindingBuilder.java b/core/src/com/google/inject/binder/ScopedBindingBuilder.java index ceb8497d..e907362d 100644 --- a/core/src/com/google/inject/binder/ScopedBindingBuilder.java +++ b/core/src/com/google/inject/binder/ScopedBindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,6 @@ package com.google.inject.binder; import com.google.inject.Scope; - import java.lang.annotation.Annotation; /** @@ -27,20 +26,15 @@ import java.lang.annotation.Annotation; */ public interface ScopedBindingBuilder { - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ void in(Class<? extends Annotation> scopeAnnotation); - /** - * See the EDSL examples at {@link com.google.inject.Binder}. - */ + /** See the EDSL examples at {@link com.google.inject.Binder}. */ void in(Scope scope); /** - * Instructs the {@link com.google.inject.Injector} to eagerly initialize this - * singleton-scoped binding upon creation. Useful for application - * initialization logic. See the EDSL examples at + * Instructs the {@link com.google.inject.Injector} to eagerly initialize this singleton-scoped + * binding upon creation. Useful for application initialization logic. See the EDSL examples at * {@link com.google.inject.Binder}. */ void asEagerSingleton(); diff --git a/core/src/com/google/inject/binder/package-info.java b/core/src/com/google/inject/binder/package-info.java index 57ed8754..14e701fa 100644 --- a/core/src/com/google/inject/binder/package-info.java +++ b/core/src/com/google/inject/binder/package-info.java @@ -14,8 +14,5 @@ * limitations under the License. */ -/** - * Interfaces which make up {@link com.google.inject.Binder}'s - * expression language. - */ -package com.google.inject.binder;
\ No newline at end of file +/** Interfaces which make up {@link com.google.inject.Binder}'s expression language. */ +package com.google.inject.binder; diff --git a/core/src/com/google/inject/internal/AbstractBindingBuilder.java b/core/src/com/google/inject/internal/AbstractBindingBuilder.java index e803b75a..6eb07e70 100644 --- a/core/src/com/google/inject/internal/AbstractBindingBuilder.java +++ b/core/src/com/google/inject/internal/AbstractBindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.inject.Key; import com.google.inject.Scope; import com.google.inject.spi.Element; import com.google.inject.spi.InstanceBinding; - import java.lang.annotation.Annotation; import java.util.List; @@ -35,14 +34,15 @@ import java.util.List; public abstract class AbstractBindingBuilder<T> { public static final String IMPLEMENTATION_ALREADY_SET = "Implementation is set more than once."; - public static final String SINGLE_INSTANCE_AND_SCOPE - = "Setting the scope is not permitted when binding to a single instance."; + public static final String SINGLE_INSTANCE_AND_SCOPE = + "Setting the scope is not permitted when binding to a single instance."; public static final String SCOPE_ALREADY_SET = "Scope is set more than once."; - public static final String BINDING_TO_NULL = "Binding to null instances is not allowed. " - + "Use toProvider(Providers.of(null)) if this is your intended behaviour."; + public static final String BINDING_TO_NULL = + "Binding to null instances is not allowed. " + + "Use toProvider(Providers.of(null)) if this is your intended behaviour."; public static final String CONSTANT_VALUE_ALREADY_SET = "Constant value is set more than once."; - public static final String ANNOTATION_ALREADY_SPECIFIED - = "More than one annotation is specified for this binding."; + public static final String ANNOTATION_ALREADY_SPECIFIED = + "More than one annotation is specified for this binding."; protected static final Key<?> NULL_KEY = Key.get(Void.class); @@ -55,7 +55,7 @@ public abstract class AbstractBindingBuilder<T> { this.binder = binder; this.elements = elements; this.position = elements.size(); - this.binding = new UntargettedBindingImpl<T>(source, key, Scoping.UNSCOPED); + this.binding = new UntargettedBindingImpl<>(source, key, Scoping.UNSCOPED); elements.add(position, this.binding); } @@ -73,16 +73,15 @@ public abstract class AbstractBindingBuilder<T> { protected BindingImpl<T> annotatedWithInternal(Class<? extends Annotation> annotationType) { checkNotNull(annotationType, "annotationType"); checkNotAnnotated(); - return setBinding(binding.withKey( - Key.get(this.binding.getKey().getTypeLiteral(), annotationType))); + return setBinding( + binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotationType))); } /** Sets the binding to a copy with the specified annotation on the bound key */ protected BindingImpl<T> annotatedWithInternal(Annotation annotation) { checkNotNull(annotation, "annotation"); checkNotAnnotated(); - return setBinding(binding.withKey( - Key.get(this.binding.getKey().getTypeLiteral(), annotation))); + return setBinding(binding.withKey(Key.get(this.binding.getKey().getTypeLiteral(), annotation))); } public void in(final Class<? extends Annotation> scopeAnnotation) { @@ -129,4 +128,4 @@ public abstract class AbstractBindingBuilder<T> { binder.addError(SCOPE_ALREADY_SET); } } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/AbstractBindingProcessor.java b/core/src/com/google/inject/internal/AbstractBindingProcessor.java index e1a0bba9..5d2640de 100644 --- a/core/src/com/google/inject/internal/AbstractBindingProcessor.java +++ b/core/src/com/google/inject/internal/AbstractBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,11 +30,9 @@ import com.google.inject.Stage; import com.google.inject.TypeLiteral; import com.google.inject.spi.DefaultBindingTargetVisitor; -import java.util.Set; - /** * Guarantees that processing of Binding elements happens in a sane way. - * + * * @author sameb@google.com (Sam Berlin) */ abstract class AbstractBindingProcessor extends AbstractProcessor { @@ -42,21 +40,22 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { // It's unfortunate that we have to maintain a blacklist of specific // classes, but we can't easily block the whole package because of // all our unit tests. - private static final Set<Class<?>> FORBIDDEN_TYPES = ImmutableSet.<Class<?>>of( - AbstractModule.class, - Binder.class, - Binding.class, - Injector.class, - Key.class, - MembersInjector.class, - Module.class, - Provider.class, - Scope.class, - Stage.class, - TypeLiteral.class); - + private static final ImmutableSet<Class<?>> FORBIDDEN_TYPES = + ImmutableSet.<Class<?>>of( + AbstractModule.class, + Binder.class, + Binding.class, + Injector.class, + Key.class, + MembersInjector.class, + Module.class, + Provider.class, + Scope.class, + Stage.class, + TypeLiteral.class); + protected final ProcessedBindingData bindingData; - + AbstractBindingProcessor(Errors errors, ProcessedBindingData bindingData) { super(errors); this.bindingData = bindingData; @@ -66,7 +65,7 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { InjectorImpl injector, Key<T> key, Object source) { return new UntargettedBindingImpl<T>(injector, key, source); } - + protected void putBinding(BindingImpl<?> binding) { Key<?> key = binding.getKey(); @@ -81,11 +80,11 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { // If it failed because of an explicit duplicate binding... if (injector.state.getExplicitBinding(key) != null) { try { - if(!isOkayDuplicate(original, binding, injector.state)) { + if (!isOkayDuplicate(original, binding, injector.state)) { errors.bindingAlreadySet(key, original.getSource()); return; } - } catch(Throwable t) { + } catch (Throwable t) { errors.errorCheckingDuplicateBinding(key, original.getSource(), t); return; } @@ -103,8 +102,8 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { } /** - * We tolerate duplicate bindings if one exposes the other or if the two bindings - * are considered duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}. + * We tolerate duplicate bindings if one exposes the other or if the two bindings are considered + * duplicates (see {@link Bindings#areDuplicates(BindingImpl, BindingImpl)}. * * @param original the binding in the parent injector (candidate for an exposing binding) * @param binding the binding to check (candidate for the exposed binding) @@ -115,46 +114,63 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector(); return (exposedFrom == binding.getInjector()); } else { - original = (BindingImpl<?>)state.getExplicitBindingsThisLevel().get(binding.getKey()); + original = (BindingImpl<?>) state.getExplicitBindingsThisLevel().get(binding.getKey()); // If no original at this level, the original was on a parent, and we don't // allow deduplication between parents & children. - if(original == null) { + if (original == null) { return false; } else { return original.equals(binding); } } } - + private <T> void validateKey(Object source, Key<T> key) { Annotations.checkForMisplacedScopeAnnotations( key.getTypeLiteral().getRawType(), source, errors); } - - /** - * Processor for visiting bindings. Each overriden method that wants to - * actually process the binding should call prepareBinding first. + + /** + * Processor for visiting bindings. Each overriden method that wants to actually process the + * binding should call prepareBinding first. */ abstract class Processor<T, V> extends DefaultBindingTargetVisitor<T, V> { final Object source; final Key<T> key; final Class<? super T> rawType; Scoping scoping; - + Processor(BindingImpl<T> binding) { source = binding.getSource(); key = binding.getKey(); rawType = key.getTypeLiteral().getRawType(); scoping = binding.getScoping(); } - - protected void prepareBinding() { + + protected void prepareBinding() { validateKey(source, key); scoping = Scoping.makeInjectable(scoping, injector, errors); } - protected void scheduleInitialization(final BindingImpl<?> binding) { - bindingData.addUninitializedBinding(new Runnable() { + /** + * Schedule initialization of this binding to occur immediately after all bindings have been + * initialially processed. + */ + protected void scheduleInitialization(BindingImpl<?> binding) { + bindingData.addUninitializedBinding(asRunnable(binding)); + } + + /** + * Schedule initialization for this binding to occur after all other static initialization of + * bindings. + */ + protected void scheduleDelayedInitialization(BindingImpl<?> binding) { + bindingData.addDelayedUninitializedBinding(asRunnable(binding)); + } + + private Runnable asRunnable(final BindingImpl<?> binding) { + return new Runnable() { + @Override public void run() { try { binding.getInjector().initializeBinding(binding, errors.withSource(source)); @@ -162,7 +178,7 @@ abstract class AbstractBindingProcessor extends AbstractProcessor { errors.merge(e.getErrors()); } } - }); + }; } } } diff --git a/core/src/com/google/inject/internal/AbstractProcessor.java b/core/src/com/google/inject/internal/AbstractProcessor.java index 2697a99c..6132dd36 100644 --- a/core/src/com/google/inject/internal/AbstractProcessor.java +++ b/core/src/com/google/inject/internal/AbstractProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,16 +18,14 @@ package com.google.inject.internal; import com.google.inject.spi.DefaultElementVisitor; import com.google.inject.spi.Element; - import java.util.Iterator; import java.util.List; /** * Abstract base class for creating an injector from module elements. * - * <p>Extending classes must return {@code true} from any overridden - * {@code visit*()} methods, in order for the element processor to remove the - * handled element. + * <p>Extending classes must return {@code true} from any overridden {@code visit*()} methods, in + * order for the element processor to remove the handled element. * * @author jessewilson@google.com (Jesse Wilson) */ @@ -63,7 +61,7 @@ abstract class AbstractProcessor extends DefaultElementVisitor<Boolean> { this.injector = null; } } - + @Override protected Boolean visitOther(Element element) { return false; diff --git a/core/src/com/google/inject/internal/Annotations.java b/core/src/com/google/inject/internal/Annotations.java index 4c994a95..c8159732 100644 --- a/core/src/com/google/inject/internal/Annotations.java +++ b/core/src/com/google/inject/internal/Annotations.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +16,8 @@ package com.google.inject.internal; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + import com.google.common.base.Function; import com.google.common.base.Joiner; import com.google.common.base.Joiner.MapJoiner; @@ -32,7 +34,6 @@ import com.google.inject.TypeLiteral; import com.google.inject.internal.util.Classes; import com.google.inject.name.Named; import com.google.inject.name.Names; - import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -43,7 +44,6 @@ import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Collection; import java.util.Map; - import javax.inject.Qualifier; /** @@ -53,9 +53,7 @@ import javax.inject.Qualifier; */ public class Annotations { - /** - * Returns {@code true} if the given annotation type has no attributes. - */ + /** Returns {@code true} if the given annotation type has no attributes. */ public static boolean isMarker(Class<? extends Annotation> annotationType) { return annotationType.getDeclaredMethods().length == 0; } @@ -72,13 +70,15 @@ public class Annotations { } private static final LoadingCache<Class<? extends Annotation>, Annotation> cache = - CacheBuilder.newBuilder().weakKeys().build( - new CacheLoader<Class<? extends Annotation>, Annotation>() { - @Override - public Annotation load(Class<? extends Annotation> input) { - return generateAnnotationImpl(input); - } - }); + CacheBuilder.newBuilder() + .weakKeys() + .build( + new CacheLoader<Class<? extends Annotation>, Annotation>() { + @Override + public Annotation load(Class<? extends Annotation> input) { + return generateAnnotationImpl(input); + } + }); /** * Generates an Annotation for the annotation class. Requires that the annotation is all @@ -87,31 +87,32 @@ public class Annotations { public static <T extends Annotation> T generateAnnotation(Class<T> annotationType) { Preconditions.checkState( isAllDefaultMethods(annotationType), "%s is not all default methods", annotationType); - return (T)cache.getUnchecked(annotationType); + return (T) cache.getUnchecked(annotationType); } private static <T extends Annotation> T generateAnnotationImpl(final Class<T> annotationType) { final Map<String, Object> members = resolveMembers(annotationType); - return annotationType.cast(Proxy.newProxyInstance( - annotationType.getClassLoader(), - new Class<?>[] { annotationType }, - new InvocationHandler() { - @Override - public Object invoke(Object proxy, Method method, Object[] args) throws Exception { - String name = method.getName(); - if (name.equals("annotationType")) { - return annotationType; - } else if (name.equals("toString")) { - return annotationToString(annotationType, members); - } else if (name.equals("hashCode")) { - return annotationHashCode(annotationType, members); - } else if (name.equals("equals")) { - return annotationEquals(annotationType, members, args[0]); - } else { - return members.get(name); - } - } - })); + return annotationType.cast( + Proxy.newProxyInstance( + annotationType.getClassLoader(), + new Class<?>[] {annotationType}, + new InvocationHandler() { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Exception { + String name = method.getName(); + if (name.equals("annotationType")) { + return annotationType; + } else if (name.equals("toString")) { + return annotationToString(annotationType, members); + } else if (name.equals("hashCode")) { + return annotationHashCode(annotationType, members); + } else if (name.equals("equals")) { + return annotationEquals(annotationType, members, args[0]); + } else { + return members.get(name); + } + } + })); } private static ImmutableMap<String, Object> resolveMembers( @@ -124,8 +125,9 @@ public class Annotations { } /** Implements {@link Annotation#equals}. */ - private static boolean annotationEquals(Class<? extends Annotation> type, - Map<String, Object> members, Object other) throws Exception { + private static boolean annotationEquals( + Class<? extends Annotation> type, Map<String, Object> members, Object other) + throws Exception { if (!type.isInstance(other)) { return false; } @@ -140,8 +142,8 @@ public class Annotations { } /** Implements {@link Annotation#hashCode}. */ - private static int annotationHashCode(Class<? extends Annotation> type, - Map<String, Object> members) throws Exception { + private static int annotationHashCode( + Class<? extends Annotation> type, Map<String, Object> members) throws Exception { int result = 0; for (Method method : type.getDeclaredMethods()) { String name = method.getName(); @@ -153,25 +155,24 @@ public class Annotations { private static final MapJoiner JOINER = Joiner.on(", ").withKeyValueSeparator("="); - private static final Function<Object, String> DEEP_TO_STRING_FN = new Function<Object, String>() { - @Override - public String apply(Object arg) { - String s = Arrays.deepToString(new Object[] {arg}); - return s.substring(1, s.length() - 1); // cut off brackets - } - }; + private static final Function<Object, String> DEEP_TO_STRING_FN = + new Function<Object, String>() { + @Override + public String apply(Object arg) { + String s = Arrays.deepToString(new Object[] {arg}); + return s.substring(1, s.length() - 1); // cut off brackets + } + }; /** Implements {@link Annotation#toString}. */ - private static String annotationToString(Class<? extends Annotation> type, - Map<String, Object> members) throws Exception { + private static String annotationToString( + Class<? extends Annotation> type, Map<String, Object> members) throws Exception { StringBuilder sb = new StringBuilder().append("@").append(type.getName()).append("("); JOINER.appendTo(sb, Maps.transformValues(members, DEEP_TO_STRING_FN)); return sb.append(")").toString(); } - /** - * Returns true if the given annotation is retained at runtime. - */ + /** Returns true if the given annotation is retained at runtime. */ public static boolean isRetainedAtRuntime(Class<? extends Annotation> annotationType) { Retention retention = annotationType.getAnnotation(Retention.class); return retention != null && retention.value() == RetentionPolicy.RUNTIME; @@ -184,7 +185,8 @@ public class Annotations { } /** Returns the scoping annotation, or null if there isn't one. */ - public static Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) { + public static Class<? extends Annotation> findScopeAnnotation( + Errors errors, Annotation[] annotations) { Class<? extends Annotation> found = null; for (Annotation annotation : annotations) { @@ -212,53 +214,77 @@ public class Annotations { return false; } + private static final boolean QUOTE_MEMBER_VALUES = determineWhetherToQuote(); + /** - * Checks for the presence of annotations. Caches results because Android doesn't. + * Returns {@code value}, quoted if annotation implementations quote their member values. In Java + * 9, annotations quote their string members. */ + public static String memberValueString(String value) { + return QUOTE_MEMBER_VALUES ? "\"" + value + "\"" : value; + } + + @Retention(RUNTIME) + private @interface TestAnnotation { + String value(); + } + + @TestAnnotation("determineWhetherToQuote") + private static boolean determineWhetherToQuote() { + try { + String annotation = + Annotations.class + .getDeclaredMethod("determineWhetherToQuote") + .getAnnotation(TestAnnotation.class) + .toString(); + return annotation.contains("\"determineWhetherToQuote\""); + } catch (NoSuchMethodException e) { + throw new AssertionError(e); + } + } + + /** Checks for the presence of annotations. Caches results because Android doesn't. */ static class AnnotationChecker { private final Collection<Class<? extends Annotation>> annotationTypes; /** Returns true if the given class has one of the desired annotations. */ private CacheLoader<Class<? extends Annotation>, Boolean> hasAnnotations = new CacheLoader<Class<? extends Annotation>, Boolean>() { - public Boolean load(Class<? extends Annotation> annotationType) { - for (Annotation annotation : annotationType.getAnnotations()) { - if (annotationTypes.contains(annotation.annotationType())) { - return true; + @Override + public Boolean load(Class<? extends Annotation> annotationType) { + for (Annotation annotation : annotationType.getAnnotations()) { + if (annotationTypes.contains(annotation.annotationType())) { + return true; + } + } + return false; } - } - return false; - } - }; + }; - final LoadingCache<Class<? extends Annotation>, Boolean> cache = CacheBuilder.newBuilder().weakKeys() - .build(hasAnnotations); + final LoadingCache<Class<? extends Annotation>, Boolean> cache = + CacheBuilder.newBuilder().weakKeys().build(hasAnnotations); - /** - * Constructs a new checker that looks for annotations of the given types. - */ + /** Constructs a new checker that looks for annotations of the given types. */ AnnotationChecker(Collection<Class<? extends Annotation>> annotationTypes) { this.annotationTypes = annotationTypes; } - /** - * Returns true if the given type has one of the desired annotations. - */ + /** Returns true if the given type has one of the desired annotations. */ boolean hasAnnotations(Class<? extends Annotation> annotated) { return cache.getUnchecked(annotated); } } - private static final AnnotationChecker scopeChecker = new AnnotationChecker( - Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class)); + private static final AnnotationChecker scopeChecker = + new AnnotationChecker(Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class)); public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) { return scopeChecker.hasAnnotations(annotationType); } /** - * Adds an error if there is a misplaced annotations on {@code type}. Scoping - * annotations are not allowed on abstract classes or interfaces. + * Adds an error if there is a misplaced annotations on {@code type}. Scoping annotations are not + * allowed on abstract classes or interfaces. */ public static void checkForMisplacedScopeAnnotations( Class<?> type, Object source, Errors errors) { @@ -274,18 +300,20 @@ public class Annotations { } } + // NOTE: getKey/findBindingAnnotation are used by Gin which is abandoned. So changing this API + // will prevent Gin users from upgrading Guice version. + /** Gets a key for the given type, member and annotations. */ - public static Key<?> getKey(TypeLiteral<?> type, Member member, Annotation[] annotations, - Errors errors) throws ErrorsException { + public static Key<?> getKey( + TypeLiteral<?> type, Member member, Annotation[] annotations, Errors errors) + throws ErrorsException { int numErrorsBefore = errors.size(); Annotation found = findBindingAnnotation(errors, member, annotations); errors.throwIfNewErrors(numErrorsBefore); return found == null ? Key.get(type) : Key.get(type, found); } - /** - * Returns the binding annotation on {@code member}, or null if there isn't one. - */ + /** Returns the binding annotation on {@code member}, or null if there isn't one. */ public static Annotation findBindingAnnotation( Errors errors, Member member, Annotation[] annotations) { Annotation found = null; @@ -304,23 +332,21 @@ public class Annotations { return found; } - private static final AnnotationChecker bindingAnnotationChecker = new AnnotationChecker( - Arrays.asList(BindingAnnotation.class, Qualifier.class)); + private static final AnnotationChecker bindingAnnotationChecker = + new AnnotationChecker(Arrays.asList(BindingAnnotation.class, Qualifier.class)); - /** - * Returns true if annotations of the specified type are binding annotations. - */ + /** Returns true if annotations of the specified type are binding annotations. */ public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) { return bindingAnnotationChecker.hasAnnotations(annotationType); } /** * If the annotation is an instance of {@code javax.inject.Named}, canonicalizes to - * com.google.guice.name.Named. Returns the given annotation otherwise. + * com.google.guice.name.Named. Returns the given annotation otherwise. */ public static Annotation canonicalizeIfNamed(Annotation annotation) { - if(annotation instanceof javax.inject.Named) { - return Names.named(((javax.inject.Named)annotation).value()); + if (annotation instanceof javax.inject.Named) { + return Names.named(((javax.inject.Named) annotation).value()); } else { return annotation; } @@ -338,4 +364,22 @@ public class Annotations { return annotationType; } } + + /** + * Returns the name the binding should use. This is based on the annotation. If the annotation has + * an instance and is not a marker annotation, we ask the annotation for its toString. If it was a + * marker annotation or just an annotation type, we use the annotation's name. Otherwise, the name + * is the empty string. + */ + public static String nameOf(Key<?> key) { + Annotation annotation = key.getAnnotation(); + Class<? extends Annotation> annotationType = key.getAnnotationType(); + if (annotation != null && !isMarker(annotationType)) { + return key.getAnnotation().toString(); + } else if (key.getAnnotationType() != null) { + return "@" + key.getAnnotationType().getName(); + } else { + return ""; + } + } } diff --git a/core/src/com/google/inject/internal/BindingBuilder.java b/core/src/com/google/inject/internal/BindingBuilder.java index 36c31ffa..100137e1 100644 --- a/core/src/com/google/inject/internal/BindingBuilder.java +++ b/core/src/com/google/inject/internal/BindingBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,6 @@ import com.google.inject.binder.ScopedBindingBuilder; import com.google.inject.spi.Element; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.Message; - import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.util.List; @@ -47,33 +46,39 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T> super(binder, elements, source, key); } + @Override public BindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType) { annotatedWithInternal(annotationType); return this; } + @Override public BindingBuilder<T> annotatedWith(Annotation annotation) { annotatedWithInternal(annotation); return this; } + @Override public BindingBuilder<T> to(Class<? extends T> implementation) { return to(Key.get(implementation)); } + @Override public BindingBuilder<T> to(TypeLiteral<? extends T> implementation) { return to(Key.get(implementation)); } + @Override public BindingBuilder<T> to(Key<? extends T> linkedKey) { checkNotNull(linkedKey, "linkedKey"); checkNotTargetted(); BindingImpl<T> base = getBinding(); - setBinding(new LinkedBindingImpl<T>( - base.getSource(), base.getKey(), base.getScoping(), linkedKey)); + setBinding( + new LinkedBindingImpl<T>(base.getSource(), base.getKey(), base.getScoping(), linkedKey)); return this; } + @Override public void toInstance(T instance) { checkNotTargetted(); @@ -92,14 +97,17 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T> } BindingImpl<T> base = getBinding(); - setBinding(new InstanceBindingImpl<T>( - base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance)); + setBinding( + new InstanceBindingImpl<T>( + base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance)); } + @Override public BindingBuilder<T> toProvider(Provider<? extends T> provider) { return toProvider((javax.inject.Provider<T>) provider); } + @Override public BindingBuilder<T> toProvider(javax.inject.Provider<? extends T> provider) { checkNotNull(provider, "provider"); checkNotTargetted(); @@ -114,38 +122,45 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T> } BindingImpl<T> base = getBinding(); - setBinding(new ProviderInstanceBindingImpl<T>( - base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider)); + setBinding( + new ProviderInstanceBindingImpl<T>( + base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider)); return this; } + @Override public BindingBuilder<T> toProvider( Class<? extends javax.inject.Provider<? extends T>> providerType) { return toProvider(Key.get(providerType)); } + @Override public BindingBuilder<T> toProvider( TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType) { return toProvider(Key.get(providerType)); } + @Override public BindingBuilder<T> toProvider( Key<? extends javax.inject.Provider<? extends T>> providerKey) { checkNotNull(providerKey, "providerKey"); checkNotTargetted(); BindingImpl<T> base = getBinding(); - setBinding(new LinkedProviderBindingImpl<T>( - base.getSource(), base.getKey(), base.getScoping(), providerKey)); + setBinding( + new LinkedProviderBindingImpl<T>( + base.getSource(), base.getKey(), base.getScoping(), providerKey)); return this; } + @Override public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor) { return toConstructor(constructor, TypeLiteral.get(constructor.getDeclaringClass())); } - public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor, - TypeLiteral<? extends S> type) { + @Override + public <S extends T> ScopedBindingBuilder toConstructor( + Constructor<S> constructor, TypeLiteral<? extends S> type) { checkNotNull(constructor, "constructor"); checkNotNull(type, "type"); checkNotTargetted(); @@ -162,16 +177,22 @@ public class BindingBuilder<T> extends AbstractBindingBuilder<T> try { InjectionPoint constructorPoint = InjectionPoint.forConstructor(constructor, type); - setBinding(new ConstructorBindingImpl<T>(base.getKey(), base.getSource(), base.getScoping(), - constructorPoint, injectionPoints)); + setBinding( + new ConstructorBindingImpl<T>( + base.getKey(), + base.getSource(), + base.getScoping(), + constructorPoint, + injectionPoints)); } catch (ConfigurationException e) { copyErrorsToBinder(e); } return this; } - - @Override public String toString() { + + @Override + public String toString() { return "BindingBuilder<" + getBinding().getKey().getTypeLiteral() + ">"; } diff --git a/core/src/com/google/inject/internal/BindingImpl.java b/core/src/com/google/inject/internal/BindingImpl.java index 3228e3d1..42592962 100644 --- a/core/src/com/google/inject/internal/BindingImpl.java +++ b/core/src/com/google/inject/internal/BindingImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ package com.google.inject.internal; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.inject.Binding; import com.google.inject.Key; import com.google.inject.Provider; @@ -24,9 +24,7 @@ import com.google.inject.spi.BindingScopingVisitor; import com.google.inject.spi.ElementVisitor; import com.google.inject.spi.InstanceBinding; -/** - * @author crazybob@google.com (Bob Lee) - */ +/** @author crazybob@google.com (Bob Lee) */ public abstract class BindingImpl<T> implements Binding<T> { private final InjectorImpl injector; @@ -35,8 +33,12 @@ public abstract class BindingImpl<T> implements Binding<T> { private final Scoping scoping; private final InternalFactory<? extends T> internalFactory; - public BindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> internalFactory, Scoping scoping) { + public BindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping) { this.injector = injector; this.key = key; this.source = source; @@ -52,16 +54,19 @@ public abstract class BindingImpl<T> implements Binding<T> { this.scoping = scoping; } + @Override public Key<T> getKey() { return key; } + @Override public Object getSource() { return source; } private volatile Provider<T> provider; + @Override public Provider<T> getProvider() { if (provider == null) { if (injector == null) { @@ -82,17 +87,19 @@ public abstract class BindingImpl<T> implements Binding<T> { } /** - * Is this a constant binding? This returns true for constant bindings as - * well as toInstance() bindings. + * Is this a constant binding? This returns true for constant bindings as well as toInstance() + * bindings. */ public boolean isConstant() { return this instanceof InstanceBinding; } + @Override public <V> V acceptVisitor(ElementVisitor<V> visitor) { return visitor.visit(this); } + @Override public <V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor) { return scoping.acceptVisitor(visitor); } @@ -104,9 +111,10 @@ public abstract class BindingImpl<T> implements Binding<T> { protected BindingImpl<T> withKey(Key<T> key) { throw new AssertionError(); } - - @Override public String toString() { - return Objects.toStringHelper(Binding.class) + + @Override + public String toString() { + return MoreObjects.toStringHelper(Binding.class) .add("key", key) .add("scope", scoping) .add("source", source) diff --git a/core/src/com/google/inject/internal/BindingProcessor.java b/core/src/com/google/inject/internal/BindingProcessor.java index b3c869e3..e9c52b4c 100644 --- a/core/src/com/google/inject/internal/BindingProcessor.java +++ b/core/src/com/google/inject/internal/BindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,6 @@ import com.google.inject.spi.ProviderBinding; import com.google.inject.spi.ProviderInstanceBinding; import com.google.inject.spi.ProviderKeyBinding; import com.google.inject.spi.UntargettedBinding; - import java.util.Set; /** @@ -49,7 +48,8 @@ final class BindingProcessor extends AbstractBindingProcessor { this.initializer = initializer; } - @Override public <T> Boolean visit(Binding<T> command) { + @Override + public <T> Boolean visit(Binding<T> command) { Class<?> rawType = command.getKey().getTypeLiteral().getRawType(); if (Void.class.equals(rawType)) { if (command instanceof ProviderInstanceBinding @@ -61,127 +61,183 @@ final class BindingProcessor extends AbstractBindingProcessor { } return true; } - + if (rawType == Provider.class) { errors.bindingToProvider(); return true; } - - return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)command) { - @Override - public Boolean visit(ConstructorBinding<? extends T> binding) { - prepareBinding(); - try { - ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key, - binding.getConstructor(), source, scoping, errors, false, false); - scheduleInitialization(onInjector); - putBinding(onInjector); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); - putBinding(invalidBinding(injector, key, source)); - } - return true; - } - @Override - public Boolean visit(InstanceBinding<? extends T> binding) { - prepareBinding(); - Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); - T instance = binding.getInstance(); - @SuppressWarnings("unchecked") // safe to cast to binding<T> because - // the processor was constructed w/ it - Initializable<T> ref = initializer.requestInjection( - injector, instance, (Binding<T>) binding, source, injectionPoints); - ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref); - InternalFactory<? extends T> scopedFactory - = Scoping.scope(key, injector, factory, source, scoping); - putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints, - instance)); - return true; - } + return command.acceptTargetVisitor( + new Processor<T, Boolean>((BindingImpl<T>) command) { + @Override + public Boolean visit(ConstructorBinding<? extends T> binding) { + prepareBinding(); + try { + ConstructorBindingImpl<T> onInjector = + ConstructorBindingImpl.create( + injector, + key, + binding.getConstructor(), + source, + scoping, + errors, + false, + false); + scheduleInitialization(onInjector); + putBinding(onInjector); + } catch (ErrorsException e) { + errors.merge(e.getErrors()); + putBinding(invalidBinding(injector, key, source)); + } + return true; + } - @Override - public Boolean visit(ProviderInstanceBinding<? extends T> binding) { - prepareBinding(); - javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider(); - Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); - Initializable<? extends javax.inject.Provider<? extends T>> initializable = - initializer.<javax.inject.Provider<? extends T>>requestInjection( - injector, provider, null, source, injectionPoints); - // always visited with Binding<T> - @SuppressWarnings("unchecked") - InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>( - initializable, source, - injector.provisionListenerStore.get((ProviderInstanceBinding<T>)binding)); - InternalFactory<? extends T> scopedFactory - = Scoping.scope(key, injector, factory, source, scoping); - putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping, - provider, injectionPoints)); - return true; - } + @Override + public Boolean visit(InstanceBinding<? extends T> binding) { + prepareBinding(); + Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); + T instance = binding.getInstance(); + @SuppressWarnings("unchecked") // safe to cast to binding<T> because + // the processor was constructed w/ it + Initializable<T> ref = + initializer.requestInjection( + injector, instance, (Binding<T>) binding, source, injectionPoints); + ConstantFactory<? extends T> factory = new ConstantFactory<>(ref); + InternalFactory<? extends T> scopedFactory = + Scoping.scope(key, injector, factory, source, scoping); + putBinding( + new InstanceBindingImpl<T>( + injector, key, source, scopedFactory, injectionPoints, instance)); + return true; + } - @Override - public Boolean visit(ProviderKeyBinding<? extends T> binding) { - prepareBinding(); - Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey(); - // always visited with Binding<T> - @SuppressWarnings("unchecked") - BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>( - injector, providerKey, source, - injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding)); - bindingData.addCreationListener(boundProviderFactory); - InternalFactory<? extends T> scopedFactory = Scoping.scope( - key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping); - putBinding(new LinkedProviderBindingImpl<T>( - injector, key, source, scopedFactory, scoping, providerKey)); - return true; - } + @Override + public Boolean visit(ProviderInstanceBinding<? extends T> binding) { + prepareBinding(); + javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider(); + if (provider instanceof InternalProviderInstanceBindingImpl.Factory) { + @SuppressWarnings("unchecked") + InternalProviderInstanceBindingImpl.Factory<T> asProviderMethod = + (InternalProviderInstanceBindingImpl.Factory<T>) provider; + return visitInternalProviderInstanceBindingFactory(asProviderMethod); + } + Set<InjectionPoint> injectionPoints = binding.getInjectionPoints(); + Initializable<? extends javax.inject.Provider<? extends T>> initializable = + initializer.<javax.inject.Provider<? extends T>>requestInjection( + injector, provider, null, source, injectionPoints); + // always visited with Binding<T> + @SuppressWarnings("unchecked") + InternalFactory<T> factory = + new InternalFactoryToInitializableAdapter<T>( + initializable, + source, + injector.provisionListenerStore.get((ProviderInstanceBinding<T>) binding)); + InternalFactory<? extends T> scopedFactory = + Scoping.scope(key, injector, factory, source, scoping); + putBinding( + new ProviderInstanceBindingImpl<T>( + injector, key, source, scopedFactory, scoping, provider, injectionPoints)); + return true; + } - @Override - public Boolean visit(LinkedKeyBinding<? extends T> binding) { - prepareBinding(); - Key<? extends T> linkedKey = binding.getLinkedKey(); - if (key.equals(linkedKey)) { - errors.recursiveBinding(); - } - - FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source); - bindingData.addCreationListener(factory); - InternalFactory<? extends T> scopedFactory - = Scoping.scope(key, injector, factory, source, scoping); - putBinding( - new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey)); - return true; - } + @Override + public Boolean visit(ProviderKeyBinding<? extends T> binding) { + prepareBinding(); + Key<? extends javax.inject.Provider<? extends T>> providerKey = + binding.getProviderKey(); + // always visited with Binding<T> + @SuppressWarnings("unchecked") + BoundProviderFactory<T> boundProviderFactory = + new BoundProviderFactory<T>( + injector, + providerKey, + source, + injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding)); + bindingData.addCreationListener(boundProviderFactory); + InternalFactory<? extends T> scopedFactory = + Scoping.scope( + key, + injector, + (InternalFactory<? extends T>) boundProviderFactory, + source, + scoping); + putBinding( + new LinkedProviderBindingImpl<T>( + injector, key, source, scopedFactory, scoping, providerKey)); + return true; + } - @Override - public Boolean visit(UntargettedBinding<? extends T> untargetted) { - return false; - } + @Override + public Boolean visit(LinkedKeyBinding<? extends T> binding) { + prepareBinding(); + Key<? extends T> linkedKey = binding.getLinkedKey(); + if (key.equals(linkedKey)) { + errors.recursiveBinding(); + } - @Override - public Boolean visit(ExposedBinding<? extends T> binding) { - throw new IllegalArgumentException("Cannot apply a non-module element"); - } - - @Override - public Boolean visit(ConvertedConstantBinding<? extends T> binding) { - throw new IllegalArgumentException("Cannot apply a non-module element"); - } - - @Override - public Boolean visit(ProviderBinding<? extends T> binding) { - throw new IllegalArgumentException("Cannot apply a non-module element"); - } - - @Override - protected Boolean visitOther(Binding<? extends T> binding) { - throw new IllegalStateException("BindingProcessor should override all visitations"); - } - }); + FactoryProxy<T> factory = new FactoryProxy<>(injector, key, linkedKey, source); + bindingData.addCreationListener(factory); + InternalFactory<? extends T> scopedFactory = + Scoping.scope(key, injector, factory, source, scoping); + putBinding( + new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey)); + return true; + } + + /** Handle ProviderMethods specially. */ + private Boolean visitInternalProviderInstanceBindingFactory( + InternalProviderInstanceBindingImpl.Factory<T> provider) { + InternalProviderInstanceBindingImpl<T> binding = + new InternalProviderInstanceBindingImpl<T>( + injector, + key, + source, + provider, + Scoping.scope(key, injector, provider, source, scoping), + scoping); + switch (binding.getInitializationTiming()) { + case DELAYED: + scheduleDelayedInitialization(binding); + break; + case EAGER: + scheduleInitialization(binding); + break; + default: + throw new AssertionError(); + } + putBinding(binding); + return true; + } + + @Override + public Boolean visit(UntargettedBinding<? extends T> untargetted) { + return false; + } + + @Override + public Boolean visit(ExposedBinding<? extends T> binding) { + throw new IllegalArgumentException("Cannot apply a non-module element"); + } + + @Override + public Boolean visit(ConvertedConstantBinding<? extends T> binding) { + throw new IllegalArgumentException("Cannot apply a non-module element"); + } + + @Override + public Boolean visit(ProviderBinding<? extends T> binding) { + throw new IllegalArgumentException("Cannot apply a non-module element"); + } + + @Override + protected Boolean visitOther(Binding<? extends T> binding) { + throw new IllegalStateException("BindingProcessor should override all visitations"); + } + }); } - @Override public Boolean visit(PrivateElements privateElements) { + @Override + public Boolean visit(PrivateElements privateElements) { for (Key<?> key : privateElements.getExposedKeys()) { bindExposed(privateElements, key); } @@ -189,9 +245,14 @@ final class BindingProcessor extends AbstractBindingProcessor { } private <T> void bindExposed(PrivateElements privateElements, Key<T> key) { - ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements); + ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<>(key, privateElements); bindingData.addCreationListener(exposedKeyFactory); - putBinding(new ExposedBindingImpl<T>( - injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements)); + putBinding( + new ExposedBindingImpl<T>( + injector, + privateElements.getExposedSource(key), + key, + exposedKeyFactory, + privateElements)); } } diff --git a/core/src/com/google/inject/internal/BoundProviderFactory.java b/core/src/com/google/inject/internal/BoundProviderFactory.java index 9f523dfa..eaaf7678 100644 --- a/core/src/com/google/inject/internal/BoundProviderFactory.java +++ b/core/src/com/google/inject/internal/BoundProviderFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,17 +16,12 @@ package com.google.inject.internal; -import static com.google.common.base.Preconditions.checkNotNull; - import com.google.inject.Key; import com.google.inject.internal.InjectorImpl.JitLimitation; import com.google.inject.spi.Dependency; - import javax.inject.Provider; -/** - * Delegates to a custom factory which is also bound in the injector. - */ +/** Delegates to a custom factory which is also bound in the injector. */ final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implements CreationListener { private final ProvisionListenerStackCallback<T> provisionCallback; @@ -40,42 +35,53 @@ final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implement Object source, ProvisionListenerStackCallback<T> provisionCallback) { super(source); - this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback"); + this.provisionCallback = provisionCallback; this.injector = injector; this.providerKey = providerKey; } + @Override public void notify(Errors errors) { try { - providerFactory = injector.getInternalFactory(providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT); + providerFactory = + injector.getInternalFactory( + providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT); } catch (ErrorsException e) { errors.merge(e.getErrors()); } } - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { context.pushState(providerKey, source); + try { - errors = errors.withSource(providerKey); - javax.inject.Provider<? extends T> provider = providerFactory.get(errors, context, dependency, true); - return circularGet(provider, errors, context, dependency, provisionCallback); - } finally { - context.popState(); + javax.inject.Provider<? extends T> provider = providerFactory.get(context, dependency, true); + return circularGet(provider, context, dependency, provisionCallback); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(providerKey); + } finally { + context.popState(); + } } - + @Override - protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency, - ConstructionContext<T> constructionContext) throws ErrorsException { + protected T provision( + Provider<? extends T> provider, + Dependency<?> dependency, + ConstructionContext<T> constructionContext) + throws InternalProvisionException { try { - return super.provision(provider, errors, dependency, constructionContext); - } catch(RuntimeException userException) { - throw errors.errorInProvider(userException).toException(); - } + return super.provision(provider, dependency, constructionContext); + } catch (RuntimeException userException) { + throw InternalProvisionException.errorInProvider(userException); + } } - @Override public String toString() { + @Override + public String toString() { return providerKey.toString(); } } diff --git a/core/src/com/google/inject/internal/BytecodeGen.java b/core/src/com/google/inject/internal/BytecodeGen.java index ed01cd10..2ec96cb3 100644 --- a/core/src/com/google/inject/internal/BytecodeGen.java +++ b/core/src/com/google/inject/internal/BytecodeGen.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,13 +22,13 @@ import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; import com.google.inject.internal.InternalFlags.CustomClassLoadingOption; - import java.lang.reflect.Constructor; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.logging.Level; import java.util.logging.Logger; /** @@ -37,24 +37,26 @@ import java.util.logging.Logger; * interceptors} and to proxy circular dependencies. * * <p>When loading classes, we need to be careful of: + * * <ul> - * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived - * applications. Once an injector and any instances it created can be garbage collected, the - * corresponding generated classes should be collectable. - * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries - * to enforce modularity at runtime. + * <li><strong>Memory leaks.</strong> Generated classes need to be garbage collected in long-lived + * applications. Once an injector and any instances it created can be garbage collected, the + * corresponding generated classes should be collectable. + * <li><strong>Visibility.</strong> Containers like <code>OSGi</code> use class loader boundaries to + * enforce modularity at runtime. * </ul> * * <p>For each generated class, there's multiple class loaders involved: + * * <ul> - * <li><strong>The related class's class loader.</strong> Every generated class services exactly - * one user-supplied class. This class loader must be used to access members with private and - * package visibility. - * <li><strong>Guice's class loader.</strong> - * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It - * selectively delegates to either the user's class loader (for user classes) or the Guice - * class loader (for internal classes that are used by the generated classes). This class - * loader that owns the classes generated by Guice. + * <li><strong>The related class's class loader.</strong> Every generated class services exactly one + * user-supplied class. This class loader must be used to access members with protected and + * package visibility. + * <li><strong>Guice's class loader.</strong> + * <li><strong>Our bridge class loader.</strong> This is a child of the user's class loader. It + * selectively delegates to either the user's class loader (for user classes) or the Guice class + * loader (for internal classes that are used by the generated classes). This class loader that + * owns the classes generated by Guice. * </ul> * * @author mcculls@gmail.com (Stuart McCulloch) @@ -72,56 +74,57 @@ public final class BytecodeGen { } /** ie. "com.google.inject.internal" */ - static final String GUICE_INTERNAL_PACKAGE - = BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal"); + static final String GUICE_INTERNAL_PACKAGE = + BytecodeGen.class.getName().replaceFirst("\\.internal\\..*$", ".internal"); /*if[AOP]*/ /** either "net.sf.cglib", or "com.google.inject.internal.cglib" */ - static final String CGLIB_PACKAGE - = net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib"); - - static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY - = new net.sf.cglib.core.DefaultNamingPolicy() { - @Override protected String getTag() { - return "ByGuice"; - } + static final String CGLIB_PACKAGE = + net.sf.cglib.proxy.Enhancer.class.getName().replaceFirst("\\.cglib\\..*$", ".cglib"); + + static final net.sf.cglib.core.NamingPolicy FASTCLASS_NAMING_POLICY = + new net.sf.cglib.core.DefaultNamingPolicy() { + @Override + protected String getTag() { + return "ByGuice"; + } - @Override - public String getClassName(String prefix, String source, Object key, - net.sf.cglib.core.Predicate names) { - // we explicitly set the source here to "FastClass" so that our jarjar renaming - // to $FastClass doesn't leak into the class names. if we did not do this, - // classes would end up looking like $$$FastClassByGuice$$, with the extra $ - // at the front. - return super.getClassName(prefix, "FastClass", key, names); - } - }; + @Override + public String getClassName( + String prefix, String source, Object key, net.sf.cglib.core.Predicate names) { + // we explicitly set the source here to "FastClass" so that our jarjar renaming + // to $FastClass doesn't leak into the class names. if we did not do this, + // classes would end up looking like $$$FastClassByGuice$$, with the extra $ + // at the front. + return super.getClassName(prefix, "FastClass", key, names); + } + }; - static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY - = new net.sf.cglib.core.DefaultNamingPolicy() { - @Override - protected String getTag() { - return "ByGuice"; - } + static final net.sf.cglib.core.NamingPolicy ENHANCER_NAMING_POLICY = + new net.sf.cglib.core.DefaultNamingPolicy() { + @Override + protected String getTag() { + return "ByGuice"; + } - @Override - public String getClassName(String prefix, String source, Object key, - net.sf.cglib.core.Predicate names) { - // we explicitly set the source here to "Enhancer" so that our jarjar renaming - // to $Enhancer doesn't leak into the class names. if we did not do this, - // classes would end up looking like $$$EnhancerByGuice$$, with the extra $ - // at the front. - return super.getClassName(prefix, "Enhancer", key, names); - } - }; + @Override + public String getClassName( + String prefix, String source, Object key, net.sf.cglib.core.Predicate names) { + // we explicitly set the source here to "Enhancer" so that our jarjar renaming + // to $Enhancer doesn't leak into the class names. if we did not do this, + // classes would end up looking like $$$EnhancerByGuice$$, with the extra $ + // at the front. + return super.getClassName(prefix, "Enhancer", key, names); + } + }; /*end[AOP]*/ /*if[NO_AOP] private static final String CGLIB_PACKAGE = " "; // any string that's illegal in a package name end[NO_AOP]*/ /** - * Weak cache of bridge class loaders that make the Guice implementation - * classes visible to various code-generated proxies of client classes. + * Weak cache of bridge class loaders that make the Guice implementation classes visible to + * various code-generated proxies of client classes. */ private static final LoadingCache<ClassLoader, ClassLoader> CLASS_LOADER_CACHE; @@ -130,30 +133,32 @@ public final class BytecodeGen { if (getCustomClassLoadingOption() == CustomClassLoadingOption.OFF) { builder.maximumSize(0); } - CLASS_LOADER_CACHE = builder.build( - new CacheLoader<ClassLoader, ClassLoader>() { - @Override public ClassLoader load(final ClassLoader typeClassLoader) { - logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); - return AccessController.doPrivileged(new PrivilegedAction<ClassLoader>() { - public ClassLoader run() { - return new BridgeClassLoader(typeClassLoader); + CLASS_LOADER_CACHE = + builder.build( + new CacheLoader<ClassLoader, ClassLoader>() { + @Override + public ClassLoader load(final ClassLoader typeClassLoader) { + logger.fine("Creating a bridge ClassLoader for " + typeClassLoader); + return AccessController.doPrivileged( + new PrivilegedAction<ClassLoader>() { + @Override + public ClassLoader run() { + return new BridgeClassLoader(typeClassLoader); + } + }); } }); - } - }); } /** - * Attempts to canonicalize null references to the system class loader. - * May return null if for some reason the system loader is unavailable. + * Attempts to canonicalize null references to the system class loader. May return null if for + * some reason the system loader is unavailable. */ private static ClassLoader canonicalize(ClassLoader classLoader) { return classLoader != null ? classLoader : SystemBridgeHolder.SYSTEM_BRIDGE.getParent(); } - /** - * Returns the class loader to host generated classes for {@code type}. - */ + /** Returns the class loader to host generated classes for {@code type}. */ public static ClassLoader getClassLoader(Class<?> type) { return getClassLoader(type, type.getClassLoader()); } @@ -191,19 +196,108 @@ public final class BytecodeGen { } /*if[AOP]*/ - // use fully-qualified names so imports don't need preprocessor statements - public static net.sf.cglib.reflect.FastClass newFastClass(Class<?> type, Visibility visibility) { - net.sf.cglib.reflect.FastClass.Generator generator - = new net.sf.cglib.reflect.FastClass.Generator(); - generator.setType(type); - if (visibility == Visibility.PUBLIC) { + // use fully-qualified names so imports don't need preprocessor statements + /** + * Returns a FastClass proxy for invoking the given member or {@code null} if access rules + * disallow it. + * + * @see #newFastClassForMember(Class, Member) for a full description + */ + public static net.sf.cglib.reflect.FastClass newFastClassForMember(Member member) { + return newFastClassForMember(member.getDeclaringClass(), member); + } + + /** + * Returns a FastClass proxy for invoking the given member or {@code null} if access rules + * disallow it. + * + * <p>FastClass works by generating a type in the same package as the target {@code type}. This + * may or may not work depending on the access level of the class/member. It breaks down into the + * following cases depending on accessibility: + * + * <ul> + * <li>Public: This always works since we can generate the type into the {@link BridgeClassLoader} + * which ensures there are no versioning issues. + * <li>Package private and Protected: This works as long as: + * <ul> + * <li>We can generate into the same classloader as the type. This is not possible for JDK + * types which use the 'bootstrap' loader. + * <li>The classloader of the type has the same version of {@code FastClass} as we do. This + * may be violated when running in OSGI bundles. + * </ul> + * + * <li>Private: This never works. + * </ul> + * + * If we are unable to generate the type, then we return null and callers should work around by + * using normal java reflection. + */ + public static net.sf.cglib.reflect.FastClass newFastClassForMember(Class<?> type, Member member) { + if (!new net.sf.cglib.core.VisibilityPredicate(type, false).evaluate(member)) { + // the member cannot be indexed by fast class. Bail out. + return null; + } + + boolean publiclyCallable = isPubliclyCallable(member); + if (!publiclyCallable && !hasSameVersionOfCglib(type.getClassLoader())) { + // The type is in a classloader with a different version of cglib and is not publicly visible + // (so we can't use the bridge classloader to work around). Bail out. + return null; + } + net.sf.cglib.reflect.FastClass.Generator generator = + new net.sf.cglib.reflect.FastClass.Generator(); + if (publiclyCallable) { + // Use the bridge classloader if we can generator.setClassLoader(getClassLoader(type)); } + generator.setType(type); generator.setNamingPolicy(FASTCLASS_NAMING_POLICY); - logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader()); + if (logger.isLoggable(Level.FINE)) { + logger.fine("Loading " + type + " FastClass with " + generator.getClassLoader()); + } return generator.create(); } + /** + * Returns true if the types classloader has the same version of cglib that BytecodeGen has. This + * only returns false in strange OSGI situations, but it prevents us from using FastClass for non + * public members. + */ + private static boolean hasSameVersionOfCglib(ClassLoader classLoader) { + Class<?> fc = net.sf.cglib.reflect.FastClass.class; + try { + return classLoader.loadClass(fc.getName()) == fc; + } catch (ClassNotFoundException e) { + return false; + } + } + + /** + * Returns true if the member can be called by a fast class generated in a different classloader. + */ + private static boolean isPubliclyCallable(Member member) { + if (!Modifier.isPublic(member.getModifiers())) { + return false; + } + Class<?>[] parameterTypes; + if (member instanceof Constructor) { + parameterTypes = ((Constructor) member).getParameterTypes(); + } else { + Method method = (Method) member; + if (!Modifier.isPublic(method.getReturnType().getModifiers())) { + return false; + } + parameterTypes = method.getParameterTypes(); + } + + for (Class<?> type : parameterTypes) { + if (!Modifier.isPublic(type.getModifiers())) { + return false; + } + } + return true; + } + public static net.sf.cglib.proxy.Enhancer newEnhancer(Class<?> type, Visibility visibility) { net.sf.cglib.proxy.Enhancer enhancer = new net.sf.cglib.proxy.Enhancer(); enhancer.setSuperclass(type); @@ -298,10 +392,10 @@ public final class BytecodeGen { super(usersClassLoader); } - @Override protected Class<?> loadClass(String name, boolean resolve) - throws ClassNotFoundException { + @Override + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException { - if (name.startsWith("sun.reflect")) { + if (name.startsWith("sun.reflect") || name.startsWith("jdk.internal.reflect")) { // these reflection classes must be loaded from bootstrap class loader return SystemBridgeHolder.SYSTEM_BRIDGE.classicLoadClass(name, resolve); } @@ -326,8 +420,7 @@ public final class BytecodeGen { } // make the classic delegating loadClass method visible - Class<?> classicLoadClass(String name, boolean resolve) - throws ClassNotFoundException { + Class<?> classicLoadClass(String name, boolean resolve) throws ClassNotFoundException { return super.loadClass(name, resolve); } } diff --git a/core/src/com/google/inject/internal/CircularDependencyProxy.java b/core/src/com/google/inject/internal/CircularDependencyProxy.java index fe894a40..dc127480 100644 --- a/core/src/com/google/inject/internal/CircularDependencyProxy.java +++ b/core/src/com/google/inject/internal/CircularDependencyProxy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,7 @@ package com.google.inject.internal; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ public interface CircularDependencyProxy { // marker interface } diff --git a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java index 8a0c5c6a..1c11cfe4 100644 --- a/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java +++ b/core/src/com/google/inject/internal/ConstantBindingBuilderImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.inject.binder.AnnotatedConstantBindingBuilder; import com.google.inject.binder.ConstantBindingBuilder; import com.google.inject.spi.Element; import com.google.inject.spi.InjectionPoint; - import java.lang.annotation.Annotation; import java.util.List; @@ -32,8 +31,7 @@ import java.util.List; * * @author jessewilson@google.com (Jesse Wilson) */ -public final class ConstantBindingBuilderImpl<T> - extends AbstractBindingBuilder<T> +public final class ConstantBindingBuilderImpl<T> extends AbstractBindingBuilder<T> implements AnnotatedConstantBindingBuilder, ConstantBindingBuilder { @SuppressWarnings("unchecked") // constant bindings start out with T unknown @@ -41,56 +39,69 @@ public final class ConstantBindingBuilderImpl<T> super(binder, elements, source, (Key<T>) NULL_KEY); } + @Override public ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType) { annotatedWithInternal(annotationType); return this; } + @Override public ConstantBindingBuilder annotatedWith(Annotation annotation) { annotatedWithInternal(annotation); return this; } + @Override public void to(final String value) { toConstant(String.class, value); } + @Override public void to(final int value) { toConstant(Integer.class, value); } + @Override public void to(final long value) { toConstant(Long.class, value); } + @Override public void to(final boolean value) { toConstant(Boolean.class, value); } + @Override public void to(final double value) { toConstant(Double.class, value); } + @Override public void to(final float value) { toConstant(Float.class, value); } + @Override public void to(final short value) { toConstant(Short.class, value); } + @Override public void to(final char value) { toConstant(Character.class, value); } + @Override public void to(final byte value) { toConstant(Byte.class, value); - } + } + @Override public void to(final Class<?> value) { toConstant(Class.class, value); } + @Override public <E extends Enum<E>> void to(final E value) { toConstant(value.getDeclaringClass(), value); } @@ -121,11 +132,17 @@ public final class ConstantBindingBuilderImpl<T> binder.addError(BINDING_TO_NULL); } - setBinding(new InstanceBindingImpl<T>( - base.getSource(), key, base.getScoping(), ImmutableSet.<InjectionPoint>of(), instanceAsT)); + setBinding( + new InstanceBindingImpl<T>( + base.getSource(), + key, + base.getScoping(), + ImmutableSet.<InjectionPoint>of(), + instanceAsT)); } - @Override public String toString() { + @Override + public String toString() { return "ConstantBindingBuilder"; } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/ConstantFactory.java b/core/src/com/google/inject/internal/ConstantFactory.java index 633d5de0..d9320036 100644 --- a/core/src/com/google/inject/internal/ConstantFactory.java +++ b/core/src/com/google/inject/internal/ConstantFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,12 +16,10 @@ package com.google.inject.internal; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.inject.spi.Dependency; -/** - * @author crazybob@google.com (Bob Lee) - */ +/** @author crazybob@google.com (Bob Lee) */ final class ConstantFactory<T> implements InternalFactory<T> { private final Initializable<T> initializable; @@ -30,14 +28,14 @@ final class ConstantFactory<T> implements InternalFactory<T> { this.initializable = initializable; } - public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked) - throws ErrorsException { - return initializable.get(errors); + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + return initializable.get(); } + @Override public String toString() { - return Objects.toStringHelper(ConstantFactory.class) - .add("value", initializable) - .toString(); + return MoreObjects.toStringHelper(ConstantFactory.class).add("value", initializable).toString(); } } diff --git a/core/src/com/google/inject/internal/ConstructionContext.java b/core/src/com/google/inject/internal/ConstructionContext.java index ced388f6..25786f59 100644 --- a/core/src/com/google/inject/internal/ConstructionContext.java +++ b/core/src/com/google/inject/internal/ConstructionContext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,6 @@ package com.google.inject.internal; import com.google.inject.internal.InjectorImpl.InjectorOptions; - import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.List; @@ -59,28 +58,31 @@ final class ConstructionContext<T> { invocationHandlers = null; } - public Object createProxy(Errors errors, InjectorOptions injectorOptions, - Class<?> expectedType) throws ErrorsException { + public Object createProxy(InjectorOptions injectorOptions, Class<?> expectedType) + throws InternalProvisionException { if (injectorOptions.disableCircularProxies) { - throw errors.circularProxiesDisabled(expectedType).toException(); + throw InternalProvisionException.circularDependenciesDisabled(expectedType); } if (!expectedType.isInterface()) { - throw errors.cannotSatisfyCircularDependency(expectedType).toException(); + throw InternalProvisionException.cannotProxyClass(expectedType); } if (invocationHandlers == null) { - invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>(); + invocationHandlers = new ArrayList<>(); } - DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<T>(); + DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<>(); invocationHandlers.add(invocationHandler); // TODO: if I create a proxy which implements all the interfaces of // the implementation type, I'll be able to get away with one proxy // instance (as opposed to one per caller). ClassLoader classLoader = BytecodeGen.getClassLoader(expectedType); - return expectedType.cast(Proxy.newProxyInstance(classLoader, - new Class[] { expectedType, CircularDependencyProxy.class }, invocationHandler)); + return expectedType.cast( + Proxy.newProxyInstance( + classLoader, + new Class[] {expectedType, CircularDependencyProxy.class}, + invocationHandler)); } public void setProxyDelegates(T delegate) { diff --git a/core/src/com/google/inject/internal/ConstructionProxy.java b/core/src/com/google/inject/internal/ConstructionProxy.java index 6c6f3fcc..2f56cf0b 100644 --- a/core/src/com/google/inject/internal/ConstructionProxy.java +++ b/core/src/com/google/inject/internal/ConstructionProxy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,28 +18,22 @@ package com.google.inject.internal; import com.google.common.collect.ImmutableMap; import com.google.inject.spi.InjectionPoint; - import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.List; /** - * Proxies calls to a {@link java.lang.reflect.Constructor} for a class - * {@code T}. + * Proxies calls to a {@link java.lang.reflect.Constructor} for a class {@code T}. * * @author crazybob@google.com (Bob Lee) */ interface ConstructionProxy<T> { - /** - * Constructs an instance of {@code T} for the given arguments. - */ + /** Constructs an instance of {@code T} for the given arguments. */ T newInstance(Object... arguments) throws InvocationTargetException; - /** - * Returns the injection point for this constructor. - */ + /** Returns the injection point for this constructor. */ InjectionPoint getInjectionPoint(); /** @@ -49,9 +43,7 @@ interface ConstructionProxy<T> { Constructor<T> getConstructor(); /*if[AOP]*/ - /** - * Returns the interceptors applied to each method, in order of invocation. - */ + /** Returns the interceptors applied to each method, in order of invocation. */ ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors(); /*end[AOP]*/ } diff --git a/core/src/com/google/inject/internal/ConstructionProxyFactory.java b/core/src/com/google/inject/internal/ConstructionProxyFactory.java index 0eca0fe7..51225242 100644 --- a/core/src/com/google/inject/internal/ConstructionProxyFactory.java +++ b/core/src/com/google/inject/internal/ConstructionProxyFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,8 +23,6 @@ package com.google.inject.internal; */ interface ConstructionProxyFactory<T> { - /** - * Gets a construction proxy for the given constructor. - */ + /** Gets a construction proxy for the given constructor. */ ConstructionProxy<T> create() throws ErrorsException; } diff --git a/core/src/com/google/inject/internal/ConstructorBindingImpl.java b/core/src/com/google/inject/internal/ConstructorBindingImpl.java index 8fb21035..d141d65f 100644 --- a/core/src/com/google/inject/internal/ConstructorBindingImpl.java +++ b/core/src/com/google/inject/internal/ConstructorBindingImpl.java @@ -19,6 +19,7 @@ package com.google.inject.internal; import static com.google.common.base.Preconditions.checkState; import static com.google.inject.internal.Annotations.findScopeAnnotation; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; @@ -31,7 +32,6 @@ import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.ConstructorBinding; import com.google.inject.spi.Dependency; import com.google.inject.spi.InjectionPoint; - import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -46,44 +46,60 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> private final Factory<T> factory; private final InjectionPoint constructorInjectionPoint; - private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> scopedFactory, Scoping scoping, Factory<T> factory, + private ConstructorBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> scopedFactory, + Scoping scoping, + Factory<T> factory, InjectionPoint constructorInjectionPoint) { super(injector, key, source, scopedFactory, scoping); this.factory = factory; this.constructorInjectionPoint = constructorInjectionPoint; } - public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping, - InjectionPoint constructorInjectionPoint, Set<InjectionPoint> injectionPoints) { + public ConstructorBindingImpl( + Key<T> key, + Object source, + Scoping scoping, + InjectionPoint constructorInjectionPoint, + Set<InjectionPoint> injectionPoints) { super(source, key, scoping); - this.factory = new Factory<T>(false, key); - ConstructionProxy<T> constructionProxy - = new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create(); + this.factory = new Factory<>(false, key); + ConstructionProxy<T> constructionProxy = + new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create(); this.constructorInjectionPoint = constructorInjectionPoint; - factory.constructorInjector = new ConstructorInjector<T>( - injectionPoints, constructionProxy, null, null); + factory.constructorInjector = + new ConstructorInjector<T>(injectionPoints, constructionProxy, null, null); } /** * @param constructorInjector the constructor to use, or {@code null} to use the default. - * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should - * only succeed if retrieved from a linked binding + * @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should only + * succeed if retrieved from a linked binding */ - static <T> ConstructorBindingImpl<T> create(InjectorImpl injector, Key<T> key, - InjectionPoint constructorInjector, Object source, Scoping scoping, Errors errors, - boolean failIfNotLinked, boolean failIfNotExplicit) + static <T> ConstructorBindingImpl<T> create( + InjectorImpl injector, + Key<T> key, + InjectionPoint constructorInjector, + Object source, + Scoping scoping, + Errors errors, + boolean failIfNotLinked, + boolean failIfNotExplicit) throws ErrorsException { int numErrors = errors.size(); @SuppressWarnings("unchecked") // constructorBinding guarantees type is consistent - Class<? super T> rawType = constructorInjector == null - ? key.getTypeLiteral().getRawType() - : (Class) constructorInjector.getDeclaringType().getRawType(); + Class<? super T> rawType = + constructorInjector == null + ? key.getTypeLiteral().getRawType() + : (Class) constructorInjector.getDeclaringType().getRawType(); // We can't inject abstract classes. if (Modifier.isAbstract(rawType.getModifiers())) { - errors.missingImplementation(key); + errors.missingImplementationWithHint(key, injector); } // Error: Inner class. @@ -110,16 +126,17 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> Class<?> annotatedType = constructorInjector.getMember().getDeclaringClass(); Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, annotatedType); if (scopeAnnotation != null) { - scoping = Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation), - injector, errors.withSource(rawType)); + scoping = + Scoping.makeInjectable( + Scoping.forAnnotation(scopeAnnotation), injector, errors.withSource(rawType)); } } errors.throwIfNewErrors(numErrors); - Factory<T> factoryFactory = new Factory<T>(failIfNotLinked, key); - InternalFactory<? extends T> scopedFactory - = Scoping.scope(key, injector, factoryFactory, source, scoping); + Factory<T> factoryFactory = new Factory<>(failIfNotLinked, key); + InternalFactory<? extends T> scopedFactory = + Scoping.scope(key, injector, factoryFactory, source, scoping); return new ConstructorBindingImpl<T>( injector, key, source, scopedFactory, scoping, factoryFactory, constructorInjector); @@ -131,12 +148,12 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> || cxtor.isAnnotationPresent(javax.inject.Inject.class); } + @Override @SuppressWarnings("unchecked") // the result type always agrees with the ConstructorInjector type public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { factory.constructorInjector = (ConstructorInjector<T>) injector.constructors.get(constructorInjectionPoint, errors); - factory.provisionCallback = - injector.provisionListenerStore.get(this); + factory.provisionCallback = injector.provisionListenerStore.get(this); } /** True if this binding has been initialized and is ready for use. */ @@ -146,7 +163,7 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> /** Returns an injection point that can be used to clean up the constructor store. */ InjectionPoint getInternalConstructor() { - if(factory.constructorInjector != null) { + if (factory.constructorInjector != null) { return factory.constructorInjector.getConstructionProxy().getInjectionPoint(); } else { return constructorInjectionPoint; @@ -156,69 +173,87 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> /** Returns a set of dependencies that can be iterated over to clean up stray JIT bindings. */ Set<Dependency<?>> getInternalDependencies() { ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder(); - if(factory.constructorInjector == null) { + if (factory.constructorInjector == null) { builder.add(constructorInjectionPoint); // If the below throws, it's OK -- we just ignore those dependencies, because no one // could have used them anyway. try { - builder.addAll(InjectionPoint.forInstanceMethodsAndFields(constructorInjectionPoint.getDeclaringType())); - } catch(ConfigurationException ignored) {} + builder.addAll( + InjectionPoint.forInstanceMethodsAndFields( + constructorInjectionPoint.getDeclaringType())); + } catch (ConfigurationException ignored) { + } } else { - builder.add(getConstructor()) - .addAll(getInjectableMembers()); + builder.add(getConstructor()).addAll(getInjectableMembers()); } return Dependency.forInjectionPoints(builder.build()); } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { checkState(factory.constructorInjector != null, "not initialized"); return visitor.visit(this); } + @Override public InjectionPoint getConstructor() { checkState(factory.constructorInjector != null, "Binding is not ready"); return factory.constructorInjector.getConstructionProxy().getInjectionPoint(); } + @Override public Set<InjectionPoint> getInjectableMembers() { checkState(factory.constructorInjector != null, "Binding is not ready"); return factory.constructorInjector.getInjectableMembers(); } /*if[AOP]*/ + @Override public Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors() { checkState(factory.constructorInjector != null, "Binding is not ready"); return factory.constructorInjector.getConstructionProxy().getMethodInterceptors(); } /*end[AOP]*/ + @Override public Set<Dependency<?>> getDependencies() { - return Dependency.forInjectionPoints(new ImmutableSet.Builder<InjectionPoint>() - .add(getConstructor()) - .addAll(getInjectableMembers()) - .build()); + return Dependency.forInjectionPoints( + new ImmutableSet.Builder<InjectionPoint>() + .add(getConstructor()) + .addAll(getInjectableMembers()) + .build()); } - @Override protected BindingImpl<T> withScoping(Scoping scoping) { + @Override + protected BindingImpl<T> withScoping(Scoping scoping) { return new ConstructorBindingImpl<T>( null, getKey(), getSource(), factory, scoping, factory, constructorInjectionPoint); } - @Override protected BindingImpl<T> withKey(Key<T> key) { + @Override + protected BindingImpl<T> withKey(Key<T> key) { return new ConstructorBindingImpl<T>( null, key, getSource(), factory, getScoping(), factory, constructorInjectionPoint); } + @Override @SuppressWarnings("unchecked") // the raw constructor member and declaring type always agree public void applyTo(Binder binder) { InjectionPoint constructor = getConstructor(); - getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).toConstructor( - (Constructor) getConstructor().getMember(), (TypeLiteral) constructor.getDeclaringType())); + getScoping() + .applyTo( + binder + .withSource(getSource()) + .bind(getKey()) + .toConstructor( + (Constructor) getConstructor().getMember(), + (TypeLiteral) constructor.getDeclaringType())); } - @Override public String toString() { - return Objects.toStringHelper(ConstructorBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(ConstructorBinding.class) .add("key", getKey()) .add("source", getSource()) .add("scope", getScoping()) @@ -227,11 +262,11 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> @Override public boolean equals(Object obj) { - if(obj instanceof ConstructorBindingImpl) { - ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>)obj; + if (obj instanceof ConstructorBindingImpl) { + ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint); + && getScoping().equals(o.getScoping()) + && Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint); } else { return false; } @@ -253,19 +288,22 @@ final class ConstructorBindingImpl<T> extends BindingImpl<T> this.key = key; } + @Override @SuppressWarnings("unchecked") - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - checkState(constructorInjector != null, "Constructor not ready"); + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + ConstructorInjector<T> localInjector = constructorInjector; + if (localInjector == null) { + throw new IllegalStateException("Constructor not ready"); + } - if(failIfNotLinked && !linked) { - throw errors.jitDisabled(key).toException(); + if (!linked && failIfNotLinked) { + throw InternalProvisionException.jitDisabled(key); } // This may not actually be safe because it could return a super type of T (if that's all the // client needs), but it should be OK in practice thanks to the wonders of erasure. - return (T) constructorInjector.construct(errors, context, - dependency.getKey().getTypeLiteral().getRawType(), provisionCallback); + return (T) localInjector.construct(context, dependency, provisionCallback); } } } diff --git a/core/src/com/google/inject/internal/ConstructorInjector.java b/core/src/com/google/inject/internal/ConstructorInjector.java index 1ff4be1f..13e11478 100644 --- a/core/src/com/google/inject/internal/ConstructorInjector.java +++ b/core/src/com/google/inject/internal/ConstructorInjector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,8 +18,8 @@ package com.google.inject.internal; import com.google.common.collect.ImmutableSet; import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback; +import com.google.inject.spi.Dependency; import com.google.inject.spi.InjectionPoint; - import java.lang.reflect.InvocationTargetException; import java.util.Set; @@ -36,7 +36,8 @@ final class ConstructorInjector<T> { private final ConstructionProxy<T> constructionProxy; private final MembersInjectorImpl<T> membersInjector; - ConstructorInjector(Set<InjectionPoint> injectableMembers, + ConstructorInjector( + Set<InjectionPoint> injectableMembers, ConstructionProxy<T> constructionProxy, SingleParameterInjector<?>[] parameterInjectors, MembersInjectorImpl<T> membersInjector) { @@ -55,40 +56,48 @@ final class ConstructorInjector<T> { } /** - * Construct an instance. Returns {@code Object} instead of {@code T} because - * it may return a proxy. + * Construct an instance. Returns {@code Object} instead of {@code T} because it may return a + * proxy. */ - Object construct(final Errors errors, final InternalContext context, - Class<?> expectedType, - ProvisionListenerStackCallback<T> provisionCallback) - throws ErrorsException { + Object construct( + final InternalContext context, + Dependency<?> dependency, + /* @Nullable */ ProvisionListenerStackCallback<T> provisionCallback) + throws InternalProvisionException { final ConstructionContext<T> constructionContext = context.getConstructionContext(this); - // We have a circular reference between constructors. Return a proxy. if (constructionContext.isConstructing()) { // TODO (crazybob): if we can't proxy this object, can we proxy the other object? return constructionContext.createProxy( - errors, context.getInjectorOptions(), expectedType); + context.getInjectorOptions(), dependency.getKey().getTypeLiteral().getRawType()); } // If we're re-entering this factory while injecting fields or methods, // return the same instance. This prevents infinite loops. T t = constructionContext.getCurrentReference(); if (t != null) { - return t; + if (context.getInjectorOptions().disableCircularProxies) { + throw InternalProvisionException.circularDependenciesDisabled( + dependency.getKey().getTypeLiteral().getRawType()); + } else { + return t; + } } constructionContext.startConstruction(); try { // Optimization: Don't go through the callback stack if we have no listeners. - if (!provisionCallback.hasListeners()) { - return provision(errors, context, constructionContext); + if (provisionCallback == null) { + return provision(context, constructionContext); } else { - return provisionCallback.provision(errors, context, new ProvisionCallback<T>() { - public T call() throws ErrorsException { - return provision(errors, context, constructionContext); - } - }); + return provisionCallback.provision( + context, + new ProvisionCallback<T>() { + @Override + public T call() throws InternalProvisionException { + return provision(context, constructionContext); + } + }); } } finally { constructionContext.finishConstruction(); @@ -96,12 +105,12 @@ final class ConstructorInjector<T> { } /** Provisions a new T. */ - private T provision(Errors errors, InternalContext context, - ConstructionContext<T> constructionContext) throws ErrorsException { + private T provision(InternalContext context, ConstructionContext<T> constructionContext) + throws InternalProvisionException { try { T t; try { - Object[] parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors); + Object[] parameters = SingleParameterInjector.getAll(context, parameterInjectors); t = constructionProxy.newInstance(parameters); constructionContext.setProxyDelegates(t); } finally { @@ -111,16 +120,15 @@ final class ConstructorInjector<T> { // Store reference. If an injector re-enters this factory, they'll get the same reference. constructionContext.setCurrentReference(t); - membersInjector.injectMembers(t, errors, context, false); - membersInjector.notifyListeners(t, errors); + MembersInjectorImpl<T> localMembersInjector = membersInjector; + localMembersInjector.injectMembers(t, context, false); + localMembersInjector.notifyListeners(t); return t; } catch (InvocationTargetException userException) { - Throwable cause = userException.getCause() != null - ? userException.getCause() - : userException; - throw errors.withSource(constructionProxy.getInjectionPoint()) - .errorInjectingConstructor(cause).toException(); + Throwable cause = userException.getCause() != null ? userException.getCause() : userException; + throw InternalProvisionException.errorInjectingConstructor(cause) + .addSource(constructionProxy.getInjectionPoint()); } finally { constructionContext.removeCurrentReference(); } diff --git a/core/src/com/google/inject/internal/ConstructorInjectorStore.java b/core/src/com/google/inject/internal/ConstructorInjectorStore.java index b8e48670..eb17a540 100644 --- a/core/src/com/google/inject/internal/ConstructorInjectorStore.java +++ b/core/src/com/google/inject/internal/ConstructorInjectorStore.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,35 +29,33 @@ import com.google.inject.spi.InjectionPoint; final class ConstructorInjectorStore { private final InjectorImpl injector; - private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache - = new FailableCache<InjectionPoint, ConstructorInjector<?>> () { - @Override - protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors) - throws ErrorsException { - return createConstructor(constructorInjector, errors); - } - }; + private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache = + new FailableCache<InjectionPoint, ConstructorInjector<?>>() { + @Override + protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors) + throws ErrorsException { + return createConstructor(constructorInjector, errors); + } + }; ConstructorInjectorStore(InjectorImpl injector) { this.injector = injector; } - /** - * Returns a new complete constructor injector with injection listeners registered. - */ + /** Returns a new complete constructor injector with injection listeners registered. */ public ConstructorInjector<?> get(InjectionPoint constructorInjector, Errors errors) throws ErrorsException { return cache.get(constructorInjector, errors); } - + /** * Purges an injection point from the cache. Use this only if the cache is not actually valid and * needs to be purged. (See issue 319 and * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is * necessary.) - * - * Returns true if the injector for that point was stored in the cache, false otherwise. + * + * <p>Returns true if the injector for that point was stored in the cache, false otherwise. */ boolean remove(InjectionPoint ip) { return cache.remove(ip); @@ -67,27 +65,32 @@ final class ConstructorInjectorStore { throws ErrorsException { int numErrorsBefore = errors.size(); - SingleParameterInjector<?>[] constructorParameterInjectors - = injector.getParametersInjectors(injectionPoint.getDependencies(), errors); + SingleParameterInjector<?>[] constructorParameterInjectors = + injector.getParametersInjectors(injectionPoint.getDependencies(), errors); @SuppressWarnings("unchecked") // the injector type agrees with the injection point type - MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>) injector.membersInjectorStore - .get(injectionPoint.getDeclaringType(), errors); + MembersInjectorImpl<T> membersInjector = + (MembersInjectorImpl<T>) + injector.membersInjectorStore.get(injectionPoint.getDeclaringType(), errors); /*if[AOP]*/ ImmutableList<MethodAspect> injectorAspects = injector.state.getMethodAspects(); - ImmutableList<MethodAspect> methodAspects = membersInjector.getAddedAspects().isEmpty() - ? injectorAspects - : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects())); - ConstructionProxyFactory<T> factory = new ProxyFactory<T>(injectionPoint, methodAspects); + ImmutableList<MethodAspect> methodAspects = + membersInjector.getAddedAspects().isEmpty() + ? injectorAspects + : ImmutableList.copyOf(concat(injectorAspects, membersInjector.getAddedAspects())); + ConstructionProxyFactory<T> factory = new ProxyFactory<>(injectionPoint, methodAspects); /*end[AOP]*/ /*if[NO_AOP] - ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<T>(injectionPoint); + ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<>(injectionPoint); end[NO_AOP]*/ errors.throwIfNewErrors(numErrorsBefore); - return new ConstructorInjector<T>(membersInjector.getInjectionPoints(), factory.create(), - constructorParameterInjectors, membersInjector); + return new ConstructorInjector<T>( + membersInjector.getInjectionPoints(), + factory.create(), + constructorParameterInjectors, + membersInjector); } } diff --git a/core/src/com/google/inject/internal/CreationListener.java b/core/src/com/google/inject/internal/CreationListener.java index 1779204c..53a61ee5 100644 --- a/core/src/com/google/inject/internal/CreationListener.java +++ b/core/src/com/google/inject/internal/CreationListener.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,4 +21,4 @@ interface CreationListener { /** Notifies that creation should happen. */ void notify(Errors errors); -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/CycleDetectingLock.java b/core/src/com/google/inject/internal/CycleDetectingLock.java index 690b1510..7b387b01 100644 --- a/core/src/com/google/inject/internal/CycleDetectingLock.java +++ b/core/src/com/google/inject/internal/CycleDetectingLock.java @@ -2,7 +2,6 @@ package com.google.inject.internal; import com.google.common.base.Preconditions; import com.google.common.base.Supplier; -import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableListMultimap; import com.google.common.collect.LinkedHashMultimap; import com.google.common.collect.ListMultimap; @@ -10,7 +9,6 @@ import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Multimap; import com.google.common.collect.Multimaps; - import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; @@ -21,166 +19,174 @@ import java.util.concurrent.locks.ReentrantLock; /** * Simplified version of {@link Lock} that is special due to how it handles deadlocks detection. * - * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due - * to its size and complexity. - * - * @param <ID> Lock identification provided by the client, is returned unmodified to the client - * when lock cycle is detected to identify it. Only toString() needs to be implemented. - * Lock references this object internally, - * for the purposes of Garbage Collection you should not use heavy IDs. - * Lock is referenced by a lock factory as long as it's owned by a thread. + * <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due to its size + * and complexity. * + * @param <ID> Lock identification provided by the client, is returned unmodified to the client when + * lock cycle is detected to identify it. Only toString() needs to be implemented. Lock + * references this object internally, for the purposes of Garbage Collection you should not use + * heavy IDs. Lock is referenced by a lock factory as long as it's owned by a thread. * @see SingletonScope * @see com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory - * * @author timofeyb (Timothy Basanov) */ interface CycleDetectingLock<ID> { /** - * Takes a lock in a blocking fashion in case no potential deadlocks are detected. - * If the lock was successfully owned, returns an empty map indicating no detected potential - * deadlocks. + * Takes a lock in a blocking fashion in case no potential deadlocks are detected. If the lock was + * successfully owned, returns an empty map indicating no detected potential deadlocks. * - * Otherwise, a map indicating threads involved in a potential deadlock are returned. - * Map is ordered by dependency cycle and lists locks for each thread that are part of - * the loop in order. Returned map is created atomically. + * <p>Otherwise, a map indicating threads involved in a potential deadlock are returned. Map is + * ordered by dependency cycle and lists locks for each thread that are part of the loop in order, + * the last lock in the list is the one that the thread is currently waiting for. Returned map is + * created atomically. * - * In case no cycle is detected performance is O(threads creating singletons), - * in case cycle is detected performance is O(singleton locks). + * <p>In case no cycle is detected performance is O(threads creating singletons), in case cycle is + * detected performance is O(singleton locks). */ - ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle(); + ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle(); - /** - * Unlocks previously locked lock. - */ + /** Unlocks previously locked lock. */ void unlock(); /** - * Wraps locks so they would never cause a deadlock. On each - * {@link CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles - * within locks created by the same factory. Either we detect a cycle and return it - * or take it atomically. + * Wraps locks so they would never cause a deadlock. On each {@link + * CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles within locks + * created by the same factory. Either we detect a cycle and return it or take it atomically. * - * <p>Important to note that we do not prevent deadlocks in the client code. As an example: - * Thread A takes lock L and creates singleton class CA depending on the singleton class CB. - * Meanwhile thread B is creating class CB and is waiting on the lock L. Issue happens - * due to client code creating interdependent classes and using locks, where - * no guarantees on the creation order from Guice are provided. + * <p>Important to note that we do not prevent deadlocks in the client code. As an example: Thread + * A takes lock L and creates singleton class CA depending on the singleton class CB. Meanwhile + * thread B is creating class CB and is waiting on the lock L. Issue happens due to client code + * creating interdependent classes and using locks, where no guarantees on the creation order from + * Guice are provided. * * <p>Instances of these locks are not intended to be exposed outside of {@link SingletonScope}. */ class CycleDetectingLockFactory<ID> { /** - * Specifies lock that thread is currently waiting on to own it. - * Used only for purposes of locks cycle detection. + * Specifies lock that thread is currently waiting on to own it. Used only for purposes of locks + * cycle detection. * - * Key: thread id - * Value: lock that is being waited on + * <ul> + * <li>Key: thread + * <li> Value: lock that is being waited on + * </ul> * - * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link Lock#lock} - * is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()} after - * {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}. + * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link + * Lock#lock} is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()} + * after {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}. * - * Same lock can be added for several threads in case all of them are trying to - * take it. + * <p>Same lock can be added for several threads in case all of them are trying to take it. * - * Guarded by {@code this}. + * <p>Guarded by {@code CycleDetectingLockFactory.class}. */ - private Map<Long, ReentrantCycleDetectingLock> lockThreadIsWaitingOn = Maps.newHashMap(); + private static Map<Thread, ReentrantCycleDetectingLock<?>> lockThreadIsWaitingOn = + Maps.newHashMap(); /** - * Lists locks that thread owns. - * Used only to populate locks in a potential cycle when it is detected. + * Lists locks that thread owns. Used only to populate locks in a potential cycle when it is + * detected. * - * Key: thread id - * Value: stack of locks that were owned. + * <ul> + * <li>Key: thread + * <li>Value: stack of locks that were owned. + * </ul> * - * Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock} - * is called. Element is removed inside {@link #unlock()} synchronously with - * {@link Lock#unlock()} call. + * <p>Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock} + * is called. Element is removed inside {@link #unlock()} synchronously with {@link + * Lock#unlock()} call. * - * Same lock can only be present several times for the same thread as locks are - * reentrant. Lock can not be owned by several different threads as the same time. + * <p>Same lock can only be present several times for the same thread as locks are reentrant. + * Lock can not be owned by several different threads as the same time. * - * Guarded by {@code this}. + * <p>Guarded by {@code CycleDetectingLockFactory.class}. */ - private final Multimap<Long, ReentrantCycleDetectingLock> locksOwnedByThread = + private static final Multimap<Thread, ReentrantCycleDetectingLock<?>> locksOwnedByThread = LinkedHashMultimap.create(); /** - * Creates new lock within this factory context. We can guarantee that locks created by - * the same factory would not deadlock. + * Creates new lock within this factory context. We can guarantee that locks created by the same + * factory would not deadlock. * - * @param newLockId lock id that would be used to report lock cycles if detected + * @param userLockId lock id that would be used to report lock cycles if detected */ - CycleDetectingLock<ID> create(ID newLockId) { - return new ReentrantCycleDetectingLock(newLockId, new ReentrantLock()); + CycleDetectingLock<ID> create(ID userLockId) { + return new ReentrantCycleDetectingLock<ID>(this, userLockId, new ReentrantLock()); } /** The implementation for {@link CycleDetectingLock}. */ - class ReentrantCycleDetectingLock implements CycleDetectingLock<ID> { + static class ReentrantCycleDetectingLock<ID> implements CycleDetectingLock<ID> { /** Underlying lock used for actual waiting when no potential deadlocks are detected. */ private final Lock lockImplementation; /** User id for this lock. */ private final ID userLockId; + /** Factory that was used to create this lock. */ + private final CycleDetectingLockFactory<ID> lockFactory; /** - * Thread id for the thread that owned this lock. Nullable. - * Guarded by {@code CycleDetectingLockFactory.this}. + * Thread that owns this lock. Nullable. Guarded by {@code CycleDetectingLockFactory.this}. */ - private Long lockOwnerThreadId = null; + private Thread lockOwnerThread = null; + /** - * Number of times that thread owned this lock. - * Guarded by {@code CycleDetectingLockFactory.this}. + * Number of times that thread owned this lock. Guarded by {@code + * CycleDetectingLockFactory.this}. */ private int lockReentranceCount = 0; - ReentrantCycleDetectingLock(ID userLockId, Lock lockImplementation) { + ReentrantCycleDetectingLock( + CycleDetectingLockFactory<ID> lockFactory, ID userLockId, Lock lockImplementation) { + this.lockFactory = lockFactory; this.userLockId = Preconditions.checkNotNull(userLockId, "userLockId"); - this.lockImplementation = Preconditions.checkNotNull( - lockImplementation, "lockImplementation"); + this.lockImplementation = + Preconditions.checkNotNull(lockImplementation, "lockImplementation"); } - @Override public ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle() { - final long currentThreadId = Thread.currentThread().getId(); - synchronized (CycleDetectingLockFactory.this) { + @Override + public ListMultimap<Thread, ID> lockOrDetectPotentialLocksCycle() { + final Thread currentThread = Thread.currentThread(); + synchronized (CycleDetectingLockFactory.class) { checkState(); - ListMultimap<Long, ID> locksInCycle = detectPotentialLocksCycle(); + // Add this lock to the waiting map to ensure it is included in any reported lock cycle. + lockThreadIsWaitingOn.put(currentThread, this); + ListMultimap<Thread, ID> locksInCycle = detectPotentialLocksCycle(); if (!locksInCycle.isEmpty()) { + // We aren't actually going to wait for this lock, so remove it from the map. + lockThreadIsWaitingOn.remove(currentThread); // potential deadlock is found, we don't try to take this lock return locksInCycle; } - lockThreadIsWaitingOn.put(currentThreadId, this); } // this may be blocking, but we don't expect it to cause a deadlock lockImplementation.lock(); - synchronized (CycleDetectingLockFactory.this) { + synchronized (CycleDetectingLockFactory.class) { // current thread is no longer waiting on this lock - lockThreadIsWaitingOn.remove(currentThreadId); + lockThreadIsWaitingOn.remove(currentThread); checkState(); // mark it as owned by us - lockOwnerThreadId = currentThreadId; + lockOwnerThread = currentThread; lockReentranceCount++; // add this lock to the list of locks owned by a current thread - locksOwnedByThread.put(currentThreadId, this); + locksOwnedByThread.put(currentThread, this); } // no deadlock is found, locking successful return ImmutableListMultimap.of(); } - @Override public void unlock() { - final long currentThreadId = Thread.currentThread().getId(); - synchronized (CycleDetectingLockFactory.this) { + @Override + public void unlock() { + final Thread currentThread = Thread.currentThread(); + synchronized (CycleDetectingLockFactory.class) { checkState(); - Preconditions.checkState(lockOwnerThreadId != null, - "Thread is trying to unlock a lock that is not locked"); - Preconditions.checkState(lockOwnerThreadId == currentThreadId, + Preconditions.checkState( + lockOwnerThread != null, "Thread is trying to unlock a lock that is not locked"); + Preconditions.checkState( + lockOwnerThread == currentThread, "Thread is trying to unlock a lock owned by another thread"); // releasing underlying lock @@ -190,12 +196,13 @@ interface CycleDetectingLock<ID> { lockReentranceCount--; if (lockReentranceCount == 0) { // we no longer own this lock - lockOwnerThreadId = null; - Preconditions.checkState(locksOwnedByThread.remove(currentThreadId, this), + lockOwnerThread = null; + Preconditions.checkState( + locksOwnedByThread.remove(currentThread, this), "Internal error: Can not find this lock in locks owned by a current thread"); - if (locksOwnedByThread.get(currentThreadId).isEmpty()) { + if (locksOwnedByThread.get(currentThread).isEmpty()) { // clearing memory - locksOwnedByThread.removeAll(currentThreadId); + locksOwnedByThread.removeAll(currentThread); } } } @@ -203,21 +210,26 @@ interface CycleDetectingLock<ID> { /** Check consistency of an internal state. */ void checkState() throws IllegalStateException { - final long currentThreadId = Thread.currentThread().getId(); - Preconditions.checkState(!lockThreadIsWaitingOn.containsKey(currentThreadId), + final Thread currentThread = Thread.currentThread(); + Preconditions.checkState( + !lockThreadIsWaitingOn.containsKey(currentThread), "Internal error: Thread should not be in a waiting thread on a lock now"); - if (lockOwnerThreadId != null) { + if (lockOwnerThread != null) { // check state of a locked lock - Preconditions.checkState(lockReentranceCount >= 0, + Preconditions.checkState( + lockReentranceCount >= 0, "Internal error: Lock ownership and reentrance count internal states do not match"); - Preconditions.checkState(locksOwnedByThread.get(lockOwnerThreadId).contains(this), + Preconditions.checkState( + locksOwnedByThread.get(lockOwnerThread).contains(this), "Internal error: Set of locks owned by a current thread and lock " + "ownership status do not match"); } else { // check state of a non locked lock - Preconditions.checkState(lockReentranceCount == 0, + Preconditions.checkState( + lockReentranceCount == 0, "Internal error: Reentrance count of a non locked lock is expect to be zero"); - Preconditions.checkState(!locksOwnedByThread.values().contains(this), + Preconditions.checkState( + !locksOwnedByThread.values().contains(this), "Internal error: Non locked lock should not be owned by any thread"); } } @@ -225,76 +237,93 @@ interface CycleDetectingLock<ID> { /** * Algorithm to detect a potential lock cycle. * - * For lock's thread owner check which lock is it trying to take. - * Repeat recursively. When current thread is found a potential cycle is detected. + * <p>For lock's thread owner check which lock is it trying to take. Repeat recursively. When + * current thread is found a potential cycle is detected. * * @see CycleDetectingLock#lockOrDetectPotentialLocksCycle() */ - private ListMultimap<Long, ID> detectPotentialLocksCycle() { - final long currentThreadId = Thread.currentThread().getId(); - if (lockOwnerThreadId == null || lockOwnerThreadId == currentThreadId) { + private ListMultimap<Thread, ID> detectPotentialLocksCycle() { + final Thread currentThread = Thread.currentThread(); + if (lockOwnerThread == null || lockOwnerThread == currentThread) { // if nobody owns this lock, lock cycle is impossible // if a current thread owns this lock, we let Guice to handle it return ImmutableListMultimap.of(); } - ListMultimap<Long, ID> potentialLocksCycle = Multimaps.newListMultimap( - new LinkedHashMap<Long, Collection<ID>>(), - new Supplier<List<ID>>() { - @Override - public List<ID> get() { - return Lists.newArrayList(); - } - }); + ListMultimap<Thread, ID> potentialLocksCycle = + Multimaps.newListMultimap( + new LinkedHashMap<Thread, Collection<ID>>(), + new Supplier<List<ID>>() { + @Override + public List<ID> get() { + return Lists.newArrayList(); + } + }); // lock that is a part of a potential locks cycle, starts with current lock - ReentrantCycleDetectingLock lockOwnerWaitingOn = this; + ReentrantCycleDetectingLock<?> lockOwnerWaitingOn = this; // try to find a dependency path between lock's owner thread and a current thread - while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThreadId != null) { - Long threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThreadId; + while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThread != null) { + Thread threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThread; // in case locks cycle exists lock we're waiting for is part of it - potentialLocksCycle.putAll(threadOwnerThreadWaits, - getAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn)); - - if (threadOwnerThreadWaits == currentThreadId) { + lockOwnerWaitingOn = + addAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn, potentialLocksCycle); + if (threadOwnerThreadWaits == currentThread) { // owner thread depends on current thread, cycle detected return potentialLocksCycle; } - // going for the next thread we wait on indirectly - lockOwnerWaitingOn = lockThreadIsWaitingOn.get(threadOwnerThreadWaits); } // no dependency path from an owner thread to a current thread return ImmutableListMultimap.of(); } - /** Return locks owned by a thread after a lock specified, inclusive. */ - private List<ID> getAllLockIdsAfter(long threadId, ReentrantCycleDetectingLock lock) { - List<ID> ids = Lists.newArrayList(); + /** + * Adds all locks held by the given thread that are after the given lock and then returns the + * lock the thread is currently waiting on, if any + */ + private ReentrantCycleDetectingLock<?> addAllLockIdsAfter( + Thread thread, + ReentrantCycleDetectingLock<?> lock, + ListMultimap<Thread, ID> potentialLocksCycle) { boolean found = false; - Collection<ReentrantCycleDetectingLock> ownedLocks = locksOwnedByThread.get(threadId); - Preconditions.checkNotNull(ownedLocks, - "Internal error: No locks were found taken by a thread"); - for (ReentrantCycleDetectingLock ownedLock : ownedLocks) { + Collection<ReentrantCycleDetectingLock<?>> ownedLocks = locksOwnedByThread.get(thread); + Preconditions.checkNotNull( + ownedLocks, "Internal error: No locks were found taken by a thread"); + for (ReentrantCycleDetectingLock<?> ownedLock : ownedLocks) { if (ownedLock == lock) { found = true; } - if (found) { - ids.add(ownedLock.userLockId); + if (found && ownedLock.lockFactory == this.lockFactory) { + // All locks are stored in a shared map therefore there is no way to + // enforce type safety. We know that our cast is valid as we check for a lock's + // factory. If the lock was generated by the + // same factory it has to have same type as the current lock. + @SuppressWarnings("unchecked") + ID userLockId = (ID) ownedLock.userLockId; + potentialLocksCycle.put(thread, userLockId); } } - Preconditions.checkState(found, "Internal error: We can not find locks that " - + "created a cycle that we detected"); - return ids; + Preconditions.checkState( + found, + "Internal error: We can not find locks that created a cycle that we detected"); + ReentrantCycleDetectingLock<?> unownedLock = lockThreadIsWaitingOn.get(thread); + // If this thread is waiting for a lock add it to the cycle and return it + if (unownedLock != null && unownedLock.lockFactory == this.lockFactory) { + @SuppressWarnings("unchecked") + ID typed = (ID) unownedLock.userLockId; + potentialLocksCycle.put(thread, typed); + } + return unownedLock; } - @Override public String toString() { + @Override + public String toString() { // copy is made to prevent a data race // no synchronization is used, potentially stale data, should be good enough - Long localLockOwnerThreadId = this.lockOwnerThreadId; - if (localLockOwnerThreadId != null) { - return String.format("CycleDetectingLock[%s][locked by %s]", - userLockId, localLockOwnerThreadId); + Thread thread = this.lockOwnerThread; + if (thread != null) { + return String.format("%s[%s][locked by %s]", super.toString(), userLockId, thread); } else { - return String.format("CycleDetectingLock[%s][unlocked]", userLockId); + return String.format("%s[%s][unlocked]", super.toString(), userLockId); } } } diff --git a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java index 947b49a2..d8cfc182 100644 --- a/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java +++ b/core/src/com/google/inject/internal/DefaultConstructionProxyFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,10 +16,9 @@ package com.google.inject.internal; +import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableMap; -import com.google.inject.internal.BytecodeGen.Visibility; import com.google.inject.spi.InjectionPoint; - import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -35,73 +34,119 @@ final class DefaultConstructionProxyFactory<T> implements ConstructionProxyFacto private final InjectionPoint injectionPoint; - /** - * @param injectionPoint an injection point whose member is a constructor of {@code T}. - */ + /** @param injectionPoint an injection point whose member is a constructor of {@code T}. */ DefaultConstructionProxyFactory(InjectionPoint injectionPoint) { this.injectionPoint = injectionPoint; } + @Override public ConstructionProxy<T> create() { @SuppressWarnings("unchecked") // the injection point is for a constructor of T final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember(); - // Use FastConstructor if the constructor is public. - if (Modifier.isPublic(constructor.getModifiers())) { - Class<T> classToConstruct = constructor.getDeclaringClass(); - /*if[AOP]*/ - try { - final net.sf.cglib.reflect.FastConstructor fastConstructor - = BytecodeGen.newFastClass(classToConstruct, Visibility.forMember(constructor)) - .getConstructor(constructor); - - return new ConstructionProxy<T>() { - @SuppressWarnings("unchecked") - public T newInstance(Object... arguments) throws InvocationTargetException { - return (T) fastConstructor.newInstance(arguments); - } - public InjectionPoint getInjectionPoint() { - return injectionPoint; - } - public Constructor<T> getConstructor() { - return constructor; - } - public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> - getMethodInterceptors() { - return ImmutableMap.of(); - } - }; - } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */} - /*end[AOP]*/ - if (!Modifier.isPublic(classToConstruct.getModifiers())) { - constructor.setAccessible(true); + /*if[AOP]*/ + try { + net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(constructor); + if (fc != null) { + int index = fc.getIndex(constructor.getParameterTypes()); + // We could just fall back to reflection in this case but I believe this should actually + // be impossible. + Preconditions.checkArgument( + index >= 0, "Could not find constructor %s in fast class", constructor); + return new FastClassProxy<T>(injectionPoint, constructor, fc, index); } - } else { - constructor.setAccessible(true); + } catch (net.sf.cglib.core.CodeGenerationException e) { + /* fall-through */ } + /*end[AOP]*/ - return new ConstructionProxy<T>() { - public T newInstance(Object... arguments) throws InvocationTargetException { - try { - return constructor.newInstance(arguments); - } catch (InstantiationException e) { - throw new AssertionError(e); // shouldn't happen, we know this is a concrete type - } catch (IllegalAccessException e) { - throw new AssertionError(e); // a security manager is blocking us, we're hosed - } - } - public InjectionPoint getInjectionPoint() { - return injectionPoint; - } - public Constructor<T> getConstructor() { - return constructor; + return new ReflectiveProxy<T>(injectionPoint, constructor); + } + + /*if[AOP]*/ + /** A {@link ConstructionProxy} that uses FastClass to invoke the constructor. */ + private static final class FastClassProxy<T> implements ConstructionProxy<T> { + final InjectionPoint injectionPoint; + final Constructor<T> constructor; + final net.sf.cglib.reflect.FastClass fc; + final int index; + + private FastClassProxy( + InjectionPoint injectionPoint, + Constructor<T> constructor, + net.sf.cglib.reflect.FastClass fc, + int index) { + this.injectionPoint = injectionPoint; + this.constructor = constructor; + this.fc = fc; + this.index = index; + } + + @Override + @SuppressWarnings("unchecked") + public T newInstance(Object... arguments) throws InvocationTargetException { + // Use this method instead of FastConstructor to save a stack frame + return (T) fc.newInstance(index, arguments); + } + + @Override + public InjectionPoint getInjectionPoint() { + return injectionPoint; + } + + @Override + public Constructor<T> getConstructor() { + return constructor; + } + + @Override + public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> + getMethodInterceptors() { + return ImmutableMap.of(); + } + } + /*end[AOP]*/ + + private static final class ReflectiveProxy<T> implements ConstructionProxy<T> { + final Constructor<T> constructor; + final InjectionPoint injectionPoint; + + ReflectiveProxy(InjectionPoint injectionPoint, Constructor<T> constructor) { + if (!Modifier.isPublic(constructor.getDeclaringClass().getModifiers()) + || !Modifier.isPublic(constructor.getModifiers())) { + constructor.setAccessible(true); } - /*if[AOP]*/ - public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> - getMethodInterceptors() { - return ImmutableMap.of(); + this.injectionPoint = injectionPoint; + this.constructor = constructor; + } + + @Override + public T newInstance(Object... arguments) throws InvocationTargetException { + try { + return constructor.newInstance(arguments); + } catch (InstantiationException e) { + throw new AssertionError(e); // shouldn't happen, we know this is a concrete type + } catch (IllegalAccessException e) { + throw new AssertionError(e); // a security manager is blocking us, we're hosed } - /*end[AOP]*/ - }; + } + + @Override + public InjectionPoint getInjectionPoint() { + return injectionPoint; + } + + @Override + public Constructor<T> getConstructor() { + return constructor; + } + + /*if[AOP]*/ + @Override + public ImmutableMap<Method, List<org.aopalliance.intercept.MethodInterceptor>> + getMethodInterceptors() { + return ImmutableMap.of(); + } + /*end[AOP]*/ } } diff --git a/core/src/com/google/inject/internal/DeferredLookups.java b/core/src/com/google/inject/internal/DeferredLookups.java index 049c9a8d..2c374060 100644 --- a/core/src/com/google/inject/internal/DeferredLookups.java +++ b/core/src/com/google/inject/internal/DeferredLookups.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ import com.google.inject.TypeLiteral; import com.google.inject.spi.Element; import com.google.inject.spi.MembersInjectorLookup; import com.google.inject.spi.ProviderLookup; - import java.util.List; /** @@ -41,22 +40,22 @@ final class DeferredLookups implements Lookups { this.injector = injector; } - /** - * Initialize the specified lookups, either immediately or when the injector is created. - */ + /** Initialize the specified lookups, either immediately or when the injector is created. */ void initialize(Errors errors) { injector.lookups = injector; new LookupProcessor(errors).process(injector, lookups); } + @Override public <T> Provider<T> getProvider(Key<T> key) { - ProviderLookup<T> lookup = new ProviderLookup<T>(key, key); + ProviderLookup<T> lookup = new ProviderLookup<>(key, key); lookups.add(lookup); return lookup.getProvider(); } + @Override public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) { - MembersInjectorLookup<T> lookup = new MembersInjectorLookup<T>(type, type); + MembersInjectorLookup<T> lookup = new MembersInjectorLookup<>(type, type); lookups.add(lookup); return lookup.getMembersInjector(); } diff --git a/core/src/com/google/inject/internal/DelayedInitialize.java b/core/src/com/google/inject/internal/DelayedInitialize.java index 82a84634..5534f508 100644 --- a/core/src/com/google/inject/internal/DelayedInitialize.java +++ b/core/src/com/google/inject/internal/DelayedInitialize.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,13 @@ package com.google.inject.internal; /** - * Something that needs some delayed initialization, typically - * a binding or internal factory that needs to be created & put - * into the bindings map & then initialized later. - * + * Something that needs some delayed initialization, typically a binding or internal factory that + * needs to be created & put into the bindings map & then initialized later. + * * @author sameb@google.com (Sam Berlin) */ interface DelayedInitialize { - + /** Initializes this binding, throwing any errors if necessary. */ void initialize(InjectorImpl injector, Errors errors) throws ErrorsException; - } diff --git a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java index 32441ff6..f78262f6 100644 --- a/core/src/com/google/inject/internal/DelegatingInvocationHandler.java +++ b/core/src/com/google/inject/internal/DelegatingInvocationHandler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,9 +16,7 @@ package com.google.inject.internal; - import com.google.common.base.Preconditions; - import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -29,16 +27,18 @@ class DelegatingInvocationHandler<T> implements InvocationHandler { private T delegate; - public Object invoke(Object proxy, Method method, Object[] args) - throws Throwable { + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { try { // checking volatile field for synchronization - Preconditions.checkState(initialized, + Preconditions.checkState( + initialized, "This is a proxy used to support" + " circular references. The object we're" + " proxying is not constructed yet. Please wait until after" + " injection has completed to use this object."); - Preconditions.checkNotNull(delegate, + Preconditions.checkNotNull( + delegate, "This is a proxy used to support" + " circular references. The object we're " + " proxying is initialized to null." diff --git a/core/src/com/google/inject/internal/Element.java b/core/src/com/google/inject/internal/Element.java new file mode 100644 index 00000000..5b738ef1 --- /dev/null +++ b/core/src/com/google/inject/internal/Element.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.internal; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.BindingAnnotation; +import java.lang.annotation.Retention; + +/** + * An internal binding annotation applied to each element in a multibinding. All elements are + * assigned a globally-unique id to allow different modules to contribute multibindings + * independently. + * + * @author jessewilson@google.com (Jesse Wilson) + */ +@Retention(RUNTIME) +@BindingAnnotation +@interface Element { + + enum Type { + MAPBINDER, + MULTIBINDER; + } + + String setName(); + + int uniqueId(); + + Type type(); + + String keyType(); +} diff --git a/core/src/com/google/inject/internal/EncounterImpl.java b/core/src/com/google/inject/internal/EncounterImpl.java index 8aa3e948..4fb8575e 100644 --- a/core/src/com/google/inject/internal/EncounterImpl.java +++ b/core/src/com/google/inject/internal/EncounterImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,13 +30,10 @@ import com.google.inject.matcher.Matchers; import com.google.inject.spi.InjectionListener; import com.google.inject.spi.Message; import com.google.inject.spi.TypeEncounter; - import java.lang.reflect.Method; import java.util.List; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ final class EncounterImpl<T> implements TypeEncounter<T> { private final Errors errors; @@ -59,12 +56,12 @@ final class EncounterImpl<T> implements TypeEncounter<T> { /*if[AOP]*/ ImmutableList<MethodAspect> getAspects() { - return aspects == null - ? ImmutableList.<MethodAspect>of() - : ImmutableList.copyOf(aspects); + return aspects == null ? ImmutableList.<MethodAspect>of() : ImmutableList.copyOf(aspects); } - public void bindInterceptor(Matcher<? super Method> methodMatcher, + @Override + public void bindInterceptor( + Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors) { checkState(valid, "Encounters may not be used after hear() returns."); @@ -89,6 +86,7 @@ final class EncounterImpl<T> implements TypeEncounter<T> { : ImmutableSet.copyOf(injectionListeners); } + @Override public void register(MembersInjector<? super T> membersInjector) { checkState(valid, "Encounters may not be used after hear() returns."); @@ -99,6 +97,7 @@ final class EncounterImpl<T> implements TypeEncounter<T> { membersInjectors.add(membersInjector); } + @Override public void register(InjectionListener<? super T> injectionListener) { checkState(valid, "Encounters may not be used after hear() returns."); @@ -109,36 +108,43 @@ final class EncounterImpl<T> implements TypeEncounter<T> { injectionListeners.add(injectionListener); } + @Override public void addError(String message, Object... arguments) { checkState(valid, "Encounters may not be used after hear() returns."); errors.addMessage(message, arguments); } + @Override public void addError(Throwable t) { checkState(valid, "Encounters may not be used after hear() returns."); errors.errorInUserCode(t, "An exception was caught and reported. Message: %s", t.getMessage()); } + @Override public void addError(Message message) { checkState(valid, "Encounters may not be used after hear() returns."); errors.addMessage(message); } + @Override public <T> Provider<T> getProvider(Key<T> key) { checkState(valid, "Encounters may not be used after hear() returns."); return lookups.getProvider(key); } + @Override public <T> Provider<T> getProvider(Class<T> type) { return getProvider(Key.get(type)); } + @Override public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) { checkState(valid, "Encounters may not be used after hear() returns."); return lookups.getMembersInjector(typeLiteral); } + @Override public <T> MembersInjector<T> getMembersInjector(Class<T> type) { return getMembersInjector(TypeLiteral.get(type)); } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/ErrorHandler.java b/core/src/com/google/inject/internal/ErrorHandler.java index b448eb7c..c0ffd014 100644 --- a/core/src/com/google/inject/internal/ErrorHandler.java +++ b/core/src/com/google/inject/internal/ErrorHandler.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,13 +25,9 @@ import com.google.inject.spi.Message; */ interface ErrorHandler { - /** - * Handles an error. - */ + /** Handles an error. */ void handle(Object source, Errors errors); - /** - * Handles a user-reported error. - */ + /** Handles a user-reported error. */ void handle(Message message); } diff --git a/core/src/com/google/inject/internal/Errors.java b/core/src/com/google/inject/internal/Errors.java index 7527e2a1..7269f120 100644 --- a/core/src/com/google/inject/internal/Errors.java +++ b/core/src/com/google/inject/internal/Errors.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,45 +20,34 @@ import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Ordering; -import com.google.common.collect.Sets; +import com.google.common.primitives.Primitives; +import com.google.inject.Binding; import com.google.inject.ConfigurationException; import com.google.inject.CreationException; -import com.google.inject.Guice; +import com.google.inject.Injector; import com.google.inject.Key; -import com.google.inject.MembersInjector; -import com.google.inject.Provider; -import com.google.inject.Provides; import com.google.inject.ProvisionException; import com.google.inject.Scope; import com.google.inject.TypeLiteral; -import com.google.inject.internal.util.Classes; import com.google.inject.internal.util.SourceProvider; -import com.google.inject.internal.util.StackTraceElements; -import com.google.inject.spi.Dependency; import com.google.inject.spi.ElementSource; -import com.google.inject.spi.InjectionListener; -import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.Message; import com.google.inject.spi.ScopeBinding; import com.google.inject.spi.TypeConverterBinding; import com.google.inject.spi.TypeListenerBinding; - -import java.io.PrintWriter; import java.io.Serializable; -import java.io.StringWriter; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Type; +import java.util.ArrayList; import java.util.Collection; import java.util.Formatter; import java.util.List; +import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.logging.Level; -import java.util.logging.Logger; /** * A collection of error messages. If this type is passed as a method parameter, the method is @@ -77,30 +66,58 @@ import java.util.logging.Logger; */ public final class Errors implements Serializable { - private static final Logger logger = Logger.getLogger(Guice.class.getName()); - - private static final Set<Dependency<?>> warnedDependencies = - Sets.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>()); + /** When a binding is not found, show at most this many bindings with the same type */ + private static final int MAX_MATCHING_TYPES_REPORTED = 3; + /** When a binding is not found, show at most this many bindings that have some similarities */ + private static final int MAX_RELATED_TYPES_REPORTED = 3; /** - * The root errors object. Used to access the list of error messages. + * Throws a ConfigurationException with an NullPointerExceptions as the cause if the given + * reference is {@code null}. */ - private final Errors root; + static <T> T checkNotNull(T reference, String name) { + if (reference != null) { + return reference; + } + + NullPointerException npe = new NullPointerException(name); + throw new ConfigurationException(ImmutableSet.of(new Message(npe.toString(), npe))); + } /** - * The parent errors object. Used to obtain the chain of source objects. + * Throws a ConfigurationException with a formatted {@link Message} if this condition is {@code + * false}. */ - private final Errors parent; + static void checkConfiguration(boolean condition, String format, Object... args) { + if (condition) { + return; + } + + throw new ConfigurationException(ImmutableSet.of(new Message(Errors.format(format, args)))); + } /** - * The leaf source for errors added here. + * If the key is unknown and it is one of these types, it generally means there is a missing + * annotation. */ + private static final ImmutableSet<Class<?>> COMMON_AMBIGUOUS_TYPES = + ImmutableSet.<Class<?>>builder() + .add(Object.class) + .add(String.class) + .addAll(Primitives.allWrapperTypes()) + .build(); + + /** The root errors object. Used to access the list of error messages. */ + private final Errors root; + + /** The parent errors object. Used to obtain the chain of source objects. */ + private final Errors parent; + + /** The leaf source for errors added here. */ private final Object source; - /** - * null unless (root == this) and error messages exist. Never an empty list. - */ + /** null unless (root == this) and error messages exist. Never an empty list. */ private List<Message> errors; // lazy, use getErrorsForAdd() public Errors() { @@ -121,9 +138,7 @@ public final class Errors implements Serializable { this.source = source; } - /** - * Returns an instance that uses {@code source} as a reference point for newly added errors. - */ + /** Returns an instance that uses {@code source} as a reference point for newly added errors. */ public Errors withSource(Object source) { return source == this.source || source == SourceProvider.UNKNOWN_SOURCE ? this @@ -131,69 +146,166 @@ public final class Errors implements Serializable { } /** - * We use a fairly generic error message here. The motivation is to share the - * same message for both bind time errors: + * We use a fairly generic error message here. The motivation is to share the same message for + * both bind time errors: + * * <pre><code>Guice.createInjector(new AbstractModule() { * public void configure() { * bind(Runnable.class); * } * }</code></pre> + * * ...and at provide-time errors: + * * <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre> - * Otherwise we need to know who's calling when resolving a just-in-time - * binding, which makes things unnecessarily complex. + * + * Otherwise we need to know who's calling when resolving a just-in-time binding, which makes + * things unnecessarily complex. */ public Errors missingImplementation(Key key) { return addMessage("No implementation for %s was bound.", key); } - public Errors jitDisabled(Key key) { + /** Within guice's core, allow for better missing binding messages */ + <T> Errors missingImplementationWithHint(Key<T> key, Injector injector) { + StringBuilder sb = new StringBuilder(); + + sb.append(format("No implementation for %s was bound.", key)); + + // Keys which have similar strings as the desired key + List<String> possibleMatches = new ArrayList<>(); + + // Check for other keys that may have the same type, + // but not the same annotation + TypeLiteral<T> type = key.getTypeLiteral(); + List<Binding<T>> sameTypes = injector.findBindingsByType(type); + if (!sameTypes.isEmpty()) { + sb.append(format("%n Did you mean?")); + int howMany = Math.min(sameTypes.size(), MAX_MATCHING_TYPES_REPORTED); + for (int i = 0; i < howMany; ++i) { + // TODO: Look into a better way to prioritize suggestions. For example, possbily + // use levenshtein distance of the given annotation vs actual annotation. + sb.append(format("%n * %s", sameTypes.get(i).getKey())); + } + int remaining = sameTypes.size() - MAX_MATCHING_TYPES_REPORTED; + if (remaining > 0) { + String plural = (remaining == 1) ? "" : "s"; + sb.append(format("%n %d more binding%s with other annotations.", remaining, plural)); + } + } else { + // For now, do a simple substring search for possibilities. This can help spot + // issues when there are generics being used (such as a wrapper class) and the + // user has forgotten they need to bind based on the wrapper, not the underlying + // class. In the future, consider doing a strict in-depth type search. + // TODO: Look into a better way to prioritize suggestions. For example, possbily + // use levenshtein distance of the type literal strings. + String want = type.toString(); + Map<Key<?>, Binding<?>> bindingMap = injector.getAllBindings(); + for (Key<?> bindingKey : bindingMap.keySet()) { + String have = bindingKey.getTypeLiteral().toString(); + if (have.contains(want) || want.contains(have)) { + Formatter fmt = new Formatter(); + Messages.formatSource(fmt, bindingMap.get(bindingKey).getSource()); + String match = String.format("%s bound%s", convert(bindingKey), fmt.toString()); + possibleMatches.add(match); + // TODO: Consider a check that if there are more than some number of results, + // don't suggest any. + if (possibleMatches.size() > MAX_RELATED_TYPES_REPORTED) { + // Early exit if we have found more than we need. + break; + } + } + } + + if ((possibleMatches.size() > 0) && (possibleMatches.size() <= MAX_RELATED_TYPES_REPORTED)) { + sb.append(format("%n Did you mean?")); + for (String possibleMatch : possibleMatches) { + sb.append(format("%n %s", possibleMatch)); + } + } + } + + // If where are no possibilities to suggest, then handle the case of missing + // annotations on simple types. This is usually a bad idea. + if (sameTypes.isEmpty() + && possibleMatches.isEmpty() + && key.getAnnotation() == null + && COMMON_AMBIGUOUS_TYPES.contains(key.getTypeLiteral().getRawType())) { + // We don't recommend using such simple types without annotations. + sb.append(format("%nThe key seems very generic, did you forget an annotation?")); + } + + return addMessage(sb.toString()); + } + + public Errors jitDisabled(Key<?> key) { return addMessage("Explicit bindings are required and %s is not explicitly bound.", key); } public Errors jitDisabledInParent(Key<?> key) { return addMessage( "Explicit bindings are required and %s would be bound in a parent injector.%n" - + "Please add an explicit binding for it, either in the child or the parent.", + + "Please add an explicit binding for it, either in the child or the parent.", key); } public Errors atInjectRequired(Class clazz) { return addMessage( "Explicit @Inject annotations are required on constructors," - + " but %s has no constructors annotated with @Inject.", + + " but %s has no constructors annotated with @Inject.", clazz); } - public Errors converterReturnedNull(String stringValue, Object source, - TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) { - return addMessage("Received null converting '%s' (bound at %s) to %s%n" - + " using %s.", + public Errors converterReturnedNull( + String stringValue, + Object source, + TypeLiteral<?> type, + TypeConverterBinding typeConverterBinding) { + return addMessage( + "Received null converting '%s' (bound at %s) to %s%n using %s.", stringValue, convert(source), type, typeConverterBinding); } - public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type, - TypeConverterBinding typeConverterBinding, Object converted) { - return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n" - + " using %s.%n" - + " Converter returned %s.", + public Errors conversionTypeError( + String stringValue, + Object source, + TypeLiteral<?> type, + TypeConverterBinding typeConverterBinding, + Object converted) { + return addMessage( + "Type mismatch converting '%s' (bound at %s) to %s%n" + + " using %s.%n" + + " Converter returned %s.", stringValue, convert(source), type, typeConverterBinding, converted); } - public Errors conversionError(String stringValue, Object source, - TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) { - return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n" - + " using %s.%n" - + " Reason: %s", - stringValue, convert(source), type, typeConverterBinding, cause); - } - - public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type, - TypeConverterBinding a, TypeConverterBinding b) { - return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n" - + " %s and%n" - + " %s.%n" - + " Please adjust your type converter configuration to avoid overlapping matches.", + public Errors conversionError( + String stringValue, + Object source, + TypeLiteral<?> type, + TypeConverterBinding typeConverterBinding, + RuntimeException cause) { + return errorInUserCode( + cause, + "Error converting '%s' (bound at %s) to %s%n using %s.%n Reason: %s", + stringValue, + convert(source), + type, + typeConverterBinding, + cause); + } + + public Errors ambiguousTypeConversion( + String stringValue, + Object source, + TypeLiteral<?> type, + TypeConverterBinding a, + TypeConverterBinding b) { + return addMessage( + "Multiple converters can convert '%s' (bound at %s) to %s:%n" + + " %s and%n" + + " %s.%n" + + " Please adjust your type converter configuration to avoid overlapping matches.", stringValue, convert(source), type, a, b); } @@ -201,11 +313,6 @@ public final class Errors implements Serializable { return addMessage("Binding to Provider is not allowed."); } - public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType, - Class<?> type) { - return addMessage("%s doesn't provide instances of %s.", providerType, type); - } - public Errors notASubtype(Class<?> implementationType, Class<?> type) { return addMessage("%s doesn't extend %s.", implementationType, type); } @@ -227,8 +334,9 @@ public final class Errors implements Serializable { } public Errors optionalConstructor(Constructor constructor) { - return addMessage("%s is annotated @Inject(optional=true), " - + "but constructors cannot be optional.", constructor); + return addMessage( + "%s is annotated @Inject(optional=true), but constructors cannot be optional.", + constructor); } public Errors cannotBindToGuiceType(String simpleName) { @@ -241,13 +349,17 @@ public final class Errors implements Serializable { public Errors scopeAnnotationOnAbstractType( Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) { - return addMessage("%s is annotated with %s, but scope annotations are not supported " - + "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source)); + return addMessage( + "%s is annotated with %s, but scope annotations are not supported " + + "for abstract types.%n Bound at %s.", + type, scopeAnnotation, convert(source)); } public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) { - return addMessage("%s is annotated with %s, but binding annotations should be applied " - + "to its parameters instead.", member, bindingAnnotation); + return addMessage( + "%s is annotated with %s, but binding annotations should be applied " + + "to its parameters instead.", + member, bindingAnnotation); } private static final String CONSTRUCTOR_RULES = @@ -255,22 +367,24 @@ public final class Errors implements Serializable { + "annotated with @Inject or a zero-argument constructor that is not private."; public Errors missingConstructor(Class<?> implementation) { - return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES, - implementation); + return addMessage( + "Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES, implementation); } public Errors tooManyConstructors(Class<?> implementation) { - return addMessage("%s has more than one constructor annotated with @Inject. " - + CONSTRUCTOR_RULES, implementation); + return addMessage( + "%s has more than one constructor annotated with @Inject. " + CONSTRUCTOR_RULES, + implementation); } public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) { return addMessage("%s does not define %s", type, constructor); } - public Errors duplicateScopes(ScopeBinding existing, - Class<? extends Annotation> annotationType, Scope scope) { - return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.", + public Errors duplicateScopes( + ScopeBinding existing, Class<? extends Annotation> annotationType, Scope scope) { + return addMessage( + "Scope %s is already bound to %s at %s.%n Cannot bind %s.", existing.getScope(), annotationType, existing.getSource(), scope); } @@ -283,14 +397,17 @@ public final class Errors implements Serializable { } public Errors cannotInjectInnerClass(Class<?> type) { - return addMessage("Injecting into inner classes is not supported. " - + "Please use a 'static' class (top-level or nested) instead of %s.", type); + return addMessage( + "Injecting into inner classes is not supported. " + + "Please use a 'static' class (top-level or nested) instead of %s.", + type); } - public Errors duplicateBindingAnnotations(Member member, - Class<? extends Annotation> a, Class<? extends Annotation> b) { - return addMessage("%s has more than one annotation annotated with @BindingAnnotation: " - + "%s and %s", member, a, b); + public Errors duplicateBindingAnnotations( + Member member, Class<? extends Annotation> a, Class<? extends Annotation> b) { + return addMessage( + "%s has more than one annotation annotated with @BindingAnnotation: %s and %s", + member, a, b); } public Errors staticInjectionOnInterface(Class<?> clazz) { @@ -327,7 +444,8 @@ public final class Errors implements Serializable { } public Errors jitBindingAlreadySet(Key<?> key) { - return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key); + return addMessage( + "A just-in-time binding to %s was already configured on a parent injector.", key); } public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) { @@ -339,53 +457,32 @@ public final class Errors implements Serializable { allSources.format("%n bound at %s", source); } } - Errors errors = addMessage( - "Unable to create binding for %s." - + " It was already configured on one or more child injectors or private modules" - + "%s%n" - + " If it was in a PrivateModule, did you forget to expose the binding?", - key, allSources.out()); + Errors errors = + addMessage( + "Unable to create binding for %s." + + " It was already configured on one or more child injectors or private modules" + + "%s%n" + + " If it was in a PrivateModule, did you forget to expose the binding?", + key, allSources.out()); return errors; } public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) { return addMessage( "A binding to %s was already configured at %s and an error was thrown " - + "while checking duplicate bindings. Error: %s", + + "while checking duplicate bindings. Error: %s", key, convert(source), t); } - public Errors errorInjectingMethod(Throwable cause) { - return errorInUserCode(cause, "Error injecting method, %s", cause); - } - - public Errors errorNotifyingTypeListener(TypeListenerBinding listener, - TypeLiteral<?> type, Throwable cause) { - return errorInUserCode(cause, - "Error notifying TypeListener %s (bound at %s) of %s.%n" - + " Reason: %s", - listener.getListener(), convert(listener.getSource()), type, cause); - } - - public Errors errorInjectingConstructor(Throwable cause) { - return errorInUserCode(cause, "Error injecting constructor, %s", cause); - } - - public Errors errorInProvider(RuntimeException runtimeException) { - Throwable unwrapped = unwrap(runtimeException); - return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped); - } - - public Errors errorInUserInjector( - MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) { - return errorInUserCode(cause, "Error injecting %s using %s.%n" - + " Reason: %s", type, listener, cause); - } - - public Errors errorNotifyingInjectionListener( - InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) { - return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n" - + " Reason: %s", listener, type, cause); + public Errors errorNotifyingTypeListener( + TypeListenerBinding listener, TypeLiteral<?> type, Throwable cause) { + return errorInUserCode( + cause, + "Error notifying TypeListener %s (bound at %s) of %s.%n Reason: %s", + listener.getListener(), + convert(listener.getSource()), + type, + cause); } public Errors exposedButNotBound(Key<?> key) { @@ -422,14 +519,6 @@ public final class Errors implements Serializable { } } - private Throwable unwrap(RuntimeException runtimeException) { - if(runtimeException instanceof Exceptions.UnhandledCheckedUserException) { - return runtimeException.getCause(); - } else { - return runtimeException; - } - } - public Errors cannotInjectRawProvider() { return addMessage("Cannot inject a Provider that has no type parameter"); } @@ -446,18 +535,6 @@ public final class Errors implements Serializable { return addMessage("Cannot inject a TypeLiteral that has no type parameter"); } - public Errors cannotSatisfyCircularDependency(Class<?> expectedType) { - return addMessage( - "Tried proxying %s to support a circular dependency, but it is not an interface.", - expectedType); - } - - public Errors circularProxiesDisabled(Class<?> expectedType) { - return addMessage( - "Tried proxying %s to support a circular dependency, but circular proxies are disabled.", - expectedType); - } - public void throwCreationExceptionIfErrorsExist() { if (!hasErrors()) { return; @@ -474,6 +551,7 @@ public final class Errors implements Serializable { throw new ConfigurationException(getMessages()); } + // Guice no longer calls this, but external callers do public void throwProvisionExceptionIfErrorsExist() { if (!hasErrors()) { return; @@ -482,16 +560,10 @@ public final class Errors implements Serializable { throw new ProvisionException(getMessages()); } - private Message merge(Message message) { - List<Object> sources = Lists.newArrayList(); - sources.addAll(getSources()); - sources.addAll(message.getSources()); - return new Message(sources, message.getMessage(), message.getCause()); - } - public Errors merge(Collection<Message> messages) { + List<Object> sources = getSources(); for (Message message : messages) { - addMessage(merge(message)); + addMessage(Messages.mergeSources(sources, message)); } return this; } @@ -505,7 +577,12 @@ public final class Errors implements Serializable { return this; } - public List<Object> getSources() { + public Errors merge(InternalProvisionException ipe) { + merge(ipe.getErrors()); + return this; + } + + private List<Object> getSources() { List<Object> sources = Lists.newArrayList(); for (Errors e = this; e != null; e = e.parent) { if (e.source != SourceProvider.UNKNOWN_SOURCE) { @@ -536,8 +613,7 @@ public final class Errors implements Serializable { } private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) { - String message = format(messageFormat, arguments); - addMessage(new Message(getSources(), message, cause)); + addMessage(Messages.create(cause, getSources(), messageFormat, arguments)); return this; } @@ -549,11 +625,9 @@ public final class Errors implements Serializable { return this; } + // TODO(lukes): inline into callers public static String format(String messageFormat, Object... arguments) { - for (int i = 0; i < arguments.length; i++) { - arguments[i] = Errors.convert(arguments[i]); - } - return String.format(messageFormat, arguments); + return Messages.format(messageFormat, arguments); } public List<Message> getMessages() { @@ -569,274 +643,23 @@ public final class Errors implements Serializable { }.sortedCopy(root.errors); } - /** Returns the formatted message for an exception with the specified messages. */ - public static String format(String heading, Collection<Message> errorMessages) { - Formatter fmt = new Formatter().format(heading).format(":%n%n"); - int index = 1; - boolean displayCauses = getOnlyCause(errorMessages) == null; - - for (Message errorMessage : errorMessages) { - fmt.format("%s) %s%n", index++, errorMessage.getMessage()); - - List<Object> dependencies = errorMessage.getSources(); - for (int i = dependencies.size() - 1; i >= 0; i--) { - Object source = dependencies.get(i); - formatSource(fmt, source); - } - - Throwable cause = errorMessage.getCause(); - if (displayCauses && cause != null) { - StringWriter writer = new StringWriter(); - cause.printStackTrace(new PrintWriter(writer)); - fmt.format("Caused by: %s", writer.getBuffer()); - } - - fmt.format("%n"); - } - - if (errorMessages.size() == 1) { - fmt.format("1 error"); - } else { - fmt.format("%s errors", errorMessages.size()); - } - - return fmt.toString(); - } - - /** - * Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and - * an {@code ErrorsException} is thrown. - */ - public <T> T checkForNull(T value, Object source, Dependency<?> dependency) - throws ErrorsException { - if (value != null || dependency.isNullable() ) { - return value; - } - - // Hack to allow null parameters to @Provides methods, for backwards compatibility. - if (dependency.getInjectionPoint().getMember() instanceof Method) { - Method annotated = (Method) dependency.getInjectionPoint().getMember(); - if (annotated.isAnnotationPresent(Provides.class)) { - switch (InternalFlags.getNullableProvidesOption()) { - case ERROR: - break; // break out & let the below exception happen - case IGNORE: - return value; // user doesn't care about injecting nulls to non-@Nullables. - case WARN: - // Warn only once, otherwise we spam logs too much. - if (!warnedDependencies.add(dependency)) { - return value; - } - logger.log(Level.WARNING, - "Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable." - + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an" - + " error.", - new Object[] { - dependency.getParameterIndex(), - convert(dependency.getInjectionPoint().getMember()), - convert(dependency.getKey())}); - return null; // log & exit. - } - } - } - - int parameterIndex = dependency.getParameterIndex(); - String parameterName = (parameterIndex != -1) - ? "parameter " + parameterIndex + " of " - : ""; - addMessage("null returned by binding at %s%n but %s%s is not @Nullable", - source, parameterName, dependency.getInjectionPoint().getMember()); - - throw toException(); - } - - /** - * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are - * zero or multiple messages with causes, null is returned. - */ - public static Throwable getOnlyCause(Collection<Message> messages) { - Throwable onlyCause = null; - for (Message message : messages) { - Throwable messageCause = message.getCause(); - if (messageCause == null) { - continue; - } - - if (onlyCause != null) { - return null; - } - - onlyCause = messageCause; - } - - return onlyCause; - } - public int size() { return root.errors == null ? 0 : root.errors.size(); } - private static abstract class Converter<T> { - - final Class<T> type; - - Converter(Class<T> type) { - this.type = type; - } - - boolean appliesTo(Object o) { - return o != null && type.isAssignableFrom(o.getClass()); - } - - String convert(Object o) { - return toString(type.cast(o)); - } - - abstract String toString(T t); - } - - private static final Collection<Converter<?>> converters = ImmutableList.of( - new Converter<Class>(Class.class) { - @Override public String toString(Class c) { - return c.getName(); - } - }, - new Converter<Member>(Member.class) { - @Override public String toString(Member member) { - return Classes.toString(member); - } - }, - new Converter<Key>(Key.class) { - @Override public String toString(Key key) { - if (key.getAnnotationType() != null) { - return key.getTypeLiteral() + " annotated with " - + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType()); - } else { - return key.getTypeLiteral().toString(); - } - } - }); - + // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult public static Object convert(Object o) { - ElementSource source = null; - if (o instanceof ElementSource) { - source = (ElementSource)o; - o = source.getDeclaringSource(); - } - return convert(o, source); + return Messages.convert(o); } + // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult public static Object convert(Object o, ElementSource source) { - for (Converter<?> converter : converters) { - if (converter.appliesTo(o)) { - return appendModules(converter.convert(o), source); - } - } - return appendModules(o, source); - } - - private static Object appendModules(Object source, ElementSource elementSource) { - String modules = moduleSourceString(elementSource); - if (modules.length() == 0) { - return source; - } else { - return source + modules; - } - } - - private static String moduleSourceString(ElementSource elementSource) { - // if we only have one module (or don't know what they are), then don't bother - // reporting it, because the source already is going to report exactly that module. - if (elementSource == null) { - return ""; - } - List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames()); - // Insert any original element sources w/ module info into the path. - while(elementSource.getOriginalElementSource() != null) { - elementSource = elementSource.getOriginalElementSource(); - modules.addAll(0, elementSource.getModuleClassNames()); - } - if (modules.size() <= 1) { - return ""; - } - - // Ideally we'd do: - // return Joiner.on(" -> ") - // .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules)) - // .append(")").toString(); - // ... but for some reason we can't find Lists.reverse, so do it the boring way. - StringBuilder builder = new StringBuilder(" (via modules: "); - for (int i = modules.size() - 1; i >= 0; i--) { - builder.append(modules.get(i)); - if (i != 0) { - builder.append(" -> "); - } - } - builder.append(")"); - return builder.toString(); + return Messages.convert(o, source); } + // TODO(lukes): inline in callers. There are some callers outside of guice, so this is difficult public static void formatSource(Formatter formatter, Object source) { - ElementSource elementSource = null; - if (source instanceof ElementSource) { - elementSource = (ElementSource)source; - source = elementSource.getDeclaringSource(); - } - formatSource(formatter, source, elementSource); + Messages.formatSource(formatter, source); } - public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) { - String modules = moduleSourceString(elementSource); - if (source instanceof Dependency) { - Dependency<?> dependency = (Dependency<?>) source; - InjectionPoint injectionPoint = dependency.getInjectionPoint(); - if (injectionPoint != null) { - formatInjectionPoint(formatter, dependency, injectionPoint, elementSource); - } else { - formatSource(formatter, dependency.getKey(), elementSource); - } - - } else if (source instanceof InjectionPoint) { - formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource); - - } else if (source instanceof Class) { - formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules); - - } else if (source instanceof Member) { - formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules); - - } else if (source instanceof TypeLiteral) { - formatter.format(" while locating %s%s%n", source, modules); - - } else if (source instanceof Key) { - Key<?> key = (Key<?>) source; - formatter.format(" while locating %s%n", convert(key, elementSource)); - - } else if (source instanceof Thread) { - formatter.format(" in thread %s%n", source); - - } else { - formatter.format(" at %s%s%n", source, modules); - } - } - - public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency, - InjectionPoint injectionPoint, ElementSource elementSource) { - Member member = injectionPoint.getMember(); - Class<? extends Member> memberType = Classes.memberType(member); - - if (memberType == Field.class) { - dependency = injectionPoint.getDependencies().get(0); - formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource)); - formatter.format(" for field at %s%n", StackTraceElements.forMember(member)); - - } else if (dependency != null) { - formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource)); - formatter.format(" for parameter %s at %s%n", - dependency.getParameterIndex(), StackTraceElements.forMember(member)); - - } else { - formatSource(formatter, injectionPoint.getMember()); - } - } } diff --git a/core/src/com/google/inject/internal/ErrorsException.java b/core/src/com/google/inject/internal/ErrorsException.java index 57f55c49..6e95dbc7 100644 --- a/core/src/com/google/inject/internal/ErrorsException.java +++ b/core/src/com/google/inject/internal/ErrorsException.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +14,6 @@ * limitations under the License. */ - package com.google.inject.internal; /** @@ -25,6 +24,8 @@ package com.google.inject.internal; * @author jessewilson@google.com (Jesse Wilson) */ public class ErrorsException extends Exception { + // NOTE: this is used by Gin which is abandoned. So changing this API will prevent Gin users from + // upgrading Guice version. private final Errors errors; diff --git a/core/src/com/google/inject/internal/Exceptions.java b/core/src/com/google/inject/internal/Exceptions.java deleted file mode 100644 index f9d1e21f..00000000 --- a/core/src/com/google/inject/internal/Exceptions.java +++ /dev/null @@ -1,62 +0,0 @@ -/** - * Copyright (C) 2010 Google Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.inject.internal; - - -/** - * Rethrows user-code exceptions in wrapped exceptions so that Errors can target the correct - * exception. - * - * @author sameb@google.com (Sam Berlin) - */ -class Exceptions { - - /** - * Rethrows the exception (or it's cause, if it has one) directly if possible. - * If it was a checked exception, this wraps the exception in a stack trace - * with no frames, so that the exception is shown immediately with no frames - * above it. - */ - public static RuntimeException rethrowCause(Throwable throwable) { - Throwable cause = throwable; - if(cause.getCause() != null) { - cause = cause.getCause(); - } - return rethrow(cause); - } - - /** Rethrows the exception. */ - public static RuntimeException rethrow(Throwable throwable) { - if(throwable instanceof RuntimeException) { - throw (RuntimeException)throwable; - } else if(throwable instanceof Error) { - throw (Error)throwable; - } else { - throw new UnhandledCheckedUserException(throwable); - } - } - - /** - * A marker exception class that we look for in order to unwrap the exception - * into the user exception, to provide a cleaner stack trace. - */ - static class UnhandledCheckedUserException extends RuntimeException { - public UnhandledCheckedUserException(Throwable cause) { - super(cause); - } - } -} diff --git a/core/src/com/google/inject/internal/ExposedBindingImpl.java b/core/src/com/google/inject/internal/ExposedBindingImpl.java index f17d5a6a..1dfe4088 100644 --- a/core/src/com/google/inject/internal/ExposedBindingImpl.java +++ b/core/src/com/google/inject/internal/ExposedBindingImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ package com.google.inject.internal; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; import com.google.inject.Injector; @@ -25,43 +25,51 @@ import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.ExposedBinding; import com.google.inject.spi.PrivateElements; - import java.util.Set; public final class ExposedBindingImpl<T> extends BindingImpl<T> implements ExposedBinding<T> { private final PrivateElements privateElements; - public ExposedBindingImpl(InjectorImpl injector, Object source, Key<T> key, - InternalFactory<T> factory, PrivateElements privateElements) { + public ExposedBindingImpl( + InjectorImpl injector, + Object source, + Key<T> key, + InternalFactory<T> factory, + PrivateElements privateElements) { super(injector, key, source, factory, Scoping.UNSCOPED); this.privateElements = privateElements; } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public Set<Dependency<?>> getDependencies() { return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class))); } + @Override public PrivateElements getPrivateElements() { return privateElements; } - @Override public String toString() { - return Objects.toStringHelper(ExposedBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(ExposedBinding.class) .add("key", getKey()) .add("source", getSource()) .add("privateElements", privateElements) .toString(); } + @Override public void applyTo(Binder binder) { throw new UnsupportedOperationException("This element represents a synthetic binding."); } - + // Purposely does not override equals/hashcode, because exposed bindings are only equal to // themselves right now -- that is, there cannot be "duplicate" exposed bindings. } diff --git a/core/src/com/google/inject/internal/ExposedKeyFactory.java b/core/src/com/google/inject/internal/ExposedKeyFactory.java index 52bf7cb6..5de73aae 100644 --- a/core/src/com/google/inject/internal/ExposedKeyFactory.java +++ b/core/src/com/google/inject/internal/ExposedKeyFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,6 +34,7 @@ final class ExposedKeyFactory<T> implements InternalFactory<T>, CreationListener this.privateElements = privateElements; } + @Override public void notify(Errors errors) { InjectorImpl privateInjector = (InjectorImpl) privateElements.getInjector(); BindingImpl<T> explicitBinding = privateInjector.state.getExplicitBinding(key); @@ -49,8 +50,10 @@ final class ExposedKeyFactory<T> implements InternalFactory<T>, CreationListener this.delegate = explicitBinding; } - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - return delegate.getInternalFactory().get(errors, context, dependency, linked); + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + // TODO(lukes): add a source to the thrown exception? + return delegate.getInternalFactory().get(context, dependency, linked); } } diff --git a/core/src/com/google/inject/internal/ExposureBuilder.java b/core/src/com/google/inject/internal/ExposureBuilder.java index 3b1c2279..35dca169 100644 --- a/core/src/com/google/inject/internal/ExposureBuilder.java +++ b/core/src/com/google/inject/internal/ExposureBuilder.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,12 +20,9 @@ import com.google.common.base.Preconditions; import com.google.inject.Binder; import com.google.inject.Key; import com.google.inject.binder.AnnotatedElementBuilder; - import java.lang.annotation.Annotation; -/** - * For private binder's expose() method. - */ +/** For private binder's expose() method. */ public class ExposureBuilder<T> implements AnnotatedElementBuilder { private final Binder binder; private final Object source; @@ -43,12 +40,14 @@ public class ExposureBuilder<T> implements AnnotatedElementBuilder { } } + @Override public void annotatedWith(Class<? extends Annotation> annotationType) { Preconditions.checkNotNull(annotationType, "annotationType"); checkNotAnnotated(); key = Key.get(key.getTypeLiteral(), annotationType); } + @Override public void annotatedWith(Annotation annotation) { Preconditions.checkNotNull(annotation, "annotation"); checkNotAnnotated(); @@ -63,7 +62,8 @@ public class ExposureBuilder<T> implements AnnotatedElementBuilder { return source; } - @Override public String toString() { + @Override + public String toString() { return "AnnotatedElementBuilder"; } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/FactoryProxy.java b/core/src/com/google/inject/internal/FactoryProxy.java index 6416d26e..a3a2227f 100644 --- a/core/src/com/google/inject/internal/FactoryProxy.java +++ b/core/src/com/google/inject/internal/FactoryProxy.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,14 +16,14 @@ package com.google.inject.internal; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.inject.Key; import com.google.inject.internal.InjectorImpl.JitLimitation; import com.google.inject.spi.Dependency; /** - * A placeholder which enables us to swap in the real factory once the injector is created. - * Used for a linked binding, so that getting the linked binding returns the link's factory. + * A placeholder which enables us to swap in the real factory once the injector is created. Used for + * a linked binding, so that getting the linked binding returns the link's factory. */ final class FactoryProxy<T> implements InternalFactory<T>, CreationListener { @@ -41,26 +41,36 @@ final class FactoryProxy<T> implements InternalFactory<T>, CreationListener { this.source = source; } + @Override public void notify(final Errors errors) { try { - targetFactory = injector.getInternalFactory(targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT); + targetFactory = + injector.getInternalFactory( + targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT); } catch (ErrorsException e) { errors.merge(e.getErrors()); } } - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - context.pushState(targetKey, source); + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + Key<? extends T> localTargetKey = targetKey; + context.pushState(localTargetKey, source); + try { - return targetFactory.get(errors.withSource(targetKey), context, dependency, true); - } finally { - context.popState(); + return targetFactory.get(context, dependency, true); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localTargetKey); + } finally { + context.popState(); + } } - @Override public String toString() { - return Objects.toStringHelper(FactoryProxy.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(FactoryProxy.class) .add("key", key) .add("provider", targetFactory) .toString(); diff --git a/core/src/com/google/inject/internal/FailableCache.java b/core/src/com/google/inject/internal/FailableCache.java index acd8be5b..e1a461d8 100644 --- a/core/src/com/google/inject/internal/FailableCache.java +++ b/core/src/com/google/inject/internal/FailableCache.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,23 +27,26 @@ import com.google.common.cache.LoadingCache; * @author jessewilson@google.com (Jesse Wilson) */ public abstract class FailableCache<K, V> { - - private final LoadingCache<K, Object> delegate = CacheBuilder.newBuilder().build( - new CacheLoader<K, Object>() { - public Object load(K key) { - Errors errors = new Errors(); - V result = null; - try { - result = FailableCache.this.create(key, errors); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); - } - return errors.hasErrors() ? errors : result; - } - }); + + private final LoadingCache<K, Object> delegate = + CacheBuilder.newBuilder() + .build( + new CacheLoader<K, Object>() { + @Override + public Object load(K key) { + Errors errors = new Errors(); + V result = null; + try { + result = FailableCache.this.create(key, errors); + } catch (ErrorsException e) { + errors.merge(e.getErrors()); + } + return errors.hasErrors() ? errors : result; + } + }); protected abstract V create(K key, Errors errors) throws ErrorsException; - + public V get(K key, Errors errors) throws ErrorsException { Object resultOrError = delegate.getUnchecked(key); if (resultOrError instanceof Errors) { @@ -55,7 +58,7 @@ public abstract class FailableCache<K, V> { return result; } } - + boolean remove(K key) { return delegate.asMap().remove(key) != null; } diff --git a/core/src/com/google/inject/internal/Indexer.java b/core/src/com/google/inject/internal/Indexer.java new file mode 100644 index 00000000..acbc1638 --- /dev/null +++ b/core/src/com/google/inject/internal/Indexer.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.internal; + +import com.google.common.base.Objects; +import com.google.inject.Binding; +import com.google.inject.Injector; +import com.google.inject.Scope; +import com.google.inject.Scopes; +import com.google.inject.TypeLiteral; +import com.google.inject.spi.BindingScopingVisitor; +import com.google.inject.spi.ConstructorBinding; +import com.google.inject.spi.ConvertedConstantBinding; +import com.google.inject.spi.DefaultBindingTargetVisitor; +import com.google.inject.spi.ExposedBinding; +import com.google.inject.spi.InstanceBinding; +import com.google.inject.spi.LinkedKeyBinding; +import com.google.inject.spi.ProviderBinding; +import com.google.inject.spi.ProviderInstanceBinding; +import com.google.inject.spi.ProviderKeyBinding; +import com.google.inject.spi.UntargettedBinding; +import java.lang.annotation.Annotation; + +/** + * Visits bindings to return a {@code IndexedBinding} that can be used to emulate the binding + * deduplication that Guice internally performs. + * + * <p>Note: simply using equals/hashCode on the BindingImpls doesn't work because they all have + * unique annotations. This works around that by reimplementing equality semantics that ignores + * {@link Element#uniqueId()}. A better solution might be to introduce the idea of an 'anonymous' + * binding to guice, that might support this usecase directly. + */ +class Indexer extends DefaultBindingTargetVisitor<Object, Indexer.IndexedBinding> + implements BindingScopingVisitor<Object> { + enum BindingType { + INSTANCE, + PROVIDER_INSTANCE, + PROVIDER_KEY, + LINKED_KEY, + UNTARGETTED, + CONSTRUCTOR, + CONSTANT, + EXPOSED, + PROVIDED_BY, + } + + static class IndexedBinding { + final String annotationName; + final Element.Type annotationType; + final TypeLiteral<?> typeLiteral; + final Object scope; + final BindingType type; + final Object extraEquality; + + IndexedBinding(Binding<?> binding, BindingType type, Object scope, Object extraEquality) { + this.scope = scope; + this.type = type; + this.extraEquality = extraEquality; + this.typeLiteral = binding.getKey().getTypeLiteral(); + Element annotation = (Element) binding.getKey().getAnnotation(); + this.annotationName = annotation.setName(); + this.annotationType = annotation.type(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof IndexedBinding)) { + return false; + } + IndexedBinding o = (IndexedBinding) obj; + return type == o.type + && Objects.equal(scope, o.scope) + && typeLiteral.equals(o.typeLiteral) + && annotationType == o.annotationType + && annotationName.equals(o.annotationName) + && Objects.equal(extraEquality, o.extraEquality); + } + + @Override + public int hashCode() { + return Objects.hashCode( + type, scope, typeLiteral, annotationType, annotationName, extraEquality); + } + } + + final Injector injector; + + Indexer(Injector injector) { + this.injector = injector; + } + + boolean isIndexable(Binding<?> binding) { + return binding.getKey().getAnnotation() instanceof Element; + } + + private Object scope(Binding<?> binding) { + return binding.acceptScopingVisitor(this); + } + + @Override + public Indexer.IndexedBinding visit(ConstructorBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.CONSTRUCTOR, scope(binding), binding.getConstructor()); + } + + @Override + public Indexer.IndexedBinding visit(ConvertedConstantBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.CONSTANT, scope(binding), binding.getValue()); + } + + @Override + public Indexer.IndexedBinding visit(ExposedBinding<? extends Object> binding) { + return new Indexer.IndexedBinding(binding, BindingType.EXPOSED, scope(binding), binding); + } + + @Override + public Indexer.IndexedBinding visit(InstanceBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.INSTANCE, scope(binding), binding.getInstance()); + } + + @Override + public Indexer.IndexedBinding visit(LinkedKeyBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.LINKED_KEY, scope(binding), binding.getLinkedKey()); + } + + @Override + public Indexer.IndexedBinding visit(ProviderBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, + BindingType.PROVIDED_BY, + scope(binding), + injector.getBinding(binding.getProvidedKey())); + } + + @Override + public Indexer.IndexedBinding visit(ProviderInstanceBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.PROVIDER_INSTANCE, scope(binding), binding.getUserSuppliedProvider()); + } + + @Override + public Indexer.IndexedBinding visit(ProviderKeyBinding<? extends Object> binding) { + return new Indexer.IndexedBinding( + binding, BindingType.PROVIDER_KEY, scope(binding), binding.getProviderKey()); + } + + @Override + public Indexer.IndexedBinding visit(UntargettedBinding<? extends Object> binding) { + return new Indexer.IndexedBinding(binding, BindingType.UNTARGETTED, scope(binding), null); + } + + private static final Object EAGER_SINGLETON = new Object(); + + @Override + public Object visitEagerSingleton() { + return EAGER_SINGLETON; + } + + @Override + public Object visitNoScoping() { + return Scopes.NO_SCOPE; + } + + @Override + public Object visitScope(Scope scope) { + return scope; + } + + @Override + public Object visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) { + return scopeAnnotation; + } +} diff --git a/core/src/com/google/inject/internal/InheritingState.java b/core/src/com/google/inject/internal/InheritingState.java index 18363f48..7b739fca 100644 --- a/core/src/com/google/inject/internal/InheritingState.java +++ b/core/src/com/google/inject/internal/InheritingState.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,25 +31,21 @@ import com.google.inject.spi.ProvisionListenerBinding; import com.google.inject.spi.ScopeBinding; import com.google.inject.spi.TypeConverterBinding; import com.google.inject.spi.TypeListenerBinding; - import java.lang.annotation.Annotation; -import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ final class InheritingState implements State { private final State parent; // Must be a linked hashmap in order to preserve order of bindings in Modules. private final Map<Key<?>, Binding<?>> explicitBindingsMutable = Maps.newLinkedHashMap(); - private final Map<Key<?>, Binding<?>> explicitBindings - = Collections.unmodifiableMap(explicitBindingsMutable); + private final Map<Key<?>, Binding<?>> explicitBindings = + Collections.unmodifiableMap(explicitBindingsMutable); private final Map<Class<? extends Annotation>, ScopeBinding> scopes = Maps.newHashMap(); private final List<TypeConverterBinding> converters = Lists.newArrayList(); /*if[AOP]*/ @@ -67,41 +63,50 @@ final class InheritingState implements State { this.blacklistedKeys = new WeakKeySet(lock); } + @Override public State parent() { return parent; } + @Override @SuppressWarnings("unchecked") // we only put in BindingImpls that match their key types public <T> BindingImpl<T> getExplicitBinding(Key<T> key) { Binding<?> binding = explicitBindings.get(key); return binding != null ? (BindingImpl<T>) binding : parent.getExplicitBinding(key); } + @Override public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() { return explicitBindings; } + @Override public void putBinding(Key<?> key, BindingImpl<?> binding) { explicitBindingsMutable.put(key, binding); } + @Override public ScopeBinding getScopeBinding(Class<? extends Annotation> annotationType) { ScopeBinding scopeBinding = scopes.get(annotationType); return scopeBinding != null ? scopeBinding : parent.getScopeBinding(annotationType); } + @Override public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) { scopes.put(annotationType, scope); } + @Override public Iterable<TypeConverterBinding> getConvertersThisLevel() { return converters; } + @Override public void addConverter(TypeConverterBinding typeConverterBinding) { converters.add(typeConverterBinding); } + @Override public TypeConverterBinding getConverter( String stringValue, TypeLiteral<?> type, Errors errors, Object source) { TypeConverterBinding matchingConverter = null; @@ -119,10 +124,12 @@ final class InheritingState implements State { } /*if[AOP]*/ + @Override public void addMethodAspect(MethodAspect methodAspect) { methodAspects.add(methodAspect); } + @Override public ImmutableList<MethodAspect> getMethodAspects() { return new ImmutableList.Builder<MethodAspect>() .addAll(parent.getMethodAspects()) @@ -131,10 +138,12 @@ final class InheritingState implements State { } /*end[AOP]*/ + @Override public void addTypeListener(TypeListenerBinding listenerBinding) { typeListenerBindings.add(listenerBinding); } + @Override public List<TypeListenerBinding> getTypeListenerBindings() { List<TypeListenerBinding> parentBindings = parent.getTypeListenerBindings(); List<TypeListenerBinding> result = @@ -143,11 +152,13 @@ final class InheritingState implements State { result.addAll(typeListenerBindings); return result; } - + + @Override public void addProvisionListener(ProvisionListenerBinding listenerBinding) { provisionListenerBindings.add(listenerBinding); } + @Override public List<ProvisionListenerBinding> getProvisionListenerBindings() { List<ProvisionListenerBinding> parentBindings = parent.getProvisionListenerBindings(); List<ProvisionListenerBinding> result = @@ -157,10 +168,12 @@ final class InheritingState implements State { return result; } + @Override public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) { scannerBindings.add(scanner); } + @Override public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() { List<ModuleAnnotatedMethodScannerBinding> parentBindings = parent.getScannerBindings(); List<ModuleAnnotatedMethodScannerBinding> result = @@ -170,23 +183,28 @@ final class InheritingState implements State { return result; } + @Override public void blacklist(Key<?> key, State state, Object source) { parent.blacklist(key, state, source); blacklistedKeys.add(key, state, source); } + @Override public boolean isBlacklisted(Key<?> key) { return blacklistedKeys.contains(key); } - + + @Override public Set<Object> getSourcesForBlacklistedKey(Key<?> key) { return blacklistedKeys.getSources(key); } + @Override public Object lock() { return lock; } + @Override public Map<Class<? extends Annotation>, Scope> getScopes() { ImmutableMap.Builder<Class<? extends Annotation>, Scope> builder = ImmutableMap.builder(); for (Map.Entry<Class<? extends Annotation>, ScopeBinding> entry : scopes.entrySet()) { diff --git a/core/src/com/google/inject/internal/Initializable.java b/core/src/com/google/inject/internal/Initializable.java index 855dd8cb..e3c9ed93 100644 --- a/core/src/com/google/inject/internal/Initializable.java +++ b/core/src/com/google/inject/internal/Initializable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,8 +23,6 @@ package com.google.inject.internal; */ interface Initializable<T> { - /** - * Ensures the reference is initialized, then returns it. - */ - T get(Errors errors) throws ErrorsException; + /** Ensures the reference is initialized, then returns it. */ + T get() throws InternalProvisionException; } diff --git a/core/src/com/google/inject/internal/Initializables.java b/core/src/com/google/inject/internal/Initializables.java index 82e28687..36655f7d 100644 --- a/core/src/com/google/inject/internal/Initializables.java +++ b/core/src/com/google/inject/internal/Initializables.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,21 +16,19 @@ package com.google.inject.internal; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ final class Initializables { - /** - * Returns an initializable for an instance that requires no initialization. - */ + /** Returns an initializable for an instance that requires no initialization. */ static <T> Initializable<T> of(final T instance) { return new Initializable<T>() { - public T get(Errors errors) throws ErrorsException { + @Override + public T get() { return instance; } - @Override public String toString() { + @Override + public String toString() { return String.valueOf(instance); } }; diff --git a/core/src/com/google/inject/internal/Initializer.java b/core/src/com/google/inject/internal/Initializer.java index ff83ea9b..2ab4b0fe 100644 --- a/core/src/com/google/inject/internal/Initializer.java +++ b/core/src/com/google/inject/internal/Initializer.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,15 +21,16 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Preconditions; import com.google.common.collect.Lists; import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; import com.google.inject.Binding; import com.google.inject.Key; import com.google.inject.Stage; import com.google.inject.TypeLiteral; +import com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory; import com.google.inject.spi.InjectionPoint; - -import java.util.Map; +import java.util.IdentityHashMap; +import java.util.List; import java.util.Set; -import java.util.concurrent.CountDownLatch; /** * Manages and injects instances at injector-creation time. This is made more complicated by @@ -39,46 +40,76 @@ import java.util.concurrent.CountDownLatch; * @author jessewilson@google.com (Jesse Wilson) */ final class Initializer { - - /** the only thread that we'll use to inject members. */ - private final Thread creatingThread = Thread.currentThread(); - - /** zero means everything is injected. */ - private final CountDownLatch ready = new CountDownLatch(1); - - /** Maps from instances that need injection to the MembersInjector that will inject them. */ - private final Map<Object, MembersInjectorImpl<?>> pendingMembersInjectors = - Maps.newIdentityHashMap(); - /** Maps instances that need injection to a source that registered them */ - private final Map<Object, InjectableReference<?>> pendingInjection = Maps.newIdentityHashMap(); + /** Is set to true once {@link #validateOustandingInjections} is called. */ + private volatile boolean validationStarted = false; + + /** + * Allows us to detect circular dependencies. It's only used during injectable reference + * initialization. After initialization direct access through volatile field is used. + */ + private final CycleDetectingLockFactory<Class<?>> cycleDetectingLockFactory = + new CycleDetectingLockFactory<Class<?>>(); + + /** + * Instances that need injection during injector creation to a source that registered them. New + * references added before {@link #validateOustandingInjections}. Cleared up in {@link + * #injectAll}. + */ + private final List<InjectableReference<?>> pendingInjections = Lists.newArrayList(); + + /** + * Map that guarantees that no instance would get two references. New references added before + * {@link #validateOustandingInjections}. Cleared up in {@link #validateOustandingInjections}. + */ + private final IdentityHashMap<Object, InjectableReference<?>> initializablesCache = + Maps.newIdentityHashMap(); /** * Registers an instance for member injection when that step is performed. * - * @param instance an instance that optionally has members to be injected (each annotated with - * @Inject). + * @param instance an instance that optionally has members to be injected (each annotated + * with @Inject). * @param binding the binding that caused this initializable to be created, if it exists. * @param source the source location that this injection was requested */ - <T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Binding<T> binding, - Object source, Set<InjectionPoint> injectionPoints) { + <T> Initializable<T> requestInjection( + InjectorImpl injector, + T instance, + Binding<T> binding, + Object source, + Set<InjectionPoint> injectionPoints) { checkNotNull(source); - + Preconditions.checkState( + !validationStarted, "Member injection could not be requested after validation is started"); ProvisionListenerStackCallback<T> provisionCallback = binding == null ? null : injector.provisionListenerStore.get(binding); // short circuit if the object has no injections or listeners. - if (instance == null || (injectionPoints.isEmpty() - && !injector.membersInjectorStore.hasTypeListeners() - && (provisionCallback == null || !provisionCallback.hasListeners()))) { + if (instance == null + || (injectionPoints.isEmpty() + && !injector.membersInjectorStore.hasTypeListeners() + && provisionCallback == null)) { return Initializables.of(instance); } - InjectableReference<T> initializable = new InjectableReference<T>( - injector, instance, binding == null ? null : binding.getKey(), provisionCallback, source); - pendingInjection.put(instance, initializable); - return initializable; + if (initializablesCache.containsKey(instance)) { + @SuppressWarnings("unchecked") // Map from T to InjectableReference<T> + Initializable<T> cached = (Initializable<T>) initializablesCache.get(instance); + return cached; + } + + InjectableReference<T> injectableReference = + new InjectableReference<T>( + injector, + instance, + binding == null ? null : binding.getKey(), + provisionCallback, + source, + cycleDetectingLockFactory.create(instance.getClass())); + initializablesCache.put(instance, injectableReference); + pendingInjections.add(injectableReference); + return injectableReference; } /** @@ -86,9 +117,11 @@ final class Initializer { * on the injected instances. */ void validateOustandingInjections(Errors errors) { - for (InjectableReference<?> reference : pendingInjection.values()) { + validationStarted = true; + initializablesCache.clear(); + for (InjectableReference<?> reference : pendingInjections) { try { - pendingMembersInjectors.put(reference.instance, reference.validate(errors)); + reference.validate(errors); } catch (ErrorsException e) { errors.merge(e.getErrors()); } @@ -101,88 +134,130 @@ final class Initializer { * instances are codependent (directly or transitively), ordering of injection is arbitrary. */ void injectAll(final Errors errors) { - // loop over a defensive copy since ensureInjected() mutates the set. Unfortunately, that copy - // is made complicated by a bug in IBM's JDK, wherein entrySet().toArray(Object[]) doesn't work - for (InjectableReference<?> reference : Lists.newArrayList(pendingInjection.values())) { + Preconditions.checkState(validationStarted, "Validation should be done before injection"); + for (InjectableReference<?> reference : pendingInjections) { try { - reference.get(errors); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); + reference.get(); + } catch (InternalProvisionException ipe) { + errors.merge(ipe); } } + pendingInjections.clear(); + } - if (!pendingInjection.isEmpty()) { - throw new AssertionError("Failed to satisfy " + pendingInjection); - } - - ready.countDown(); + private enum InjectableReferenceState { + NEW, + VALIDATED, + INJECTING, + READY } - private class InjectableReference<T> implements Initializable<T> { + private static class InjectableReference<T> implements Initializable<T> { + private volatile InjectableReferenceState state = InjectableReferenceState.NEW; + private volatile MembersInjectorImpl<T> membersInjector = null; + private final InjectorImpl injector; private final T instance; private final Object source; private final Key<T> key; private final ProvisionListenerStackCallback<T> provisionCallback; + private final CycleDetectingLock<?> lock; - public InjectableReference(InjectorImpl injector, T instance, Key<T> key, - ProvisionListenerStackCallback<T> provisionCallback, Object source) { + public InjectableReference( + InjectorImpl injector, + T instance, + Key<T> key, + ProvisionListenerStackCallback<T> provisionCallback, + Object source, + CycleDetectingLock<?> lock) { this.injector = injector; this.key = key; // possibly null! this.provisionCallback = provisionCallback; // possibly null! this.instance = checkNotNull(instance, "instance"); this.source = checkNotNull(source, "source"); + this.lock = checkNotNull(lock, "lock"); } - public MembersInjectorImpl<T> validate(Errors errors) throws ErrorsException { + public void validate(Errors errors) throws ErrorsException { @SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T> - TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass()); - return injector.membersInjectorStore.get(type, errors.withSource(source)); + TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass()); + membersInjector = injector.membersInjectorStore.get(type, errors.withSource(source)); + Preconditions.checkNotNull( + membersInjector, + "No membersInjector available for instance: %s, from key: %s", + instance, + key); + state = InjectableReferenceState.VALIDATED; } /** * Reentrant. If {@code instance} was registered for injection at injector-creation time, this * method will ensure that all its members have been injected before returning. */ - public T get(Errors errors) throws ErrorsException { - if (ready.getCount() == 0) { + @Override + public T get() throws InternalProvisionException { + // skipping acquiring lock if initialization is already finished + if (state == InjectableReferenceState.READY) { return instance; } - // just wait for everything to be injected by another thread - if (Thread.currentThread() != creatingThread) { - try { - ready.await(); - return instance; - } catch (InterruptedException e) { - // Give up, since we don't know if our injection is ready - throw new RuntimeException(e); - } + // acquire lock for current binding to initialize an instance + Multimap<?, ?> lockCycle = lock.lockOrDetectPotentialLocksCycle(); + if (!lockCycle.isEmpty()) { + // Potential deadlock detected and creation lock is not taken. + // According to injectAll()'s contract return non-initialized instance. + + // This condition should not be possible under the current Guice implementation. + // This clause exists for defensive programming purposes. + + // Reasoning: + // get() is called either directly from injectAll(), holds no locks and can not create + // a cycle, or it is called through a singleton scope, which resolves deadlocks by itself. + // Before calling get() object has to be requested for injection. + // Initializer.requestInjection() is called either for constant object bindings, which wrap + // creation into a Singleton scope, or from Binder.requestInjection(), which + // has to use Singleton scope to reuse the same InjectableReference to potentially + // create a lock cycle. + return instance; } + try { + // lock acquired, current thread owns this instance initialization + switch (state) { + case READY: + return instance; + // When instance depends on itself in the same thread potential dead lock + // is not detected. We have to prevent a stack overflow and we use + // an "injecting" stage to short-circuit a call. + case INJECTING: + return instance; + case VALIDATED: + state = InjectableReferenceState.INJECTING; + break; + case NEW: + throw new IllegalStateException("InjectableReference is not validated yet"); + default: + throw new IllegalStateException("Unknown state: " + state); + } - // toInject needs injection, do it right away. we only do this once, even if it fails - if (pendingInjection.remove(instance) != null) { - // safe because we only insert a members injector for the appropriate instance - @SuppressWarnings("unchecked") - MembersInjectorImpl<T> membersInjector = - (MembersInjectorImpl<T>)pendingMembersInjectors.remove(instance); - Preconditions.checkState(membersInjector != null, - "No membersInjector available for instance: %s, from key: %s", instance, key); - // if in Stage.TOOL, we only want to inject & notify toolable injection points. // (otherwise we'll inject all of them) - membersInjector.injectAndNotify(instance, - errors.withSource(source), - key, - provisionCallback, - source, - injector.options.stage == Stage.TOOL); + try { + membersInjector.injectAndNotify( + instance, key, provisionCallback, source, injector.options.stage == Stage.TOOL); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(source); + } + // mark instance as ready to skip a lock on subsequent calls + state = InjectableReferenceState.READY; + return instance; + } finally { + // always release our creation lock, even on failures + lock.unlock(); } - - return instance; } - @Override public String toString() { + @Override + public String toString() { return instance.toString(); } } diff --git a/core/src/com/google/inject/internal/InjectionRequestProcessor.java b/core/src/com/google/inject/internal/InjectionRequestProcessor.java index 36ad261a..dce78e85 100644 --- a/core/src/com/google/inject/internal/InjectionRequestProcessor.java +++ b/core/src/com/google/inject/internal/InjectionRequestProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.inject.Stage; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.InjectionRequest; import com.google.inject.spi.StaticInjectionRequest; - import java.util.List; import java.util.Set; @@ -44,12 +43,14 @@ final class InjectionRequestProcessor extends AbstractProcessor { this.initializer = initializer; } - @Override public Boolean visit(StaticInjectionRequest request) { + @Override + public Boolean visit(StaticInjectionRequest request) { staticInjections.add(new StaticInjection(injector, request)); return true; } - @Override public Boolean visit(InjectionRequest<?> request) { + @Override + public Boolean visit(InjectionRequest<?> request) { Set<InjectionPoint> injectionPoints; try { injectionPoints = request.getInjectionPoints(); @@ -103,31 +104,32 @@ final class InjectionRequestProcessor extends AbstractProcessor { injectionPoints = e.getPartialValue(); } if (injectionPoints != null) { - memberInjectors = injector.membersInjectorStore.getInjectors( - injectionPoints, errorsForMember); + memberInjectors = + injector.membersInjectorStore.getInjectors(injectionPoints, errorsForMember); } else { memberInjectors = ImmutableList.of(); } - + errors.merge(errorsForMember); } void injectMembers() { + InternalContext context = injector.enterContext(); try { - injector.callInContext(new ContextualCallable<Void>() { - public Void call(InternalContext context) { - for (SingleMemberInjector memberInjector : memberInjectors) { - // Run injections if we're not in tool stage (ie, PRODUCTION or DEV), - // or if we are in tool stage and the injection point is toolable. - if(injector.options.stage != Stage.TOOL || memberInjector.getInjectionPoint().isToolable()) { - memberInjector.inject(errors, context, null); - } + boolean isStageTool = injector.options.stage == Stage.TOOL; + for (SingleMemberInjector memberInjector : memberInjectors) { + // Run injections if we're not in tool stage (ie, PRODUCTION or DEV), + // or if we are in tool stage and the injection point is toolable. + if (!isStageTool || memberInjector.getInjectionPoint().isToolable()) { + try { + memberInjector.inject(context, null); + } catch (InternalProvisionException e) { + errors.merge(e); } - return null; } - }); - } catch (ErrorsException e) { - throw new AssertionError(); + } + } finally { + context.close(); } } } diff --git a/core/src/com/google/inject/internal/InjectorImpl.java b/core/src/com/google/inject/internal/InjectorImpl.java index 54ce8a3c..321dbea2 100644 --- a/core/src/com/google/inject/internal/InjectorImpl.java +++ b/core/src/com/google/inject/internal/InjectorImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,11 +16,13 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; +import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Lists; +import com.google.common.collect.ListMultimap; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.google.inject.Binder; @@ -33,7 +35,6 @@ import com.google.inject.MembersInjector; import com.google.inject.Module; import com.google.inject.ProvidedBy; import com.google.inject.Provider; -import com.google.inject.ProvisionException; import com.google.inject.Scope; import com.google.inject.Stage; import com.google.inject.TypeLiteral; @@ -43,10 +44,10 @@ import com.google.inject.spi.ConvertedConstantBinding; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import com.google.inject.spi.InjectionPoint; +import com.google.inject.spi.InstanceBinding; import com.google.inject.spi.ProviderBinding; import com.google.inject.spi.TypeConverterBinding; import com.google.inject.util.Providers; - import java.lang.annotation.Annotation; import java.lang.reflect.GenericArrayType; import java.lang.reflect.InvocationTargetException; @@ -57,7 +58,6 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentMap; /** * Default {@link Injector} implementation. @@ -75,8 +75,12 @@ final class InjectorImpl implements Injector, Lookups { final boolean atInjectRequired; final boolean exactBindingAnnotationsRequired; - InjectorOptions(Stage stage, boolean jitDisabled, boolean disableCircularProxies, - boolean atInjectRequired, boolean exactBindingAnnotationsRequired) { + InjectorOptions( + Stage stage, + boolean jitDisabled, + boolean disableCircularProxies, + boolean atInjectRequired, + boolean exactBindingAnnotationsRequired) { this.stage = stage; this.jitDisabled = jitDisabled; this.disableCircularProxies = disableCircularProxies; @@ -86,7 +90,7 @@ final class InjectorImpl implements Injector, Lookups { @Override public String toString() { - return Objects.toStringHelper(getClass()) + return MoreObjects.toStringHelper(getClass()) .add("stage", stage) .add("jitDisabled", jitDisabled) .add("disableCircularProxies", disableCircularProxies) @@ -108,14 +112,14 @@ final class InjectorImpl implements Injector, Lookups { final State state; final InjectorImpl parent; - final BindingsMultimap bindingsMultimap = new BindingsMultimap(); + final ListMultimap<TypeLiteral<?>, Binding<?>> bindingsMultimap = ArrayListMultimap.create(); final InjectorOptions options; /** Just-in-time binding cache. Guarded by state.lock() */ final Map<Key<?>, BindingImpl<?>> jitBindings = Maps.newHashMap(); /** - * Cache of Keys that we were unable to create JIT bindings for, so we don't - * keep trying. Also guarded by state.lock(). + * Cache of Keys that we were unable to create JIT bindings for, so we don't keep trying. Also + * guarded by state.lock(). */ final Set<Key<?>> failedJitBindings = Sets.newHashSet(); @@ -129,26 +133,29 @@ final class InjectorImpl implements Injector, Lookups { if (parent != null) { localContext = parent.localContext; } else { - localContext = new ThreadLocal<Object[]>(); + // No ThreadLocal.initialValue(), as that would cause classloader leaks. See + // https://github.com/google/guice/issues/288#issuecomment-48216933, + // https://github.com/google/guice/issues/288#issuecomment-48216944 + localContext = new ThreadLocal<>(); } } /** Indexes bindings by type. */ void index() { for (Binding<?> binding : state.getExplicitBindingsThisLevel().values()) { - index(binding); + bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding); } } - <T> void index(Binding<T> binding) { - bindingsMultimap.put(binding.getKey().getTypeLiteral(), binding); - } - + @Override public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) { - return bindingsMultimap.getAll(type); + @SuppressWarnings("unchecked") // safe because we only put matching entries into the map + List<Binding<T>> list = (List<Binding<T>>) (List) bindingsMultimap.get(type); + return Collections.unmodifiableList(list); } /** Returns the binding for {@code key} */ + @Override public <T> BindingImpl<T> getBinding(Key<T> key) { Errors errors = new Errors(key); try { @@ -160,6 +167,7 @@ final class InjectorImpl implements Injector, Lookups { } } + @Override public <T> BindingImpl<T> getExistingBinding(Key<T> key) { // Check explicit bindings, i.e. bindings created by modules. BindingImpl<T> explicitBinding = state.getExplicitBinding(key); @@ -171,7 +179,7 @@ final class InjectorImpl implements Injector, Lookups { for (InjectorImpl injector = this; injector != null; injector = injector.parent) { @SuppressWarnings("unchecked") BindingImpl<T> jitBinding = (BindingImpl<T>) injector.jitBindings.get(key); - if(jitBinding != null) { + if (jitBinding != null) { return jitBinding; } } @@ -179,15 +187,15 @@ final class InjectorImpl implements Injector, Lookups { // If Key is a Provider, we have to see if the type it is providing exists, // and, if so, we have to create the binding for the provider. - if(isProvider(key)) { + if (isProvider(key)) { try { // This is safe because isProvider above ensures that T is a Provider<?> @SuppressWarnings({"unchecked", "cast"}) - Key<?> providedKey = (Key<?>)getProvidedKey((Key)key, new Errors()); - if(getExistingBinding(providedKey) != null) { + Key<?> providedKey = (Key<?>) getProvidedKey((Key) key, new Errors()); + if (getExistingBinding(providedKey) != null) { return getBinding(key); } - } catch(ErrorsException e) { + } catch (ErrorsException e) { throw new ConfigurationException(e.getErrors().getMessages()); } } @@ -197,8 +205,8 @@ final class InjectorImpl implements Injector, Lookups { } /** - * Gets a binding implementation. First, it check to see if the parent has a binding. If the - * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this + * Gets a binding implementation. First, it check to see if the parent has a binding. If the + * parent has a binding and the binding is scoped, it will use that binding. Otherwise, this * checks for an explicit binding. If no explicit binding is found, it looks for a just-in-time * binding. */ @@ -214,21 +222,22 @@ final class InjectorImpl implements Injector, Lookups { return getJustInTimeBinding(key, errors, jitType); } + @Override public <T> Binding<T> getBinding(Class<T> type) { return getBinding(Key.get(type)); } + @Override public Injector getParent() { return parent; } + @Override public Injector createChildInjector(Iterable<? extends Module> modules) { - return new InternalInjectorCreator() - .parentInjector(this) - .addModules(modules) - .build(); + return new InternalInjectorCreator().parentInjector(this).addModules(modules).build(); } + @Override public Injector createChildInjector(Module... modules) { return createChildInjector(ImmutableList.copyOf(modules)); } @@ -292,7 +301,8 @@ final class InjectorImpl implements Injector, Lookups { return key.getTypeLiteral().getRawType().equals(TypeLiteral.class); } - private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors) throws ErrorsException { + private static <T> Key<T> getProvidedKey(Key<Provider<T>> key, Errors errors) + throws ErrorsException { Type providerType = key.getTypeLiteral().getType(); // If the Provider has no type parameter (raw Provider)... @@ -321,21 +331,26 @@ final class InjectorImpl implements Injector, Lookups { } @SuppressWarnings("unchecked") // safe because T came from Key<MembersInjector<T>> - TypeLiteral<T> instanceType = (TypeLiteral<T>) TypeLiteral.get( - ((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]); + TypeLiteral<T> instanceType = + (TypeLiteral<T>) + TypeLiteral.get(((ParameterizedType) membersInjectorType).getActualTypeArguments()[0]); MembersInjector<T> membersInjector = membersInjectorStore.get(instanceType, errors); - InternalFactory<MembersInjector<T>> factory = new ConstantFactory<MembersInjector<T>>( - Initializables.of(membersInjector)); - + InternalFactory<MembersInjector<T>> factory = + new ConstantFactory<MembersInjector<T>>(Initializables.of(membersInjector)); - return new InstanceBindingImpl<MembersInjector<T>>(this, key, SourceProvider.UNKNOWN_SOURCE, - factory, ImmutableSet.<InjectionPoint>of(), membersInjector); + return new InstanceBindingImpl<MembersInjector<T>>( + this, + key, + SourceProvider.UNKNOWN_SOURCE, + factory, + ImmutableSet.<InjectionPoint>of(), + membersInjector); } /** - * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from - * {@code Binding<T>}. + * Creates a synthetic binding to {@code Provider<T>}, i.e. a binding to the provider from {@code + * Binding<T>}. */ private <T> BindingImpl<Provider<T>> createProviderBinding(Key<Provider<T>> key, Errors errors) throws ErrorsException { @@ -349,7 +364,11 @@ final class InjectorImpl implements Injector, Lookups { final BindingImpl<T> providedBinding; ProviderBindingImpl(InjectorImpl injector, Key<Provider<T>> key, Binding<T> providedBinding) { - super(injector, key, providedBinding.getSource(), createInternalFactory(providedBinding), + super( + injector, + key, + providedBinding.getSource(), + createInternalFactory(providedBinding), Scoping.UNSCOPED); this.providedBinding = (BindingImpl<T>) providedBinding; } @@ -357,42 +376,48 @@ final class InjectorImpl implements Injector, Lookups { static <T> InternalFactory<Provider<T>> createInternalFactory(Binding<T> providedBinding) { final Provider<T> provider = providedBinding.getProvider(); return new InternalFactory<Provider<T>>() { - public Provider<T> get(Errors errors, InternalContext context, Dependency dependency, boolean linked) { + @Override + public Provider<T> get(InternalContext context, Dependency<?> dependency, boolean linked) { return provider; } }; } + @Override public Key<? extends T> getProvidedKey() { return providedBinding.getKey(); } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super Provider<T>, V> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { throw new UnsupportedOperationException("This element represents a synthetic binding."); } - @Override public String toString() { - return Objects.toStringHelper(ProviderBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(ProviderBinding.class) .add("key", getKey()) .add("providedKey", getProvidedKey()) .toString(); } + @Override public Set<Dependency<?>> getDependencies() { return ImmutableSet.<Dependency<?>>of(Dependency.get(getProvidedKey())); } @Override public boolean equals(Object obj) { - if(obj instanceof ProviderBindingImpl) { - ProviderBindingImpl<?> o = (ProviderBindingImpl<?>)obj; + if (obj instanceof ProviderBindingImpl) { + ProviderBindingImpl<?> o = (ProviderBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(providedBinding, o.providedBinding); + && getScoping().equals(o.getScoping()) + && Objects.equal(providedBinding, o.providedBinding); } else { return false; } @@ -419,12 +444,17 @@ final class InjectorImpl implements Injector, Lookups { return null; } - String stringValue = stringBinding.getProvider().get(); + // We can't call getProvider().get() because this InstanceBinding may not have been inintialized + // yet (because we may have been called during InternalInjectorCreator.initializeStatically and + // instance binding validation hasn't happened yet.) + @SuppressWarnings("unchecked") + String stringValue = ((InstanceBinding<String>) stringBinding).getInstance(); Object source = stringBinding.getSource(); // Find a matching type converter. TypeLiteral<T> type = key.getTypeLiteral(); - TypeConverterBinding typeConverterBinding = state.getConverter(stringValue, type, errors, source); + TypeConverterBinding typeConverterBinding = + state.getConverter(stringValue, type, errors, source); if (typeConverterBinding == null) { // No converter can handle the given type. @@ -437,73 +467,91 @@ final class InjectorImpl implements Injector, Lookups { T converted = (T) typeConverterBinding.getTypeConverter().convert(stringValue, type); if (converted == null) { - throw errors.converterReturnedNull(stringValue, source, type, typeConverterBinding) + throw errors + .converterReturnedNull(stringValue, source, type, typeConverterBinding) .toException(); } if (!type.getRawType().isInstance(converted)) { - throw errors.conversionTypeError(stringValue, source, type, typeConverterBinding, converted) + throw errors + .conversionTypeError(stringValue, source, type, typeConverterBinding, converted) .toException(); } - return new ConvertedConstantBindingImpl<T>(this, key, converted, stringBinding, - typeConverterBinding); + return new ConvertedConstantBindingImpl<T>( + this, key, converted, stringBinding, typeConverterBinding); } catch (ErrorsException e) { throw e; } catch (RuntimeException e) { - throw errors.conversionError(stringValue, source, type, typeConverterBinding, e) + throw errors + .conversionError(stringValue, source, type, typeConverterBinding, e) .toException(); } } - private static class ConvertedConstantBindingImpl<T> - extends BindingImpl<T> implements ConvertedConstantBinding<T> { + private static class ConvertedConstantBindingImpl<T> extends BindingImpl<T> + implements ConvertedConstantBinding<T> { final T value; final Provider<T> provider; final Binding<String> originalBinding; final TypeConverterBinding typeConverterBinding; ConvertedConstantBindingImpl( - InjectorImpl injector, Key<T> key, T value, Binding<String> originalBinding, + InjectorImpl injector, + Key<T> key, + T value, + Binding<String> originalBinding, TypeConverterBinding typeConverterBinding) { - super(injector, key, originalBinding.getSource(), - new ConstantFactory<T>(Initializables.of(value)), Scoping.UNSCOPED); + super( + injector, + key, + originalBinding.getSource(), + new ConstantFactory<T>(Initializables.of(value)), + Scoping.UNSCOPED); this.value = value; provider = Providers.of(value); this.originalBinding = originalBinding; this.typeConverterBinding = typeConverterBinding; } - @Override public Provider<T> getProvider() { + @Override + public Provider<T> getProvider() { return provider; } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public T getValue() { return value; } + @Override public TypeConverterBinding getTypeConverterBinding() { return typeConverterBinding; } + @Override public Key<String> getSourceKey() { return originalBinding.getKey(); } + @Override public Set<Dependency<?>> getDependencies() { return ImmutableSet.<Dependency<?>>of(Dependency.get(getSourceKey())); } + @Override public void applyTo(Binder binder) { throw new UnsupportedOperationException("This element represents a synthetic binding."); } - @Override public String toString() { - return Objects.toStringHelper(ConvertedConstantBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(ConvertedConstantBinding.class) .add("key", getKey()) .add("sourceKey", getSourceKey()) .add("value", value) @@ -512,11 +560,11 @@ final class InjectorImpl implements Injector, Lookups { @Override public boolean equals(Object obj) { - if(obj instanceof ConvertedConstantBindingImpl) { - ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>)obj; + if (obj instanceof ConvertedConstantBindingImpl) { + ConvertedConstantBindingImpl<?> o = (ConvertedConstantBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(value, o.value); + && getScoping().equals(o.getScoping()) + && Objects.equal(value, o.value); } else { return false; } @@ -542,7 +590,7 @@ final class InjectorImpl implements Injector, Lookups { Key<T> key = binding.getKey(); jitBindings.put(key, binding); boolean successful = false; - DelayedInitialize delayed = (DelayedInitialize)binding; + DelayedInitialize delayed = (DelayedInitialize) binding; try { delayed.initialize(this, errors); successful = true; @@ -560,32 +608,32 @@ final class InjectorImpl implements Injector, Lookups { /** * Iterates through the binding's dependencies to clean up any stray bindings that were leftover - * from a failed JIT binding. This is required because the bindings are eagerly & - * optimistically added to allow circular dependency support, so dependencies may pass where they - * should have failed. + * from a failed JIT binding. This is required because the bindings are eagerly & optimistically + * added to allow circular dependency support, so dependencies may pass where they should have + * failed. */ private boolean cleanup(BindingImpl<?> binding, Set<Key> encountered) { boolean bindingFailed = false; Set<Dependency<?>> deps = getInternalDependencies(binding); - for(Dependency dep : deps) { + for (Dependency dep : deps) { Key<?> depKey = dep.getKey(); InjectionPoint ip = dep.getInjectionPoint(); - if(encountered.add(depKey)) { // only check if we haven't looked at this key yet + if (encountered.add(depKey)) { // only check if we haven't looked at this key yet BindingImpl depBinding = jitBindings.get(depKey); - if(depBinding != null) { // if the binding still exists, validate + if (depBinding != null) { // if the binding still exists, validate boolean failed = cleanup(depBinding, encountered); // if children fail, we fail - if(depBinding instanceof ConstructorBindingImpl) { - ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl)depBinding; + if (depBinding instanceof ConstructorBindingImpl) { + ConstructorBindingImpl ctorBinding = (ConstructorBindingImpl) depBinding; ip = ctorBinding.getInternalConstructor(); - if(!ctorBinding.isInitialized()) { + if (!ctorBinding.isInitialized()) { failed = true; } } - if(failed) { + if (failed) { removeFailedJitBinding(depBinding, ip); bindingFailed = true; } - } else if(state.getExplicitBinding(depKey) == null) { + } else if (state.getExplicitBinding(depKey) == null) { // ignore keys if they were explicitly bound, but if neither JIT // nor explicit, it's also invalid & should let parent know. bindingFailed = true; @@ -601,7 +649,7 @@ final class InjectorImpl implements Injector, Lookups { jitBindings.remove(binding.getKey()); membersInjectorStore.remove(binding.getKey().getTypeLiteral()); provisionListenerStore.remove(binding); - if(ip != null) { + if (ip != null) { constructors.remove(ip); } } @@ -609,10 +657,10 @@ final class InjectorImpl implements Injector, Lookups { /** Safely gets the dependencies of possibly not initialized bindings. */ @SuppressWarnings("unchecked") private Set<Dependency<?>> getInternalDependencies(BindingImpl<?> binding) { - if(binding instanceof ConstructorBindingImpl) { - return ((ConstructorBindingImpl)binding).getInternalDependencies(); - } else if(binding instanceof HasDependencies) { - return ((HasDependencies)binding).getDependencies(); + if (binding instanceof ConstructorBindingImpl) { + return ((ConstructorBindingImpl) binding).getInternalDependencies(); + } else if (binding instanceof HasDependencies) { + return ((HasDependencies) binding).getDependencies(); } else { return ImmutableSet.of(); } @@ -622,22 +670,23 @@ final class InjectorImpl implements Injector, Lookups { * Creates a binding for an injectable type with the given scope. Looks for a scope on the type if * none is specified. */ - <T> BindingImpl<T> createUninitializedBinding(Key<T> key, Scoping scoping, Object source, - Errors errors, boolean jitBinding) throws ErrorsException { + <T> BindingImpl<T> createUninitializedBinding( + Key<T> key, Scoping scoping, Object source, Errors errors, boolean jitBinding) + throws ErrorsException { Class<?> rawType = key.getTypeLiteral().getRawType(); ImplementedBy implementedBy = rawType.getAnnotation(ImplementedBy.class); // Don't try to inject arrays or enums annotated with @ImplementedBy. if (rawType.isArray() || (rawType.isEnum() && implementedBy != null)) { - throw errors.missingImplementation(key).toException(); + throw errors.missingImplementationWithHint(key, this).toException(); } // Handle TypeLiteral<T> by binding the inner type if (rawType == TypeLiteral.class) { @SuppressWarnings("unchecked") // we have to fudge the inner type as Object - BindingImpl<T> binding = (BindingImpl<T>) createTypeLiteralBinding( - (Key<TypeLiteral<Object>>) key, errors); + BindingImpl<T> binding = + (BindingImpl<T>) createTypeLiteralBinding((Key<TypeLiteral<Object>>) key, errors); return binding; } @@ -654,8 +703,8 @@ final class InjectorImpl implements Injector, Lookups { return createProvidedByBinding(key, scoping, providedBy, errors); } - - return ConstructorBindingImpl.create(this, + return ConstructorBindingImpl.create( + this, key, null, /* use default constructor */ source, @@ -689,17 +738,22 @@ final class InjectorImpl implements Injector, Lookups { @SuppressWarnings("unchecked") // by definition, innerType == T, so this is safe TypeLiteral<T> value = (TypeLiteral<T>) TypeLiteral.get(innerType); - InternalFactory<TypeLiteral<T>> factory = new ConstantFactory<TypeLiteral<T>>( - Initializables.of(value)); - return new InstanceBindingImpl<TypeLiteral<T>>(this, key, SourceProvider.UNKNOWN_SOURCE, - factory, ImmutableSet.<InjectionPoint>of(), value); + InternalFactory<TypeLiteral<T>> factory = + new ConstantFactory<TypeLiteral<T>>(Initializables.of(value)); + return new InstanceBindingImpl<TypeLiteral<T>>( + this, + key, + SourceProvider.UNKNOWN_SOURCE, + factory, + ImmutableSet.<InjectionPoint>of(), + value); } /** Creates a binding for a type annotated with @ProvidedBy. */ - <T> BindingImpl<T> createProvidedByBinding(Key<T> key, Scoping scoping, - ProvidedBy providedBy, Errors errors) throws ErrorsException { + <T> BindingImpl<T> createProvidedByBinding( + Key<T> key, Scoping scoping, ProvidedBy providedBy, Errors errors) throws ErrorsException { Class<?> rawType = key.getTypeLiteral().getRawType(); - Class<? extends Provider<?>> providerType = providedBy.value(); + Class<? extends javax.inject.Provider<?>> providerType = providedBy.value(); // Make sure it's not the same type. TODO: Can we check for deeper loops? if (providerType == rawType) { @@ -712,21 +766,22 @@ final class InjectorImpl implements Injector, Lookups { ProvidedByInternalFactory<T> internalFactory = new ProvidedByInternalFactory<T>(rawType, providerType, providerKey); Object source = rawType; - BindingImpl<T> binding = LinkedProviderBindingImpl.createWithInitializer( - this, - key, - source, - Scoping.<T>scope(key, this, internalFactory, source, scoping), - scoping, - providerKey, - internalFactory); + BindingImpl<T> binding = + LinkedProviderBindingImpl.createWithInitializer( + this, + key, + source, + Scoping.<T>scope(key, this, internalFactory, source, scoping), + scoping, + providerKey, + internalFactory); internalFactory.setProvisionListenerCallback(provisionListenerStore.get(binding)); return binding; } /** Creates a binding for a type annotated with @ImplementedBy. */ - private <T> BindingImpl<T> createImplementedByBinding(Key<T> key, Scoping scoping, - ImplementedBy implementedBy, Errors errors) + private <T> BindingImpl<T> createImplementedByBinding( + Key<T> key, Scoping scoping, ImplementedBy implementedBy, Errors errors) throws ErrorsException { Class<?> rawType = key.getTypeLiteral().getRawType(); Class<?> implementationType = implementedBy.value(); @@ -746,27 +801,14 @@ final class InjectorImpl implements Injector, Lookups { // Look up the target binding. final Key<? extends T> targetKey = Key.get(subclass); - final BindingImpl<? extends T> targetBinding = getBindingOrThrow(targetKey, errors, JitLimitation.NEW_OR_EXISTING_JIT); - - InternalFactory<T> internalFactory = new InternalFactory<T>() { - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - context.pushState(targetKey, targetBinding.getSource()); - try { - return targetBinding.getInternalFactory().get( - errors.withSource(targetKey), context, dependency, true); - } finally { - context.popState(); - } - } - }; - Object source = rawType; + FactoryProxy<T> factory = new FactoryProxy<>(this, key, targetKey, source); + factory.notify(errors); // causes the factory to initialize itself internally return new LinkedBindingImpl<T>( this, key, source, - Scoping.<T>scope(key, this, internalFactory, source, scoping), + Scoping.<T>scope(key, this, factory, source, scoping), scoping, targetKey); } @@ -775,18 +817,23 @@ final class InjectorImpl implements Injector, Lookups { * Attempts to create a just-in-time binding for {@code key} in the root injector, falling back to * other ancestor injectors until this injector is tried. */ - private <T> BindingImpl<T> createJustInTimeBindingRecursive(Key<T> key, Errors errors, - boolean jitDisabled, JitLimitation jitType) throws ErrorsException { + private <T> BindingImpl<T> createJustInTimeBindingRecursive( + Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType) + throws ErrorsException { // ask the parent to create the JIT binding if (parent != null) { if (jitType == JitLimitation.NEW_OR_EXISTING_JIT - && jitDisabled && !parent.options.jitDisabled) { + && jitDisabled + && !parent.options.jitDisabled) { // If the binding would be forbidden here but allowed in a parent, report an error instead throw errors.jitDisabledInParent(key).toException(); } try { - return parent.createJustInTimeBindingRecursive(key, new Errors(), jitDisabled, + return parent.createJustInTimeBindingRecursive( + key, + new Errors(), + jitDisabled, parent.options.jitDisabled ? JitLimitation.NO_JIT : jitType); } catch (ErrorsException ignored) { } @@ -811,18 +858,20 @@ final class InjectorImpl implements Injector, Lookups { /** * Returns a new just-in-time binding created by resolving {@code key}. The strategies used to * create just-in-time bindings are: + * * <ol> - * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate + * <li>Internalizing Providers. If the requested binding is for {@code Provider<T>}, we delegate * to the binding for {@code T}. - * <li>Converting constants. - * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys. - * <li>The constructor of the raw type. Only for unannotated keys. + * <li>Converting constants. + * <li>ImplementedBy and ProvidedBy annotations. Only for unannotated keys. + * <li>The constructor of the raw type. Only for unannotated keys. * </ol> * * @throws com.google.inject.internal.ErrorsException if the binding cannot be created. */ - private <T> BindingImpl<T> createJustInTimeBinding(Key<T> key, Errors errors, - boolean jitDisabled, JitLimitation jitType) throws ErrorsException { + private <T> BindingImpl<T> createJustInTimeBinding( + Key<T> key, Errors errors, boolean jitDisabled, JitLimitation jitType) + throws ErrorsException { int numErrorsBefore = errors.size(); // Retrieve the sources before checking for blacklisting to guard against sources becoming null @@ -858,9 +907,7 @@ final class InjectorImpl implements Injector, Lookups { return convertedBinding; } - if (!isTypeLiteral(key) - && jitDisabled - && jitType != JitLimitation.NEW_OR_EXISTING_JIT) { + if (!isTypeLiteral(key) && jitDisabled && jitType != JitLimitation.NEW_OR_EXISTING_JIT) { throw errors.jitDisabled(key).toException(); } @@ -875,25 +922,28 @@ final class InjectorImpl implements Injector, Lookups { // throw with a more appropriate message below } } - throw errors.missingImplementation(key).toException(); + throw errors.missingImplementationWithHint(key, this).toException(); } Object source = key.getTypeLiteral().getRawType(); - BindingImpl<T> binding = createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true); + BindingImpl<T> binding = + createUninitializedBinding(key, Scoping.UNSCOPED, source, errors, true); errors.throwIfNewErrors(numErrorsBefore); initializeJitBinding(binding, errors); return binding; } - <T> InternalFactory<? extends T> getInternalFactory(Key<T> key, Errors errors, JitLimitation jitType) - throws ErrorsException { + <T> InternalFactory<? extends T> getInternalFactory( + Key<T> key, Errors errors, JitLimitation jitType) throws ErrorsException { return getBindingOrThrow(key, errors, jitType).getInternalFactory(); } + @Override public Map<Key<?>, Binding<?>> getBindings() { return state.getExplicitBindingsThisLevel(); } + @Override public Map<Key<?>, Binding<?>> getAllBindings() { synchronized (state.lock()) { return new ImmutableMap.Builder<Key<?>, Binding<?>>() @@ -903,41 +953,19 @@ final class InjectorImpl implements Injector, Lookups { } } + @Override public Map<Class<? extends Annotation>, Scope> getScopeBindings() { return ImmutableMap.copyOf(state.getScopes()); } + @Override public Set<TypeConverterBinding> getTypeConverterBindings() { return ImmutableSet.copyOf(state.getConvertersThisLevel()); } - private static class BindingsMultimap { - final Map<TypeLiteral<?>, List<Binding<?>>> multimap = Maps.newHashMap(); - - <T> void put(TypeLiteral<T> type, Binding<T> binding) { - List<Binding<?>> bindingsForType = multimap.get(type); - if (bindingsForType == null) { - bindingsForType = Lists.newArrayList(); - multimap.put(type, bindingsForType); - } - bindingsForType.add(binding); - } - - - @SuppressWarnings("unchecked") // safe because we only put matching entries into the map - <T> List<Binding<T>> getAll(TypeLiteral<T> type) { - List<Binding<?>> bindings = multimap.get(type); - return bindings != null - ? Collections.<Binding<T>>unmodifiableList((List) multimap.get(type)) - : ImmutableList.<Binding<T>>of(); - } - } - - /** - * Returns parameter injectors, or {@code null} if there are no parameters. - */ - SingleParameterInjector<?>[] getParametersInjectors( - List<Dependency<?>> parameters, Errors errors) throws ErrorsException { + /** Returns parameter injectors, or {@code null} if there are no parameters. */ + SingleParameterInjector<?>[] getParametersInjectors(List<Dependency<?>> parameters, Errors errors) + throws ErrorsException { if (parameters.isEmpty()) { return null; } @@ -957,9 +985,10 @@ final class InjectorImpl implements Injector, Lookups { return result; } - <T> SingleParameterInjector<T> createParameterInjector(final Dependency<T> dependency, - final Errors errors) throws ErrorsException { - BindingImpl<? extends T> binding = getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT); + <T> SingleParameterInjector<T> createParameterInjector( + final Dependency<T> dependency, final Errors errors) throws ErrorsException { + BindingImpl<? extends T> binding = + getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT); return new SingleParameterInjector<T>(dependency, binding); } @@ -978,12 +1007,14 @@ final class InjectorImpl implements Injector, Lookups { /** Cached provision listener callbacks for each key. */ ProvisionListenerCallbackStore provisionListenerStore; + @Override @SuppressWarnings("unchecked") // the members injector type is consistent with instance's type public void injectMembers(Object instance) { MembersInjector membersInjector = getMembersInjector(instance.getClass()); membersInjector.injectMembers(instance); } + @Override public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) { Errors errors = new Errors(typeLiteral); try { @@ -993,45 +1024,47 @@ final class InjectorImpl implements Injector, Lookups { } } + @Override public <T> MembersInjector<T> getMembersInjector(Class<T> type) { return getMembersInjector(TypeLiteral.get(type)); } + @Override public <T> Provider<T> getProvider(Class<T> type) { return getProvider(Key.get(type)); } - <T> Provider<T> getProviderOrThrow(final Dependency<T> dependency, Errors errors) throws ErrorsException { - final Key<T> key = dependency.getKey(); - final BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT); + <T> Provider<T> getProviderOrThrow(final Dependency<T> dependency, Errors errors) + throws ErrorsException { + Key<T> key = dependency.getKey(); + BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT); + final InternalFactory<? extends T> internalFactory = binding.getInternalFactory(); + final Object source = binding.getSource(); return new Provider<T>() { + @Override public T get() { - final Errors errors = new Errors(dependency); + InternalContext currentContext = enterContext(); + Dependency previous = currentContext.pushDependency(dependency, source); try { - T t = callInContext(new ContextualCallable<T>() { - public T call(InternalContext context) throws ErrorsException { - Dependency previous = context.pushDependency(dependency, binding.getSource()); - try { - return binding.getInternalFactory().get(errors, context, dependency, false); - } finally { - context.popStateAndSetDependency(previous); - } - } - }); - errors.throwIfNewErrors(0); + T t = internalFactory.get(currentContext, dependency, false); return t; - } catch (ErrorsException e) { - throw new ProvisionException(errors.merge(e.getErrors()).getMessages()); + } catch (InternalProvisionException e) { + throw e.addSource(dependency).toProvisionException(); + } finally { + currentContext.popStateAndSetDependency(previous); + currentContext.close(); } } - @Override public String toString() { - return binding.getInternalFactory().toString(); + @Override + public String toString() { + return internalFactory.toString(); } }; } + @Override public <T> Provider<T> getProvider(final Key<T> key) { Errors errors = new Errors(key); try { @@ -1043,77 +1076,68 @@ final class InjectorImpl implements Injector, Lookups { } } + @Override public <T> T getInstance(Key<T> key) { return getProvider(key).get(); } + @Override public <T> T getInstance(Class<T> type) { return getProvider(type).get(); } - /** @see #getGlobalInternalContext */ - private final ThreadLocal<Object[]> localContext; /** - * Synchronization: map value is modified only for the current thread, - * it's ok to read map values of other threads. It can change between your - * calls. + * Holds Object[] as a mutable wrapper, rather than InternalContext, since array operations are + * faster than ThreadLocal.set() / .get() operations. * - * @see #getGlobalInternalContext + * <p>Holds Object[] rather than InternalContext[], since localContext never gets cleaned up at + * any point. This could lead to problems when, for example, an OSGI application is reloaded, the + * InjectorImpl is destroyed, but the thread that the injector runs on is kept alive. In such a + * case, ThreadLocal itself would hold on to a reference to localContext, which would hold on to + * the old InternalContext.class object, which would hold on to the old classloader that loaded + * that class, and so on. */ - private static final ConcurrentMap<Thread, InternalContext> globalInternalContext = - Maps.newConcurrentMap(); + private final ThreadLocal<Object[]> localContext; + + /** Only to be called by the {@link SingletonScope} provider. */ + InternalContext getLocalContext() { + return (InternalContext) localContext.get()[0]; + } /** - * Provides access to the internal context for the current injector of all threads. - * One does not need to use this from Guice source code as context could be passed on the stack. - * It is required for custom scopes which are called from Guice and sometimes do require - * access to current internal context, but it is not passed in. Contrary to {@link #localContext} - * it is not used to store injector-specific state, but to provide easy access to the current - * state. + * Looks up thread local context and {@link InternalContext#enter() enters} it or creates a new + * context if necessary. + * + * <p>All callers of this are responsible for calling {@link InternalContext#close()}. Typical + * usage should look like: * - * @return unmodifiable map + * <pre>{@code + * InternalContext ctx = injector.enterContext(); + * try { + * ... use ctx ... + * } finally { + * ctx.close(); + * } + * }</pre> */ - static Map<Thread, InternalContext> getGlobalInternalContext() { - return Collections.unmodifiableMap(globalInternalContext); - } - - /** Looks up thread local context. Creates (and removes) a new context if necessary. */ - <T> T callInContext(ContextualCallable<T> callable) throws ErrorsException { + InternalContext enterContext() { Object[] reference = localContext.get(); if (reference == null) { reference = new Object[1]; localContext.set(reference); } - Thread currentThread = Thread.currentThread(); - if (reference[0] == null) { - reference[0] = new InternalContext(options); - globalInternalContext.put(currentThread, (InternalContext) reference[0]); - try { - return callable.call((InternalContext) reference[0]); - } finally { - // Only clear contexts if this call created them. - reference[0] = null; - globalInternalContext.remove(currentThread); - } + InternalContext ctx = (InternalContext) reference[0]; + if (ctx == null) { + reference[0] = ctx = new InternalContext(options, reference); } else { - Object previousGlobalInternalContext = globalInternalContext.get(currentThread); - globalInternalContext.put(currentThread, (InternalContext) reference[0]); - try { - // Someone else will clean up this local context. - return callable.call((InternalContext) reference[0]); - } finally { - if (previousGlobalInternalContext != null) { - globalInternalContext.put(currentThread, (InternalContext) previousGlobalInternalContext); - } else { - globalInternalContext.remove(currentThread); - } - } + ctx.enter(); } + return ctx; } @Override public String toString() { - return Objects.toStringHelper(Injector.class) + return MoreObjects.toStringHelper(Injector.class) .add("bindings", state.getExplicitBindingsThisLevel().values()) .toString(); } diff --git a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java index 61cc6eea..32bab003 100644 --- a/core/src/com/google/inject/internal/InjectorOptionsProcessor.java +++ b/core/src/com/google/inject/internal/InjectorOptionsProcessor.java @@ -53,11 +53,11 @@ class InjectorOptionsProcessor extends AbstractProcessor { jitDisabled = true; return true; } - + @Override public Boolean visit(RequireAtInjectOnConstructorsOption option) { atInjectRequired = true; - return true; + return true; } @Override @@ -68,7 +68,7 @@ class InjectorOptionsProcessor extends AbstractProcessor { InjectorOptions getOptions(Stage stage, InjectorOptions parentOptions) { checkNotNull(stage, "stage must be set"); - if(parentOptions == null) { + if (parentOptions == null) { return new InjectorOptions( stage, jitDisabled, @@ -85,5 +85,4 @@ class InjectorOptionsProcessor extends AbstractProcessor { exactBindingAnnotationsRequired || parentOptions.exactBindingAnnotationsRequired); } } - } diff --git a/core/src/com/google/inject/internal/InjectorShell.java b/core/src/com/google/inject/internal/InjectorShell.java index 5982bb39..e2ddcd98 100644 --- a/core/src/com/google/inject/internal/InjectorShell.java +++ b/core/src/com/google/inject/internal/InjectorShell.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,14 +39,13 @@ import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; import com.google.inject.spi.PrivateElements; import com.google.inject.spi.ProvisionListenerBinding; import com.google.inject.spi.TypeListenerBinding; - import java.util.List; import java.util.logging.Logger; /** - * A partially-initialized injector. See {@link InternalInjectorCreator}, which - * uses this to build a tree of injectors in batch. - * + * A partially-initialized injector. See {@link InternalInjectorCreator}, which uses this to build a + * tree of injectors in batch. + * * @author jessewilson@google.com (Jesse Wilson) */ final class InjectorShell { @@ -54,7 +53,7 @@ final class InjectorShell { private final List<Element> elements; private final InjectorImpl injector; - private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) { + private InjectorShell(List<Element> elements, InjectorImpl injector) { this.elements = elements; this.injector = injector; } @@ -80,7 +79,7 @@ final class InjectorShell { /** null unless this exists in a {@link Binder#newPrivateBinder private environment} */ private PrivateElementsImpl privateElements; - + Builder stage(Stage stage) { this.stage = stage; return this; @@ -105,7 +104,7 @@ final class InjectorShell { this.modules.add(module); } } - + Stage getStage() { return options.stage; } @@ -136,12 +135,12 @@ final class InjectorShell { modules.add(0, new InheritedScannersModule(parent.state)); } elements.addAll(Elements.getElements(stage, modules)); - + // Look for injector-changing options InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors); optionsProcessor.process(null, elements); options = optionsProcessor.getOptions(stage, options); - + InjectorImpl injector = new InjectorImpl(parent, state, options); if (privateElements != null) { privateElements.initInjector(injector); @@ -179,7 +178,7 @@ final class InjectorShell { bindStage(injector, stage); bindInjector(injector); bindLogger(injector); - + // Process all normal bindings, then UntargettedBindings. // This is necessary because UntargettedBindings can create JIT bindings // and need all their other dependencies set up ahead of time. @@ -191,7 +190,7 @@ final class InjectorShell { stopwatch.resetAndLog("Module annotated method scanners creation"); List<InjectorShell> injectorShells = Lists.newArrayList(); - injectorShells.add(new InjectorShell(this, elements, injector)); + injectorShells.add(new InjectorShell(elements, injector)); // recursively build child shells PrivateElementProcessor processor = new PrivateElementProcessor(errors); @@ -213,15 +212,21 @@ final class InjectorShell { } /** - * The Injector is a special case because we allow both parent and child injectors to both have - * a binding for that key. + * The Injector is a special case because we allow both parent and child injectors to both have a + * binding for that key. */ private static void bindInjector(InjectorImpl injector) { Key<Injector> key = Key.get(Injector.class); InjectorFactory injectorFactory = new InjectorFactory(injector); - injector.state.putBinding(key, - new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE, - injectorFactory, Scoping.UNSCOPED, injectorFactory, + injector.state.putBinding( + key, + new ProviderInstanceBindingImpl<Injector>( + injector, + key, + SourceProvider.UNKNOWN_SOURCE, + injectorFactory, + Scoping.UNSCOPED, + injectorFactory, ImmutableSet.<InjectionPoint>of())); } @@ -232,15 +237,17 @@ final class InjectorShell { this.injector = injector; } - public Injector get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { + @Override + public Injector get(InternalContext context, Dependency<?> dependency, boolean linked) { return injector; } + @Override public Injector get() { return injector; } + @Override public String toString() { return "Provider<Injector>"; } @@ -253,42 +260,53 @@ final class InjectorShell { private static void bindLogger(InjectorImpl injector) { Key<Logger> key = Key.get(Logger.class); LoggerFactory loggerFactory = new LoggerFactory(); - injector.state.putBinding(key, - new ProviderInstanceBindingImpl<Logger>(injector, key, - SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED, - loggerFactory, ImmutableSet.<InjectionPoint>of())); + injector.state.putBinding( + key, + new ProviderInstanceBindingImpl<Logger>( + injector, + key, + SourceProvider.UNKNOWN_SOURCE, + loggerFactory, + Scoping.UNSCOPED, + loggerFactory, + ImmutableSet.<InjectionPoint>of())); } private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> { - public Logger get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) { + @Override + public Logger get(InternalContext context, Dependency<?> dependency, boolean linked) { InjectionPoint injectionPoint = dependency.getInjectionPoint(); return injectionPoint == null ? Logger.getAnonymousLogger() : Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName()); } + @Override public Logger get() { return Logger.getAnonymousLogger(); } + @Override public String toString() { return "Provider<Logger>"; } } - + private static void bindStage(InjectorImpl injector, Stage stage) { Key<Stage> key = Key.get(Stage.class); - InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>( - injector, - key, - SourceProvider.UNKNOWN_SOURCE, - new ConstantFactory<Stage>(Initializables.of(stage)), - ImmutableSet.<InjectionPoint>of(), - stage); + InstanceBindingImpl<Stage> stageBinding = + new InstanceBindingImpl<Stage>( + injector, + key, + SourceProvider.UNKNOWN_SOURCE, + new ConstantFactory<Stage>(Initializables.of(stage)), + ImmutableSet.<InjectionPoint>of(), + stage); injector.state.putBinding(key, stageBinding); } private static class RootModule implements Module { + @Override public void configure(Binder binder) { binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE); binder.bindScope(Singleton.class, SINGLETON); @@ -303,6 +321,7 @@ final class InjectorShell { this.state = state; } + @Override public void configure(Binder binder) { for (ModuleAnnotatedMethodScannerBinding binding : state.getScannerBindings()) { binding.applyTo(binder); diff --git a/core/src/com/google/inject/internal/InstanceBindingImpl.java b/core/src/com/google/inject/internal/InstanceBindingImpl.java index 9b7a4835..44d53b4c 100644 --- a/core/src/com/google/inject/internal/InstanceBindingImpl.java +++ b/core/src/com/google/inject/internal/InstanceBindingImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,80 +16,83 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; import com.google.inject.Key; -import com.google.inject.Provider; import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.InstanceBinding; -import com.google.inject.util.Providers; - import java.util.Set; final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBinding<T> { final T instance; - final Provider<T> provider; final ImmutableSet<InjectionPoint> injectionPoints; - public InstanceBindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> internalFactory, Set<InjectionPoint> injectionPoints, + public InstanceBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Set<InjectionPoint> injectionPoints, T instance) { super(injector, key, source, internalFactory, Scoping.EAGER_SINGLETON); this.injectionPoints = ImmutableSet.copyOf(injectionPoints); this.instance = instance; - this.provider = Providers.of(instance); } - public InstanceBindingImpl(Object source, Key<T> key, Scoping scoping, - Set<InjectionPoint> injectionPoints, T instance) { + public InstanceBindingImpl( + Object source, Key<T> key, Scoping scoping, Set<InjectionPoint> injectionPoints, T instance) { super(source, key, scoping); this.injectionPoints = ImmutableSet.copyOf(injectionPoints); this.instance = instance; - this.provider = Providers.of(instance); - } - - @Override public Provider<T> getProvider() { - return this.provider; } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public T getInstance() { return instance; } + @Override public Set<InjectionPoint> getInjectionPoints() { return injectionPoints; } + @Override public Set<Dependency<?>> getDependencies() { return instance instanceof HasDependencies ? ImmutableSet.copyOf(((HasDependencies) instance).getDependencies()) : Dependency.forInjectionPoints(injectionPoints); } + @Override public BindingImpl<T> withScoping(Scoping scoping) { return new InstanceBindingImpl<T>(getSource(), getKey(), scoping, injectionPoints, instance); } + @Override public BindingImpl<T> withKey(Key<T> key) { return new InstanceBindingImpl<T>(getSource(), key, getScoping(), injectionPoints, instance); } + @Override public void applyTo(Binder binder) { // instance bindings aren't scoped binder.withSource(getSource()).bind(getKey()).toInstance(instance); } - @Override public String toString() { - return Objects.toStringHelper(InstanceBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(InstanceBinding.class) .add("key", getKey()) .add("source", getSource()) .add("instance", instance) @@ -98,11 +101,11 @@ final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBin @Override public boolean equals(Object obj) { - if(obj instanceof InstanceBindingImpl) { - InstanceBindingImpl<?> o = (InstanceBindingImpl<?>)obj; + if (obj instanceof InstanceBindingImpl) { + InstanceBindingImpl<?> o = (InstanceBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(instance, o.instance); + && getScoping().equals(o.getScoping()) + && Objects.equal(instance, o.instance); } else { return false; } diff --git a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java index e3526727..de2174aa 100644 --- a/core/src/com/google/inject/internal/InterceptorBindingProcessor.java +++ b/core/src/com/google/inject/internal/InterceptorBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,9 +30,11 @@ final class InterceptorBindingProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(InterceptorBinding command) { - injector.state.addMethodAspect(new MethodAspect( - command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors())); + @Override + public Boolean visit(InterceptorBinding command) { + injector.state.addMethodAspect( + new MethodAspect( + command.getClassMatcher(), command.getMethodMatcher(), command.getInterceptors())); return true; } } diff --git a/core/src/com/google/inject/internal/InterceptorStackCallback.java b/core/src/com/google/inject/internal/InterceptorStackCallback.java index f12ddaf5..7ae22bbb 100644 --- a/core/src/com/google/inject/internal/InterceptorStackCallback.java +++ b/core/src/com/google/inject/internal/InterceptorStackCallback.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,18 +17,15 @@ package com.google.inject.internal; import com.google.common.collect.Lists; - -import net.sf.cglib.proxy.MethodProxy; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - import java.lang.reflect.AccessibleObject; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; +import net.sf.cglib.proxy.MethodProxy; +import org.aopalliance.intercept.MethodInterceptor; +import org.aopalliance.intercept.MethodInvocation; /** * Intercepts a method with a stack of interceptors. @@ -36,22 +33,24 @@ import java.util.Set; * @author crazybob@google.com (Bob Lee) */ final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterceptor { - private static final Set<String> AOP_INTERNAL_CLASSES = new HashSet<String>(Arrays.asList( - InterceptorStackCallback.class.getName(), - InterceptedMethodInvocation.class.getName(), - MethodProxy.class.getName())); + private static final Set<String> AOP_INTERNAL_CLASSES = + new HashSet<String>( + Arrays.asList( + InterceptorStackCallback.class.getName(), + InterceptedMethodInvocation.class.getName(), + MethodProxy.class.getName())); final MethodInterceptor[] interceptors; final Method method; - public InterceptorStackCallback(Method method, - List<MethodInterceptor> interceptors) { + public InterceptorStackCallback(Method method, List<MethodInterceptor> interceptors) { this.method = method; this.interceptors = interceptors.toArray(new MethodInterceptor[interceptors.size()]); } - public Object intercept(Object proxy, Method method, Object[] arguments, - MethodProxy methodProxy) throws Throwable { + @Override + public Object intercept(Object proxy, Method method, Object[] arguments, MethodProxy methodProxy) + throws Throwable { return new InterceptedMethodInvocation(proxy, methodProxy, arguments, 0).proceed(); } @@ -62,49 +61,54 @@ final class InterceptorStackCallback implements net.sf.cglib.proxy.MethodInterce final MethodProxy methodProxy; final int index; - public InterceptedMethodInvocation(Object proxy, MethodProxy methodProxy, - Object[] arguments, int index) { + public InterceptedMethodInvocation( + Object proxy, MethodProxy methodProxy, Object[] arguments, int index) { this.proxy = proxy; this.methodProxy = methodProxy; this.arguments = arguments; this.index = index; } + @Override public Object proceed() throws Throwable { try { return index == interceptors.length ? methodProxy.invokeSuper(proxy, arguments) - : interceptors[index].invoke( - new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1)); + : interceptors[index] + .invoke(new InterceptedMethodInvocation(proxy, methodProxy, arguments, index + 1)); } catch (Throwable t) { pruneStacktrace(t); throw t; } } + @Override public Method getMethod() { return method; } + @Override public Object[] getArguments() { return arguments; } + @Override public Object getThis() { return proxy; } + @Override public AccessibleObject getStaticPart() { return getMethod(); } } /** - * Removes stacktrace elements related to AOP internal mechanics from the - * throwable's stack trace and any causes it may have. + * Removes stacktrace elements related to AOP internal mechanics from the throwable's stack trace + * and any causes it may have. */ private void pruneStacktrace(Throwable throwable) { - for(Throwable t = throwable; t != null; t = t.getCause()) { + for (Throwable t = throwable; t != null; t = t.getCause()) { StackTraceElement[] stackTrace = t.getStackTrace(); List<StackTraceElement> pruned = Lists.newArrayList(); for (StackTraceElement element : stackTrace) { diff --git a/core/src/com/google/inject/internal/InternalContext.java b/core/src/com/google/inject/internal/InternalContext.java index 0af19697..59c77c58 100644 --- a/core/src/com/google/inject/internal/InternalContext.java +++ b/core/src/com/google/inject/internal/InternalContext.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,129 +16,153 @@ package com.google.inject.internal; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.inject.Key; import com.google.inject.internal.InjectorImpl.InjectorOptions; import com.google.inject.spi.Dependency; -import com.google.inject.spi.DependencyAndSource; - -import java.util.Arrays; -import java.util.List; +import java.util.IdentityHashMap; import java.util.Map; /** - * Internal context. Used to coordinate injections and support circular - * dependencies. + * Internal context. Used to coordinate injections and support circular dependencies. * * @author crazybob@google.com (Bob Lee) */ -final class InternalContext { +final class InternalContext implements AutoCloseable { private final InjectorOptions options; - private Map<Object, ConstructionContext<?>> constructionContexts = Maps.newHashMap(); + private final Map<Object, ConstructionContext<?>> constructionContexts = + new IdentityHashMap<Object, ConstructionContext<?>>(); /** Keeps track of the type that is currently being requested for injection. */ private Dependency<?> dependency; - /** Keeps track of the hierarchy of types needed during injection. */ - private final DependencyStack state = new DependencyStack(); + /** + * Keeps track of the hierarchy of types needed during injection. + * + * <p>This is a pairwise combination of dependencies and sources, with dependencies or keys on + * even indices, and sources on odd indices. This structure is to avoid the memory overhead of + * DependencyAndSource objects, which can add to several tens of megabytes in large applications. + */ + private Object[] dependencyStack = new Object[16]; + + private int dependencyStackSize = 0; - InternalContext(InjectorOptions options) { + + /** + * The number of times {@link #enter()} has been called + 1 for initial construction. This value + * is decremented when {@link #exit()} is called. + */ + private int enterCount; + + /** + * A single element array to clear when the {@link #enterCount} hits {@code 0}. + * + * <p>This is the value stored in the {@code InjectorImpl.localContext} thread local. + */ + private final Object[] toClear; + + InternalContext(InjectorOptions options, Object[] toClear) { this.options = options; + this.toClear = toClear; + this.enterCount = 1; + } + + /** Should only be called by InjectorImpl.enterContext(). */ + void enter() { + enterCount++; + } + + /** Should be called any any method that received an instance via InjectorImpl.enterContext(). */ + @Override + public void close() { + int newCount = --enterCount; + if (newCount < 0) { + throw new IllegalStateException("Called close() too many times"); + } + if (newCount == 0) { + toClear[0] = null; + } } - public InjectorOptions getInjectorOptions() { + InjectorOptions getInjectorOptions() { return options; } @SuppressWarnings("unchecked") - public <T> ConstructionContext<T> getConstructionContext(Object key) { - ConstructionContext<T> constructionContext - = (ConstructionContext<T>) constructionContexts.get(key); + <T> ConstructionContext<T> getConstructionContext(Object key) { + ConstructionContext<T> constructionContext = + (ConstructionContext<T>) constructionContexts.get(key); if (constructionContext == null) { - constructionContext = new ConstructionContext<T>(); + constructionContext = new ConstructionContext<>(); constructionContexts.put(key, constructionContext); } return constructionContext; } - public Dependency<?> getDependency() { + Dependency<?> getDependency() { return dependency; } /** Sets the new current dependency & adds it to the state. */ - public Dependency<?> pushDependency(Dependency<?> dependency, Object source) { + Dependency<?> pushDependency(Dependency<?> dependency, Object source) { Dependency<?> previous = this.dependency; this.dependency = dependency; - state.add(dependency, source); + doPushState(dependency, source); return previous; } + /** Pops the current state & sets the new dependency. */ - public void popStateAndSetDependency(Dependency<?> newDependency) { - state.pop(); + void popStateAndSetDependency(Dependency<?> newDependency) { + popState(); this.dependency = newDependency; } + /** Adds to the state without setting the dependency. */ - public void pushState(Key<?> key, Object source) { - state.add(key, source); + void pushState(com.google.inject.Key<?> key, Object source) { + doPushState(key, source); } - + + + private void doPushState(Object dependencyOrKey, Object source) { + int localSize = dependencyStackSize; + Object[] localStack = dependencyStack; + if (localStack.length < localSize + 2) { + localStack = dependencyStack = + java.util.Arrays.copyOf(localStack, (localStack.length * 3) / 2 + 2); + } + localStack[localSize++] = dependencyOrKey; + localStack[localSize++] = source; + dependencyStackSize = localSize; + } + + /** Pops from the state without setting a dependency. */ - public void popState() { - state.pop(); + void popState() { + // N.B. we don't null out the array entries. It isn't necessary since all the objects in the + // array (Key, Dependency, or Binding source objects) are all tied to the lifetime of the + // injector, which is greater than the lifetime of this object. So removing them from the array + // doesn't matter. + dependencyStackSize -= 2; } - /** Returns the current dependency chain (all the state). */ - public List<DependencyAndSource> getDependencyChain() { - ImmutableList.Builder<DependencyAndSource> builder = ImmutableList.builder(); - for (int i = 0; i < state.size(); i += 2) { - Object evenEntry = state.get(i); + + /** Returns the current dependency chain (all the state stored in the dependencyStack). */ + java.util.List<com.google.inject.spi.DependencyAndSource> getDependencyChain() { + com.google.common.collect.ImmutableList.Builder<com.google.inject.spi.DependencyAndSource> + builder = com.google.common.collect.ImmutableList.builder(); + for (int i = 0; i < dependencyStackSize; i += 2) { + Object evenEntry = dependencyStack[i]; Dependency<?> dependency; - if (evenEntry instanceof Key) { - dependency = Dependency.get((Key<?>) evenEntry); + if (evenEntry instanceof com.google.inject.Key) { + dependency = Dependency.get((com.google.inject.Key<?>) evenEntry); } else { dependency = (Dependency<?>) evenEntry; } - builder.add(new DependencyAndSource(dependency, state.get(i + 1))); + builder.add(new com.google.inject.spi.DependencyAndSource(dependency, dependencyStack[i + 1])); } return builder.build(); } - /** - * Keeps track of the hierarchy of types needed during injection. - * - * <p>This is a pairwise combination of dependencies and sources, with dependencies or keys on - * even indices, and sources on odd indices. This structure is to avoid the memory overhead of - * DependencyAndSource objects, which can add to several tens of megabytes in large applications. - */ - private static final class DependencyStack { - private Object[] elements = new Object[16]; - private int size = 0; - - public void add(Object dependencyOrKey, Object source) { - if (elements.length < size + 2) { - elements = Arrays.copyOf(elements, (elements.length*3)/2 + 2); - } - elements[size++] = dependencyOrKey; - elements[size++] = source; - } - - public void pop() { - elements[--size] = null; - elements[--size] = null; - } - - public Object get(int i) { - return elements[i]; - } - - public int size() { - return size; - } - } } diff --git a/core/src/com/google/inject/internal/InternalFactory.java b/core/src/com/google/inject/internal/InternalFactory.java index 2267b128..00f0d11a 100644 --- a/core/src/com/google/inject/internal/InternalFactory.java +++ b/core/src/com/google/inject/internal/InternalFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,12 +27,12 @@ interface InternalFactory<T> { /** * Creates an object to be injected. + * * @param context of this injection * @param linked true if getting as a result of a linked binding - * - * @throws com.google.inject.internal.ErrorsException if a value cannot be provided - * @return instance to be injected + * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided + * @return instance that was created */ - T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException; + T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException; } diff --git a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java index c02c70ea..218ce7c1 100644 --- a/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java +++ b/core/src/com/google/inject/internal/InternalFactoryToInitializableAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,11 +22,11 @@ import com.google.inject.spi.Dependency; import com.google.inject.spi.ProviderInstanceBinding; /** - * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies - * fail (or proxy) properly. - * + * Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies fail (or proxy) + * properly. + * * @author sameb@google.com (Sam Berlin) -*/ + */ final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFactory<T> { private final ProvisionListenerStackCallback<T> provisionCallback; @@ -34,29 +34,34 @@ final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFac public InternalFactoryToInitializableAdapter( Initializable<? extends javax.inject.Provider<? extends T>> initializable, - Object source, ProvisionListenerStackCallback<T> provisionCallback) { + Object source, + ProvisionListenerStackCallback<T> provisionCallback) { super(source); - this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback"); + this.provisionCallback = provisionCallback; this.initializable = checkNotNull(initializable, "provider"); } - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - return circularGet(initializable.get(errors), errors, context, dependency, - provisionCallback); + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + return circularGet(initializable.get(), context, dependency, provisionCallback); } - + @Override - protected T provision(javax.inject.Provider<? extends T> provider, Errors errors, - Dependency<?> dependency, ConstructionContext<T> constructionContext) throws ErrorsException { + protected T provision( + javax.inject.Provider<? extends T> provider, + Dependency<?> dependency, + ConstructionContext<T> constructionContext) + throws InternalProvisionException { try { - return super.provision(provider, errors, dependency, constructionContext); - } catch(RuntimeException userException) { - throw errors.withSource(source).errorInProvider(userException).toException(); + return super.provision(provider, dependency, constructionContext); + } catch (RuntimeException userException) { + throw InternalProvisionException.errorInProvider(userException).addSource(source); } } - @Override public String toString() { + @Override + public String toString() { return initializable.toString(); } } diff --git a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java index 4cd1b2e1..690f6836 100644 --- a/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java +++ b/core/src/com/google/inject/internal/InternalFactoryToProviderAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,9 +21,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Provider; import com.google.inject.spi.Dependency; -/** - * @author crazybob@google.com (Bob Lee) -*/ +/** @author crazybob@google.com (Bob Lee) */ final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> { private final Provider<? extends T> provider; @@ -34,17 +32,22 @@ final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> { this.source = checkNotNull(source, "source"); } - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) - throws ErrorsException { - // TODO(sameb): Does this need to push state into the context? + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { try { - return errors.checkForNull(provider.get(), source, dependency); + T t = provider.get(); + if (t == null && !dependency.isNullable()) { + InternalProvisionException.onNullInjectedIntoNonNullableDependency(source, dependency); + } + return t; } catch (RuntimeException userException) { - throw errors.withSource(source).errorInProvider(userException).toException(); + throw InternalProvisionException.errorInProvider(userException).addSource(source); } } - @Override public String toString() { + @Override + public String toString() { return provider.toString(); } } diff --git a/core/src/com/google/inject/internal/InternalFlags.java b/core/src/com/google/inject/internal/InternalFlags.java index 85c07acb..4127ea6d 100644 --- a/core/src/com/google/inject/internal/InternalFlags.java +++ b/core/src/com/google/inject/internal/InternalFlags.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -121,11 +121,14 @@ public class InternalFlags { Class<T> enumType = defaultValue.getDeclaringClass(); String value = null; try { - value = AccessController.doPrivileged(new PrivilegedAction<String>() { - public String run() { - return System.getProperty(name); - } - }); + value = + AccessController.doPrivileged( + new PrivilegedAction<String>() { + @Override + public String run() { + return System.getProperty(name); + } + }); return (value != null && value.length() > 0) ? Enum.valueOf(enumType, value) : defaultValue; } catch (SecurityException e) { return secureValue; diff --git a/core/src/com/google/inject/internal/InternalInjectorCreator.java b/core/src/com/google/inject/internal/InternalInjectorCreator.java index d40bc83b..64c4cf1f 100644 --- a/core/src/com/google/inject/internal/InternalInjectorCreator.java +++ b/core/src/com/google/inject/internal/InternalInjectorCreator.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,6 @@ package com.google.inject.internal; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.Iterables; import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.Key; @@ -30,8 +28,8 @@ import com.google.inject.TypeLiteral; import com.google.inject.internal.util.Stopwatch; import com.google.inject.spi.Dependency; import com.google.inject.spi.TypeConverterBinding; - import java.lang.annotation.Annotation; +import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Map; @@ -43,14 +41,15 @@ import java.util.Set; * top-level injector. * * <p>Injector construction happens in two phases. + * * <ol> - * <li>Static building. In this phase, we interpret commands, create bindings, and inspect + * <li>Static building. In this phase, we interpret commands, create bindings, and inspect * dependencies. During this phase, we hold a lock to ensure consistency with parent injectors. - * No user code is executed in this phase.</li> - * <li>Dynamic injection. In this phase, we call user code. We inject members that requested + * No user code is executed in this phase. + * <li>Dynamic injection. In this phase, we call user code. We inject members that requested * injection. This may require user's objects be created and their providers be called. And we * create eager singletons. In this phase, user code may have started other threads. This phase - * is not executed for injectors created using {@link Stage#TOOL the tool stage}</li> + * is not executed for injectors created using {@link Stage#TOOL the tool stage} * </ol> * * @author crazybob@google.com (Bob Lee) @@ -67,12 +66,12 @@ public final class InternalInjectorCreator { private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder(); private List<InjectorShell> shells; - + public InternalInjectorCreator() { injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer); bindingData = new ProcessedBindingData(); } - + public InternalInjectorCreator stage(Stage stage) { shellBuilder.stage(stage); return this; @@ -146,6 +145,11 @@ public final class InternalInjectorCreator { } stopwatch.resetAndLog("Provider verification"); + // This needs to come late since some user bindings rely on requireBinding calls to create + // jit bindings during the LookupProcessor. + bindingData.initializeDelayedBindings(); + stopwatch.resetAndLog("Delayed Binding initialization"); + for (InjectorShell shell : shells) { if (!shell.getElements().isEmpty()) { throw new AssertionError("Failed to execute " + shell.getElements()); @@ -155,9 +159,7 @@ public final class InternalInjectorCreator { errors.throwCreationExceptionIfErrorsExist(); } - /** - * Returns the injector being constructed. This is not necessarily the root injector. - */ + /** Returns the injector being constructed. This is not necessarily the root injector. */ private Injector primaryInjector() { return shells.get(0).getInjector(); } @@ -175,7 +177,7 @@ public final class InternalInjectorCreator { stopwatch.resetAndLog("Instance injection"); errors.throwCreationExceptionIfErrorsExist(); - if(shellBuilder.getStage() != Stage.TOOL) { + if (shellBuilder.getStage() != Stage.TOOL) { for (InjectorShell shell : shells) { loadEagerSingletons(shell.getInjector(), shellBuilder.getStage(), errors); } @@ -189,33 +191,33 @@ public final class InternalInjectorCreator { * while we're binding these singletons are not be eager. */ void loadEagerSingletons(InjectorImpl injector, Stage stage, final Errors errors) { + List<BindingImpl<?>> candidateBindings = new ArrayList<>(); @SuppressWarnings("unchecked") // casting Collection<Binding> to Collection<BindingImpl> is safe - Iterable<BindingImpl<?>> candidateBindings = ImmutableList.copyOf(Iterables.concat( - (Collection) injector.state.getExplicitBindingsThisLevel().values(), - injector.jitBindings.values())); - for (final BindingImpl<?> binding : candidateBindings) { - if (isEagerSingleton(injector, binding, stage)) { - try { - injector.callInContext(new ContextualCallable<Void>() { - Dependency<?> dependency = Dependency.get(binding.getKey()); - public Void call(InternalContext context) { - Dependency previous = context.pushDependency(dependency, binding.getSource()); - Errors errorsForBinding = errors.withSource(dependency); - try { - binding.getInternalFactory().get(errorsForBinding, context, dependency, false); - } catch (ErrorsException e) { - errorsForBinding.merge(e.getErrors()); - } finally { - context.popStateAndSetDependency(previous); - } - - return null; + Collection<BindingImpl<?>> bindingsAtThisLevel = + (Collection) injector.state.getExplicitBindingsThisLevel().values(); + candidateBindings.addAll(bindingsAtThisLevel); + synchronized (injector.state.lock()) { + // jit bindings must be accessed while holding the lock. + candidateBindings.addAll(injector.jitBindings.values()); + } + InternalContext context = injector.enterContext(); + try { + for (BindingImpl<?> binding : candidateBindings) { + if (isEagerSingleton(injector, binding, stage)) { + Dependency<?> dependency = Dependency.get(binding.getKey()); + Dependency previous = context.pushDependency(dependency, binding.getSource()); + + try { + binding.getInternalFactory().get(context, dependency, false); + } catch (InternalProvisionException e) { + errors.withSource(dependency).merge(e); + } finally { + context.popStateAndSetDependency(previous); } - }); - } catch (ErrorsException e) { - throw new AssertionError(); } } + } finally { + context.close(); } } @@ -238,70 +240,106 @@ public final class InternalInjectorCreator { /** {@link Injector} exposed to users in {@link Stage#TOOL}. */ static class ToolStageInjector implements Injector { private final Injector delegateInjector; - + ToolStageInjector(Injector delegateInjector) { this.delegateInjector = delegateInjector; } + + @Override public void injectMembers(Object o) { throw new UnsupportedOperationException( - "Injector.injectMembers(Object) is not supported in Stage.TOOL"); + "Injector.injectMembers(Object) is not supported in Stage.TOOL"); } + + @Override public Map<Key<?>, Binding<?>> getBindings() { return this.delegateInjector.getBindings(); } + + @Override public Map<Key<?>, Binding<?>> getAllBindings() { return this.delegateInjector.getAllBindings(); } + + @Override public <T> Binding<T> getBinding(Key<T> key) { return this.delegateInjector.getBinding(key); } + + @Override public <T> Binding<T> getBinding(Class<T> type) { return this.delegateInjector.getBinding(type); } + + @Override public <T> Binding<T> getExistingBinding(Key<T> key) { return this.delegateInjector.getExistingBinding(key); } + + @Override public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) { return this.delegateInjector.findBindingsByType(type); } + + @Override public Injector getParent() { return delegateInjector.getParent(); } + + @Override public Injector createChildInjector(Iterable<? extends Module> modules) { return delegateInjector.createChildInjector(modules); } + + @Override public Injector createChildInjector(Module... modules) { return delegateInjector.createChildInjector(modules); } + + @Override public Map<Class<? extends Annotation>, Scope> getScopeBindings() { return delegateInjector.getScopeBindings(); } + + @Override public Set<TypeConverterBinding> getTypeConverterBindings() { return delegateInjector.getTypeConverterBindings(); } + + @Override public <T> Provider<T> getProvider(Key<T> key) { throw new UnsupportedOperationException( - "Injector.getProvider(Key<T>) is not supported in Stage.TOOL"); + "Injector.getProvider(Key<T>) is not supported in Stage.TOOL"); } + + @Override public <T> Provider<T> getProvider(Class<T> type) { throw new UnsupportedOperationException( - "Injector.getProvider(Class<T>) is not supported in Stage.TOOL"); + "Injector.getProvider(Class<T>) is not supported in Stage.TOOL"); } + + @Override public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) { throw new UnsupportedOperationException( - "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL"); + "Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL"); } + + @Override public <T> MembersInjector<T> getMembersInjector(Class<T> type) { throw new UnsupportedOperationException( - "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL"); + "Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL"); } + + @Override public <T> T getInstance(Key<T> key) { throw new UnsupportedOperationException( - "Injector.getInstance(Key<T>) is not supported in Stage.TOOL"); + "Injector.getInstance(Key<T>) is not supported in Stage.TOOL"); } + + @Override public <T> T getInstance(Class<T> type) { throw new UnsupportedOperationException( - "Injector.getInstance(Class<T>) is not supported in Stage.TOOL"); + "Injector.getInstance(Class<T>) is not supported in Stage.TOOL"); } } } diff --git a/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java new file mode 100644 index 00000000..dd941aa7 --- /dev/null +++ b/core/src/com/google/inject/internal/InternalProviderInstanceBindingImpl.java @@ -0,0 +1,195 @@ +package com.google.inject.internal; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Key; +import com.google.inject.Provider; +import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.HasDependencies; +import com.google.inject.spi.InjectionPoint; +import com.google.inject.spi.ProviderWithExtensionVisitor; + +/** + * A {@link ProviderInstanceBindingImpl} for implementing 'native' guice extensions. + * + * <p>Beyond the normal binding contract that is mostly handled by our baseclass, this also + * implements {@link DelayedInitialize} in order to initialize factory state. + */ +final class InternalProviderInstanceBindingImpl<T> extends ProviderInstanceBindingImpl<T> + implements DelayedInitialize { + enum InitializationTiming { + /** This factory can be initialized eagerly. This should be the case for most things. */ + EAGER, + + /** + * Initialization of this factory should be delayed until after all other static initialization + * completes. This will be useful for factories that need to call {@link + * InjectorImpl#getExistingBinding(Key)} to not create jit bindings, but also want to be able to + * conditionally consume jit bindings created by other other bindings. + */ + DELAYED; + } + + private final Factory<T> originalFactory; + + InternalProviderInstanceBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + Factory<T> originalFactory, + InternalFactory<? extends T> scopedFactory, + Scoping scoping) { + super( + injector, + key, + source, + scopedFactory, + scoping, + originalFactory, + ImmutableSet.<InjectionPoint>of()); + this.originalFactory = originalFactory; + } + + InitializationTiming getInitializationTiming() { + return originalFactory.initializationTiming; + } + + @Override + public void initialize(final InjectorImpl injector, final Errors errors) throws ErrorsException { + originalFactory.source = getSource(); + originalFactory.provisionCallback = injector.provisionListenerStore.get(this); + // For these kinds of providers, the 'user supplied provider' is really 'guice supplied' + // So make our user supplied provider just delegate to the guice supplied one. + originalFactory.delegateProvider = getProvider(); + originalFactory.initialize(injector, errors); + } + + /** + * A base factory implementation. Any Factories that delegate to other bindings should use the + * {@code CyclicFactory} subclass, but trivial factories can use this one. + */ + abstract static class Factory<T> implements InternalFactory<T>, Provider<T>, HasDependencies { + private final InitializationTiming initializationTiming; + private Object source; + private Provider<T> delegateProvider; + ProvisionListenerStackCallback<T> provisionCallback; + + Factory(InitializationTiming initializationTiming) { + this.initializationTiming = initializationTiming; + } + /** + * The binding source. + * + * <p>May be useful for augmenting runtime error messages. + * + * <p>Note: this will return {#code null} until {@link #initialize(InjectorImpl, Errors)} has + * already been called. + */ + final Object getSource() { + return source; + } + + /** + * A callback that allows for implementations to fetch dependencies on other bindings. + * + * <p>Will be called exactly once, prior to any call to {@link #doProvision}. + */ + abstract void initialize(InjectorImpl injector, Errors errors) throws ErrorsException; + + @Override + public final T get() { + Provider<T> local = delegateProvider; + if (local == null) { + throw new IllegalStateException( + "This Provider cannot be used until the Injector has been created."); + } + return local.get(); + } + + @Override + public T get(final InternalContext context, final Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + if (provisionCallback == null) { + return doProvision(context, dependency); + } else { + return provisionCallback.provision( + context, + new ProvisionCallback<T>() { + @Override + public T call() throws InternalProvisionException { + return doProvision(context, dependency); + } + }); + } + } + /** + * Creates an object to be injected. + * + * @throws com.google.inject.internal.InternalProvisionException if a value cannot be provided + * @return instance to be injected + */ + protected abstract T doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException; + } + + /** + * An base factory implementation that can be extended to provide a specialized implementation of + * a {@link ProviderWithExtensionVisitor} and also implements {@link InternalFactory} + */ + abstract static class CyclicFactory<T> extends Factory<T> { + + CyclicFactory(InitializationTiming initializationTiming) { + super(initializationTiming); + } + + @Override + public final T get( + final InternalContext context, final Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + final ConstructionContext<T> constructionContext = context.getConstructionContext(this); + // We have a circular reference between bindings. Return a proxy. + if (constructionContext.isConstructing()) { + Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType(); + @SuppressWarnings("unchecked") + T proxyType = + (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType); + return proxyType; + } + // Optimization: Don't go through the callback stack if no one's listening. + constructionContext.startConstruction(); + try { + if (provisionCallback == null) { + return provision(dependency, context, constructionContext); + } else { + return provisionCallback.provision( + context, + new ProvisionCallback<T>() { + @Override + public T call() throws InternalProvisionException { + return provision(dependency, context, constructionContext); + } + }); + } + } finally { + constructionContext.removeCurrentReference(); + constructionContext.finishConstruction(); + } + } + + private T provision( + Dependency<?> dependency, + InternalContext context, + ConstructionContext<T> constructionContext) + throws InternalProvisionException { + try { + T t = doProvision(context, dependency); + constructionContext.setProxyDelegates(t); + return t; + } catch (InternalProvisionException ipe) { + throw ipe.addSource(getSource()); + } catch (Throwable t) { + throw InternalProvisionException.errorInProvider(t).addSource(getSource()); + } + } + } +} diff --git a/core/src/com/google/inject/internal/InternalProvisionException.java b/core/src/com/google/inject/internal/InternalProvisionException.java new file mode 100644 index 00000000..4a49d923 --- /dev/null +++ b/core/src/com/google/inject/internal/InternalProvisionException.java @@ -0,0 +1,228 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.inject.internal; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.inject.Guice; +import com.google.inject.Key; +import com.google.inject.MembersInjector; +import com.google.inject.Provides; +import com.google.inject.ProvisionException; +import com.google.inject.TypeLiteral; +import com.google.inject.internal.util.SourceProvider; +import com.google.inject.internal.util.StackTraceElements; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.InjectionListener; +import com.google.inject.spi.Message; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + * A checked exception for provisioning errors. + * + * <p>This is the internal dual of {@link ProvisionException}, similar to the relationship between + * {@link com.google.inject.ConfigurationException} and {@link ErrorsException}. This is useful for + * several reasons: + * + * <ul> + * <li>Since it is a checked exception, we get some assistance from the java compiler in ensuring + * that we correctly handle it everywhere. ProvisionException is unchecked. + * <li>Since this is an internal package, we can add useful construction and mutation APIs that + * would be undesirable in a public supported API. + * </ul> + * + * <p>This exception will be thrown when errors are encountered during provisioning, ErrorsException + * will continue to be used for errors that are encountered during provisioning and both make use of + * the {@link Message} as the core model. + * + * <p>NOTE: this object stores a list of messages but in the most common case the cardinality will + * be 1. The only time that multiple errors might be reported via this mechanism is when {@link + * #errorInUserCode} is called with an exception that holds multiple errors (like + * ProvisionException). + */ +public final class InternalProvisionException extends Exception { + private static final Logger logger = Logger.getLogger(Guice.class.getName()); + private static final Set<Dependency<?>> warnedDependencies = + Collections.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>()); + + + public static InternalProvisionException circularDependenciesDisabled(Class<?> expectedType) { + return create( + "Found a circular dependency involving %s, and circular dependencies are disabled.", + expectedType); + } + + public static InternalProvisionException cannotProxyClass(Class<?> expectedType) { + return create( + "Tried proxying %s to support a circular dependency, but it is not an interface.", + expectedType); + } + + public static InternalProvisionException create(String format, Object... arguments) { + return new InternalProvisionException(Messages.create(format, arguments)); + } + + public static InternalProvisionException errorInUserCode( + Throwable cause, String messageFormat, Object... arguments) { + Collection<Message> messages = Errors.getMessagesFromThrowable(cause); + if (!messages.isEmpty()) { + // TODO(lukes): it seems like we are dropping some valuable context here.. + // consider eliminating this special case + return new InternalProvisionException(messages); + } else { + return new InternalProvisionException(Messages.create(cause, messageFormat, arguments)); + } + } + + public static InternalProvisionException subtypeNotProvided( + Class<? extends javax.inject.Provider<?>> providerType, Class<?> type) { + return create("%s doesn't provide instances of %s.", providerType, type); + } + + public static InternalProvisionException errorInProvider(Throwable cause) { + return errorInUserCode(cause, "Error in custom provider, %s", cause); + } + + public static InternalProvisionException errorInjectingMethod(Throwable cause) { + return errorInUserCode(cause, "Error injecting method, %s", cause); + } + + public static InternalProvisionException errorInjectingConstructor(Throwable cause) { + return errorInUserCode(cause, "Error injecting constructor, %s", cause); + } + + public static InternalProvisionException errorInUserInjector( + MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) { + return errorInUserCode( + cause, "Error injecting %s using %s.%n Reason: %s", type, listener, cause); + } + + public static InternalProvisionException jitDisabled(Key<?> key) { + return create("Explicit bindings are required and %s is not explicitly bound.", key); + } + + public static InternalProvisionException errorNotifyingInjectionListener( + InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) { + return errorInUserCode( + cause, "Error notifying InjectionListener %s of %s.%n Reason: %s", listener, type, cause); + } + + /** + * Returns {@code value} if it is non-null or allowed to be null. Otherwise a message is added and + * an {@code InternalProvisionException} is thrown. + */ + static void onNullInjectedIntoNonNullableDependency(Object source, Dependency<?> dependency) + throws InternalProvisionException { + // Hack to allow null parameters to @Provides methods, for backwards compatibility. + if (dependency.getInjectionPoint().getMember() instanceof Method) { + Method annotated = (Method) dependency.getInjectionPoint().getMember(); + if (annotated.isAnnotationPresent(Provides.class)) { + switch (InternalFlags.getNullableProvidesOption()) { + case ERROR: + break; // break out & let the below exception happen + case IGNORE: + return; // user doesn't care about injecting nulls to non-@Nullables. + case WARN: + // Warn only once, otherwise we spam logs too much. + if (warnedDependencies.add(dependency)) { + logger.log( + Level.WARNING, + "Guice injected null into {0} (a {1}), please mark it @Nullable." + + " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an" + + " error.", + new Object[] { + Messages.formatParameter(dependency), Messages.convert(dependency.getKey()) + }); + } + return; + } + } + } + + Object formattedDependency = + (dependency.getParameterIndex() != -1) + ? Messages.formatParameter(dependency) + : StackTraceElements.forMember(dependency.getInjectionPoint().getMember()); + + throw InternalProvisionException.create( + "null returned by binding at %s%n but %s is not @Nullable", source, formattedDependency) + .addSource(source); + } + + private final List<Object> sourcesToPrepend = new ArrayList<>(); + private final ImmutableList<Message> errors; + + private InternalProvisionException(Message error) { + this(ImmutableList.of(error)); + } + + private InternalProvisionException(Iterable<Message> errors) { + this.errors = ImmutableList.copyOf(errors); + checkArgument(!this.errors.isEmpty(), "Can't create a provision exception with no errors"); + } + + /** + * Prepends the given {@code source} to the stack of binding sources for the errors reported in + * this exception. + * + * <p>See {@link Errors#withSource(Object)} + * + * <p>It is expected that this method is called as the exception propagates up the stack. + * + * @param source + * @return {@code this} + */ + InternalProvisionException addSource(Object source) { + if (source == SourceProvider.UNKNOWN_SOURCE) { + return this; + } + int sz = sourcesToPrepend.size(); + if (sz > 0 && sourcesToPrepend.get(sz - 1) == source) { + // This is for when there are two identical sources added in a row. This behavior is copied + // from Errors.withSource where it can happen when an constructor/provider method throws an + // exception + return this; + } + sourcesToPrepend.add(source); + return this; + } + + ImmutableList<Message> getErrors() { + ImmutableList.Builder<Message> builder = ImmutableList.builder(); + // reverse them since sources are added as the exception propagates (so the first source is the + // last one added) + List<Object> newSources = Lists.reverse(sourcesToPrepend); + for (Message error : errors) { + builder.add(Messages.mergeSources(newSources, error)); + } + return builder.build(); + } + + /** Returns this exception convered to a ProvisionException. */ + public ProvisionException toProvisionException() { + return new ProvisionException(getErrors()); + } +} diff --git a/core/src/com/google/inject/internal/LinkedBindingImpl.java b/core/src/com/google/inject/internal/LinkedBindingImpl.java index 8f833242..f2e1a03b 100644 --- a/core/src/com/google/inject/internal/LinkedBindingImpl.java +++ b/core/src/com/google/inject/internal/LinkedBindingImpl.java @@ -16,6 +16,7 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; @@ -24,15 +25,19 @@ import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import com.google.inject.spi.LinkedKeyBinding; - import java.util.Set; -public final class LinkedBindingImpl<T> extends BindingImpl<T> implements LinkedKeyBinding<T>, HasDependencies { +public final class LinkedBindingImpl<T> extends BindingImpl<T> + implements LinkedKeyBinding<T>, HasDependencies { final Key<? extends T> targetKey; - public LinkedBindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> internalFactory, Scoping scoping, + public LinkedBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping, Key<? extends T> targetKey) { super(injector, key, source, internalFactory, scoping); this.targetKey = targetKey; @@ -43,32 +48,39 @@ public final class LinkedBindingImpl<T> extends BindingImpl<T> implements Linked this.targetKey = targetKey; } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public Key<? extends T> getLinkedKey() { return targetKey; } + @Override public Set<Dependency<?>> getDependencies() { return ImmutableSet.<Dependency<?>>of(Dependency.get(targetKey)); } + @Override public BindingImpl<T> withScoping(Scoping scoping) { return new LinkedBindingImpl<T>(getSource(), getKey(), scoping, targetKey); } + @Override public BindingImpl<T> withKey(Key<T> key) { return new LinkedBindingImpl<T>(getSource(), key, getScoping(), targetKey); } + @Override public void applyTo(Binder binder) { getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).to(getLinkedKey())); } - @Override public String toString() { - return Objects.toStringHelper(LinkedKeyBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(LinkedKeyBinding.class) .add("key", getKey()) .add("source", getSource()) .add("scope", getScoping()) @@ -78,11 +90,11 @@ public final class LinkedBindingImpl<T> extends BindingImpl<T> implements Linked @Override public boolean equals(Object obj) { - if(obj instanceof LinkedBindingImpl) { - LinkedBindingImpl<?> o = (LinkedBindingImpl<?>)obj; + if (obj instanceof LinkedBindingImpl) { + LinkedBindingImpl<?> o = (LinkedBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(targetKey, o.targetKey); + && getScoping().equals(o.getScoping()) + && Objects.equal(targetKey, o.targetKey); } else { return false; } diff --git a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java index a4a78a58..fa9d7926 100644 --- a/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java +++ b/core/src/com/google/inject/internal/LinkedProviderBindingImpl.java @@ -16,6 +16,7 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; @@ -24,17 +25,20 @@ import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.Dependency; import com.google.inject.spi.HasDependencies; import com.google.inject.spi.ProviderKeyBinding; - import java.util.Set; -final class LinkedProviderBindingImpl<T> - extends BindingImpl<T> implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize { +final class LinkedProviderBindingImpl<T> extends BindingImpl<T> + implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize { final Key<? extends javax.inject.Provider<? extends T>> providerKey; final DelayedInitialize delayedInitializer; - private LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> internalFactory, Scoping scoping, + private LinkedProviderBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping, Key<? extends javax.inject.Provider<? extends T>> providerKey, DelayedInitialize delayedInitializer) { super(injector, key, source, internalFactory, scoping); @@ -42,60 +46,79 @@ final class LinkedProviderBindingImpl<T> this.delayedInitializer = delayedInitializer; } - public LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source, - InternalFactory<? extends T> internalFactory, Scoping scoping, + public LinkedProviderBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping, Key<? extends javax.inject.Provider<? extends T>> providerKey) { this(injector, key, source, internalFactory, scoping, providerKey, null); } - LinkedProviderBindingImpl(Object source, Key<T> key, Scoping scoping, + LinkedProviderBindingImpl( + Object source, + Key<T> key, + Scoping scoping, Key<? extends javax.inject.Provider<? extends T>> providerKey) { super(source, key, scoping); this.providerKey = providerKey; this.delayedInitializer = null; } - static <T> LinkedProviderBindingImpl<T> createWithInitializer(InjectorImpl injector, Key<T> key, - Object source, InternalFactory<? extends T> internalFactory, Scoping scoping, + static <T> LinkedProviderBindingImpl<T> createWithInitializer( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping, Key<? extends javax.inject.Provider<? extends T>> providerKey, DelayedInitialize delayedInitializer) { - return new LinkedProviderBindingImpl<T>(injector, key, source, internalFactory, scoping, - providerKey, delayedInitializer); + return new LinkedProviderBindingImpl<T>( + injector, key, source, internalFactory, scoping, providerKey, delayedInitializer); } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public Key<? extends javax.inject.Provider<? extends T>> getProviderKey() { return providerKey; } + @Override public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { if (delayedInitializer != null) { delayedInitializer.initialize(injector, errors); } } + @Override public Set<Dependency<?>> getDependencies() { return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey)); } + @Override public BindingImpl<T> withScoping(Scoping scoping) { return new LinkedProviderBindingImpl<T>(getSource(), getKey(), scoping, providerKey); } + @Override public BindingImpl<T> withKey(Key<T> key) { return new LinkedProviderBindingImpl<T>(getSource(), key, getScoping(), providerKey); } + @Override public void applyTo(Binder binder) { - getScoping().applyTo(binder.withSource(getSource()) - .bind(getKey()).toProvider(getProviderKey())); + getScoping() + .applyTo(binder.withSource(getSource()).bind(getKey()).toProvider(getProviderKey())); } - @Override public String toString() { - return Objects.toStringHelper(ProviderKeyBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(ProviderKeyBinding.class) .add("key", getKey()) .add("source", getSource()) .add("scope", getScoping()) @@ -105,11 +128,11 @@ final class LinkedProviderBindingImpl<T> @Override public boolean equals(Object obj) { - if(obj instanceof LinkedProviderBindingImpl) { - LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>)obj; + if (obj instanceof LinkedProviderBindingImpl) { + LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(providerKey, o.providerKey); + && getScoping().equals(o.getScoping()) + && Objects.equal(providerKey, o.providerKey); } else { return false; } diff --git a/core/src/com/google/inject/internal/ListenerBindingProcessor.java b/core/src/com/google/inject/internal/ListenerBindingProcessor.java index e8ebed25..e70acb5a 100644 --- a/core/src/com/google/inject/internal/ListenerBindingProcessor.java +++ b/core/src/com/google/inject/internal/ListenerBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -30,13 +30,15 @@ final class ListenerBindingProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(TypeListenerBinding binding) { + @Override + public Boolean visit(TypeListenerBinding binding) { injector.state.addTypeListener(binding); return true; } - - @Override public Boolean visit(ProvisionListenerBinding binding) { + + @Override + public Boolean visit(ProvisionListenerBinding binding) { injector.state.addProvisionListener(binding); return true; } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/LookupProcessor.java b/core/src/com/google/inject/internal/LookupProcessor.java index bf11b833..5e685055 100644 --- a/core/src/com/google/inject/internal/LookupProcessor.java +++ b/core/src/com/google/inject/internal/LookupProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,10 +33,11 @@ final class LookupProcessor extends AbstractProcessor { super(errors); } - @Override public <T> Boolean visit(MembersInjectorLookup<T> lookup) { + @Override + public <T> Boolean visit(MembersInjectorLookup<T> lookup) { try { - MembersInjector<T> membersInjector - = injector.membersInjectorStore.get(lookup.getType(), errors); + MembersInjector<T> membersInjector = + injector.membersInjectorStore.get(lookup.getType(), errors); lookup.initializeDelegate(membersInjector); } catch (ErrorsException e) { errors.merge(e.getErrors()); // TODO: source @@ -45,7 +46,8 @@ final class LookupProcessor extends AbstractProcessor { return true; } - @Override public <T> Boolean visit(ProviderLookup<T> lookup) { + @Override + public <T> Boolean visit(ProviderLookup<T> lookup) { // ensure the provider can be created try { Provider<T> provider = injector.getProviderOrThrow(lookup.getDependency(), errors); diff --git a/core/src/com/google/inject/internal/Lookups.java b/core/src/com/google/inject/internal/Lookups.java index 2b32c7af..d3e64d8c 100644 --- a/core/src/com/google/inject/internal/Lookups.java +++ b/core/src/com/google/inject/internal/Lookups.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/core/src/com/google/inject/internal/MembersInjectorImpl.java b/core/src/com/google/inject/internal/MembersInjectorImpl.java index 498b441b..c1503ead 100644 --- a/core/src/com/google/inject/internal/MembersInjectorImpl.java +++ b/core/src/com/google/inject/internal/MembersInjectorImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,71 +33,77 @@ import com.google.inject.spi.InjectionPoint; final class MembersInjectorImpl<T> implements MembersInjector<T> { private final TypeLiteral<T> typeLiteral; private final InjectorImpl injector; - private final ImmutableList<SingleMemberInjector> memberInjectors; - private final ImmutableSet<MembersInjector<? super T>> userMembersInjectors; - private final ImmutableSet<InjectionListener<? super T>> injectionListeners; - /*if[AOP]*/ - private final ImmutableList<MethodAspect> addedAspects; + // a null list means empty. Since it is common for many of these lists to be empty we can save + // some memory lookups by representing empty as null. + /* @Nullable */ private final ImmutableList<SingleMemberInjector> memberInjectors; + /* @Nullable */ private final ImmutableList<MembersInjector<? super T>> userMembersInjectors; + /* @Nullable */ private final ImmutableList<InjectionListener<? super T>> injectionListeners; + /*if[AOP]*//* @Nullable */ private final ImmutableList<MethodAspect> addedAspects; /*end[AOP]*/ - MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral, - EncounterImpl<T> encounter, ImmutableList<SingleMemberInjector> memberInjectors) { + MembersInjectorImpl( + InjectorImpl injector, + TypeLiteral<T> typeLiteral, + EncounterImpl<T> encounter, + ImmutableList<SingleMemberInjector> memberInjectors) { this.injector = injector; this.typeLiteral = typeLiteral; - this.memberInjectors = memberInjectors; - this.userMembersInjectors = encounter.getMembersInjectors(); - this.injectionListeners = encounter.getInjectionListeners(); + this.memberInjectors = memberInjectors.isEmpty() ? null : memberInjectors; + this.userMembersInjectors = + encounter.getMembersInjectors().isEmpty() ? null : encounter.getMembersInjectors().asList(); + this.injectionListeners = + encounter.getInjectionListeners().isEmpty() + ? null + : encounter.getInjectionListeners().asList(); /*if[AOP]*/ - this.addedAspects = encounter.getAspects(); + this.addedAspects = encounter.getAspects().isEmpty() ? null : encounter.getAspects(); /*end[AOP]*/ } public ImmutableList<SingleMemberInjector> getMemberInjectors() { - return memberInjectors; + return memberInjectors == null ? ImmutableList.<SingleMemberInjector>of() : memberInjectors; } + @Override public void injectMembers(T instance) { - Errors errors = new Errors(typeLiteral); + TypeLiteral<T> localTypeLiteral = typeLiteral; try { - injectAndNotify(instance, errors, null, null, typeLiteral, false); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); + injectAndNotify(instance, null, null, localTypeLiteral, false); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localTypeLiteral).toProvisionException(); } - - errors.throwProvisionExceptionIfErrorsExist(); } - void injectAndNotify(final T instance, - final Errors errors, + void injectAndNotify( + final T instance, final Key<T> key, // possibly null! final ProvisionListenerStackCallback<T> provisionCallback, // possibly null! final Object source, - final boolean toolableOnly) throws ErrorsException { + final boolean toolableOnly) + throws InternalProvisionException { if (instance == null) { return; } - - injector.callInContext(new ContextualCallable<Void>() { - @Override - public Void call(final InternalContext context) throws ErrorsException { - context.pushState(key, source); - try { - if (provisionCallback != null && provisionCallback.hasListeners()) { - provisionCallback.provision(errors, context, new ProvisionCallback<T>() { - @Override public T call() { - injectMembers(instance, errors, context, toolableOnly); + final InternalContext context = injector.enterContext(); + context.pushState(key, source); + try { + if (provisionCallback != null && provisionCallback.hasListeners()) { + provisionCallback.provision( + context, + new ProvisionCallback<T>() { + @Override + public T call() throws InternalProvisionException { + injectMembers(instance, context, toolableOnly); return instance; } }); - } else { - injectMembers(instance, errors, context, toolableOnly); - } - } finally { - context.popState(); - } - return null; + } else { + injectMembers(instance, context, toolableOnly); } - }); + } finally { + context.popState(); + context.close(); + } // TODO: We *could* notify listeners too here, // but it's not clear if we want to. There's no way to know @@ -107,59 +113,80 @@ final class MembersInjectorImpl<T> implements MembersInjector<T> { // if atleast one InjectionPoint was toolable, in which case // the above callInContext could return 'true' if it injected // anything.) - if(!toolableOnly) { - notifyListeners(instance, errors); + if (!toolableOnly) { + notifyListeners(instance); } } - void notifyListeners(T instance, Errors errors) throws ErrorsException { - int numErrorsBefore = errors.size(); - for (InjectionListener<? super T> injectionListener : injectionListeners) { + void notifyListeners(T instance) throws InternalProvisionException { + ImmutableList<InjectionListener<? super T>> localInjectionListeners = injectionListeners; + if (localInjectionListeners == null) { + // no listeners + return; + } + // optimization: use manual for/each to save allocating an iterator here + for (int i = 0; i < localInjectionListeners.size(); i++) { + InjectionListener<? super T> injectionListener = localInjectionListeners.get(i); try { injectionListener.afterInjection(instance); } catch (RuntimeException e) { - errors.errorNotifyingInjectionListener(injectionListener, typeLiteral, e); + throw InternalProvisionException.errorNotifyingInjectionListener( + injectionListener, typeLiteral, e); } } - errors.throwIfNewErrors(numErrorsBefore); } - void injectMembers(T t, Errors errors, InternalContext context, boolean toolableOnly) { - // optimization: use manual for/each to save allocating an iterator here - for (int i = 0, size = memberInjectors.size(); i < size; i++) { - SingleMemberInjector injector = memberInjectors.get(i); - if(!toolableOnly || injector.getInjectionPoint().isToolable()) { - injector.inject(errors, context, t); + void injectMembers(T t, InternalContext context, boolean toolableOnly) + throws InternalProvisionException { + ImmutableList<SingleMemberInjector> localMembersInjectors = memberInjectors; + if (localMembersInjectors != null) { + // optimization: use manual for/each to save allocating an iterator here + for (int i = 0, size = localMembersInjectors.size(); i < size; i++) { + SingleMemberInjector injector = localMembersInjectors.get(i); + if (!toolableOnly || injector.getInjectionPoint().isToolable()) { + injector.inject(context, t); + } } } // TODO: There's no way to know if a user's MembersInjector wants toolable injections. - if(!toolableOnly) { - for (MembersInjector<? super T> userMembersInjector : userMembersInjectors) { - try { - userMembersInjector.injectMembers(t); - } catch (RuntimeException e) { - errors.errorInUserInjector(userMembersInjector, typeLiteral, e); + if (!toolableOnly) { + ImmutableList<MembersInjector<? super T>> localUsersMembersInjectors = userMembersInjectors; + if (localUsersMembersInjectors != null) { + // optimization: use manual for/each to save allocating an iterator here + for (int i = 0; i < localUsersMembersInjectors.size(); i++) { + MembersInjector<? super T> userMembersInjector = localUsersMembersInjectors.get(i); + try { + userMembersInjector.injectMembers(t); + } catch (RuntimeException e) { + throw InternalProvisionException.errorInUserInjector( + userMembersInjector, typeLiteral, e); + } } } } } - @Override public String toString() { + @Override + public String toString() { return "MembersInjector<" + typeLiteral + ">"; } public ImmutableSet<InjectionPoint> getInjectionPoints() { - ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder(); - for (SingleMemberInjector memberInjector : memberInjectors) { - builder.add(memberInjector.getInjectionPoint()); + ImmutableList<SingleMemberInjector> localMemberInjectors = memberInjectors; + if (localMemberInjectors != null) { + ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder(); + for (SingleMemberInjector memberInjector : localMemberInjectors) { + builder.add(memberInjector.getInjectionPoint()); + } + return builder.build(); } - return builder.build(); + return ImmutableSet.of(); } /*if[AOP]*/ public ImmutableList<MethodAspect> getAddedAspects() { - return addedAspects; + return addedAspects == null ? ImmutableList.<MethodAspect>of() : addedAspects; } /*end[AOP]*/ } diff --git a/core/src/com/google/inject/internal/MembersInjectorStore.java b/core/src/com/google/inject/internal/MembersInjectorStore.java index 8e2acdd0..6328902d 100644 --- a/core/src/com/google/inject/internal/MembersInjectorStore.java +++ b/core/src/com/google/inject/internal/MembersInjectorStore.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,7 +24,6 @@ import com.google.inject.TypeLiteral; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.TypeListener; import com.google.inject.spi.TypeListenerBinding; - import java.lang.reflect.Field; import java.util.List; import java.util.Set; @@ -38,16 +37,16 @@ final class MembersInjectorStore { private final InjectorImpl injector; private final ImmutableList<TypeListenerBinding> typeListenerBindings; - private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache - = new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() { - @Override protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors) - throws ErrorsException { - return createWithListeners(type, errors); - } - }; + private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache = + new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() { + @Override + protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors) + throws ErrorsException { + return createWithListeners(type, errors); + } + }; - MembersInjectorStore(InjectorImpl injector, - List<TypeListenerBinding> typeListenerBindings) { + MembersInjectorStore(InjectorImpl injector, List<TypeListenerBinding> typeListenerBindings) { this.injector = injector; this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings); } @@ -60,9 +59,7 @@ final class MembersInjectorStore { return !typeListenerBindings.isEmpty(); } - /** - * Returns a new complete members injector with injection listeners registered. - */ + /** Returns a new complete members injector with injection listeners registered. */ @SuppressWarnings("unchecked") // the MembersInjector type always agrees with the passed type public <T> MembersInjectorImpl<T> get(TypeLiteral<T> key, Errors errors) throws ErrorsException { return (MembersInjectorImpl<T>) cache.get(key, errors); @@ -74,16 +71,14 @@ final class MembersInjectorStore { * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is * necessary.) - * - * Returns true if the type was stored in the cache, false otherwise. + * + * <p>Returns true if the type was stored in the cache, false otherwise. */ boolean remove(TypeLiteral<?> type) { return cache.remove(type); } - /** - * Creates a new members injector and attaches both injection listeners and method aspects. - */ + /** Creates a new members injector and attaches both injection listeners and method aspects. */ private <T> MembersInjectorImpl<T> createWithListeners(TypeLiteral<T> type, Errors errors) throws ErrorsException { int numErrorsBefore = errors.size(); @@ -98,7 +93,7 @@ final class MembersInjectorStore { ImmutableList<SingleMemberInjector> injectors = getInjectors(injectionPoints, errors); errors.throwIfNewErrors(numErrorsBefore); - EncounterImpl<T> encounter = new EncounterImpl<T>(errors, injector.lookups); + EncounterImpl<T> encounter = new EncounterImpl<>(errors, injector.lookups); Set<TypeListener> alreadySeenListeners = Sets.newHashSet(); for (TypeListenerBinding binding : typeListenerBindings) { TypeListener typeListener = binding.getListener(); @@ -117,20 +112,20 @@ final class MembersInjectorStore { return new MembersInjectorImpl<T>(injector, type, encounter, injectors); } - /** - * Returns the injectors for the specified injection points. - */ + /** Returns the injectors for the specified injection points. */ ImmutableList<SingleMemberInjector> getInjectors( Set<InjectionPoint> injectionPoints, Errors errors) { List<SingleMemberInjector> injectors = Lists.newArrayList(); for (InjectionPoint injectionPoint : injectionPoints) { try { - Errors errorsForMember = injectionPoint.isOptional() - ? new Errors(injectionPoint) - : errors.withSource(injectionPoint); - SingleMemberInjector injector = injectionPoint.getMember() instanceof Field - ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember) - : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember); + Errors errorsForMember = + injectionPoint.isOptional() + ? new Errors(injectionPoint) + : errors.withSource(injectionPoint); + SingleMemberInjector injector = + injectionPoint.getMember() instanceof Field + ? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember) + : new SingleMethodInjector(this.injector, injectionPoint, errorsForMember); injectors.add(injector); } catch (ErrorsException ignoredForNow) { // ignored for now diff --git a/core/src/com/google/inject/internal/MessageProcessor.java b/core/src/com/google/inject/internal/MessageProcessor.java index d7c607b1..cb9be021 100644 --- a/core/src/com/google/inject/internal/MessageProcessor.java +++ b/core/src/com/google/inject/internal/MessageProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.internal; import com.google.inject.Guice; import com.google.inject.spi.Message; - import java.util.logging.Level; import java.util.logging.Logger; @@ -36,10 +35,12 @@ final class MessageProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(Message message) { + @Override + public Boolean visit(Message message) { if (message.getCause() != null) { String rootMessage = getRootMessage(message.getCause()); - logger.log(Level.INFO, + logger.log( + Level.INFO, "An exception was caught and reported. Message: " + rootMessage, message.getCause()); } diff --git a/core/src/com/google/inject/internal/Messages.java b/core/src/com/google/inject/internal/Messages.java new file mode 100644 index 00000000..2c80ab23 --- /dev/null +++ b/core/src/com/google/inject/internal/Messages.java @@ -0,0 +1,401 @@ +/* + * Copyright (C) 2017 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.inject.internal; + +import static com.google.common.base.Preconditions.checkArgument; + +import com.google.common.base.Equivalence; +import com.google.common.base.Objects; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.internal.util.Classes; +import com.google.inject.internal.util.StackTraceElements; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.ElementSource; +import com.google.inject.spi.InjectionPoint; +import com.google.inject.spi.Message; +import java.lang.reflect.Field; +import java.lang.reflect.Member; +import java.util.Arrays; +import java.util.Collection; +import java.util.Formatter; +import java.util.List; +import java.util.Map; + +/** Utility methods for {@link Message} objects */ +public final class Messages { + private Messages() {} + + /** Prepends the list of sources to the given {@link Message} */ + static Message mergeSources(List<Object> sources, Message message) { + List<Object> messageSources = message.getSources(); + // It is possible that the end of getSources() and the beginning of message.getSources() are + // equivalent, in this case we should drop the repeated source when joining the lists. The + // most likely scenario where this would happen is when a scoped binding throws an exception, + // due to the fact that InternalFactoryToProviderAdapter applies the binding source when + // merging errors. + if (!sources.isEmpty() + && !messageSources.isEmpty() + && Objects.equal(messageSources.get(0), sources.get(sources.size() - 1))) { + messageSources = messageSources.subList(1, messageSources.size()); + } + return new Message( + ImmutableList.builder().addAll(sources).addAll(messageSources).build(), + message.getMessage(), + message.getCause()); + } + + /** + * Calls {@link String#format} after converting the arguments using some standard guice formatting + * for {@link Key}, {@link Class} and {@link Member} objects. + */ + public static String format(String messageFormat, Object... arguments) { + for (int i = 0; i < arguments.length; i++) { + arguments[i] = convert(arguments[i]); + } + return String.format(messageFormat, arguments); + } + + /** Returns the formatted message for an exception with the specified messages. */ + public static String formatMessages(String heading, Collection<Message> errorMessages) { + Formatter fmt = new Formatter().format(heading).format(":%n%n"); + int index = 1; + boolean displayCauses = getOnlyCause(errorMessages) == null; + + Map<Equivalence.Wrapper<Throwable>, Integer> causes = Maps.newHashMap(); + for (Message errorMessage : errorMessages) { + int thisIdx = index++; + fmt.format("%s) %s%n", thisIdx, errorMessage.getMessage()); + + List<Object> dependencies = errorMessage.getSources(); + for (int i = dependencies.size() - 1; i >= 0; i--) { + Object source = dependencies.get(i); + formatSource(fmt, source); + } + + Throwable cause = errorMessage.getCause(); + if (displayCauses && cause != null) { + Equivalence.Wrapper<Throwable> causeEquivalence = ThrowableEquivalence.INSTANCE.wrap(cause); + if (!causes.containsKey(causeEquivalence)) { + causes.put(causeEquivalence, thisIdx); + fmt.format("Caused by: %s", Throwables.getStackTraceAsString(cause)); + } else { + int causeIdx = causes.get(causeEquivalence); + fmt.format( + "Caused by: %s (same stack trace as error #%s)", + cause.getClass().getName(), causeIdx); + } + } + + fmt.format("%n"); + } + + if (errorMessages.size() == 1) { + fmt.format("1 error"); + } else { + fmt.format("%s errors", errorMessages.size()); + } + + return fmt.toString(); + } + + /** + * Creates a new Message without a cause. + * + * @param messageFormat Format string + * @param arguments format string arguments + */ + public static Message create(String messageFormat, Object... arguments) { + return create(null, messageFormat, arguments); + } + + /** + * Creates a new Message with the given cause. + * + * @param cause The exception that caused the error + * @param messageFormat Format string + * @param arguments format string arguments + */ + public static Message create(Throwable cause, String messageFormat, Object... arguments) { + return create(cause, ImmutableList.of(), messageFormat, arguments); + } + + /** + * Creates a new Message with the given cause and a binding source stack. + * + * @param cause The exception that caused the error + * @param sources The binding sources for the source stack + * @param messageFormat Format string + * @param arguments format string arguments + */ + public static Message create( + Throwable cause, List<Object> sources, String messageFormat, Object... arguments) { + String message = format(messageFormat, arguments); + return new Message(sources, message, cause); + } + + /** Formats an object in a user friendly way. */ + static Object convert(Object o) { + ElementSource source = null; + if (o instanceof ElementSource) { + source = (ElementSource) o; + o = source.getDeclaringSource(); + } + return convert(o, source); + } + + static Object convert(Object o, ElementSource source) { + for (Converter<?> converter : converters) { + if (converter.appliesTo(o)) { + return appendModules(converter.convert(o), source); + } + } + return appendModules(o, source); + } + + private static Object appendModules(Object source, ElementSource elementSource) { + String modules = moduleSourceString(elementSource); + if (modules.length() == 0) { + return source; + } else { + return source + modules; + } + } + + private static String moduleSourceString(ElementSource elementSource) { + // if we only have one module (or don't know what they are), then don't bother + // reporting it, because the source already is going to report exactly that module. + if (elementSource == null) { + return ""; + } + List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames()); + // Insert any original element sources w/ module info into the path. + while (elementSource.getOriginalElementSource() != null) { + elementSource = elementSource.getOriginalElementSource(); + modules.addAll(0, elementSource.getModuleClassNames()); + } + if (modules.size() <= 1) { + return ""; + } + + // Ideally we'd do: + // return Joiner.on(" -> ") + // .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules)) + // .append(")").toString(); + // ... but for some reason we can't find Lists.reverse, so do it the boring way. + StringBuilder builder = new StringBuilder(" (via modules: "); + for (int i = modules.size() - 1; i >= 0; i--) { + builder.append(modules.get(i)); + if (i != 0) { + builder.append(" -> "); + } + } + builder.append(")"); + return builder.toString(); + } + + static void formatSource(Formatter formatter, Object source) { + ElementSource elementSource = null; + if (source instanceof ElementSource) { + elementSource = (ElementSource) source; + source = elementSource.getDeclaringSource(); + } + formatSource(formatter, source, elementSource); + } + + static void formatSource(Formatter formatter, Object source, ElementSource elementSource) { + String modules = moduleSourceString(elementSource); + if (source instanceof Dependency) { + Dependency<?> dependency = (Dependency<?>) source; + InjectionPoint injectionPoint = dependency.getInjectionPoint(); + if (injectionPoint != null) { + formatInjectionPoint(formatter, dependency, injectionPoint, elementSource); + } else { + formatSource(formatter, dependency.getKey(), elementSource); + } + + } else if (source instanceof InjectionPoint) { + formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource); + + } else if (source instanceof Class) { + formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules); + + } else if (source instanceof Member) { + formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules); + + } else if (source instanceof TypeLiteral) { + formatter.format(" while locating %s%s%n", source, modules); + + } else if (source instanceof Key) { + Key<?> key = (Key<?>) source; + formatter.format(" while locating %s%n", convert(key, elementSource)); + + } else if (source instanceof Thread) { + formatter.format(" in thread %s%n", source); + + } else { + formatter.format(" at %s%s%n", source, modules); + } + } + + private static void formatInjectionPoint( + Formatter formatter, + Dependency<?> dependency, + InjectionPoint injectionPoint, + ElementSource elementSource) { + Member member = injectionPoint.getMember(); + Class<? extends Member> memberType = Classes.memberType(member); + + if (memberType == Field.class) { + dependency = injectionPoint.getDependencies().get(0); + formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource)); + formatter.format(" for field at %s%n", StackTraceElements.forMember(member)); + + } else if (dependency != null) { + formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource)); + formatter.format(" for %s%n", formatParameter(dependency)); + + } else { + formatSource(formatter, injectionPoint.getMember()); + } + } + + static String formatParameter(Dependency<?> dependency) { + int ordinal = dependency.getParameterIndex() + 1; + return String.format( + "the %s%s parameter of %s", + ordinal, + getOrdinalSuffix(ordinal), + StackTraceElements.forMember(dependency.getInjectionPoint().getMember())); + } + + /** + * Maps {@code 1} to the string {@code "1st"} ditto for all non-negative numbers + * + * @see <a href="https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers"> + * https://en.wikipedia.org/wiki/English_numerals#Ordinal_numbers</a> + */ + private static String getOrdinalSuffix(int ordinal) { + // negative ordinals don't make sense, we allow zero though because we are programmers + checkArgument(ordinal >= 0); + if ((ordinal / 10) % 10 == 1) { + // all the 'teens' are weird + return "th"; + } else { + // could use a lookup table? any better? + switch (ordinal % 10) { + case 1: + return "st"; + case 2: + return "nd"; + case 3: + return "rd"; + default: + return "th"; + } + } + } + + private abstract static class Converter<T> { + + final Class<T> type; + + Converter(Class<T> type) { + this.type = type; + } + + boolean appliesTo(Object o) { + return o != null && type.isAssignableFrom(o.getClass()); + } + + String convert(Object o) { + return toString(type.cast(o)); + } + + abstract String toString(T t); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) // rawtypes aren't avoidable + private static final Collection<Converter<?>> converters = + ImmutableList.of( + new Converter<Class>(Class.class) { + @Override + public String toString(Class c) { + return c.getName(); + } + }, + new Converter<Member>(Member.class) { + @Override + public String toString(Member member) { + return Classes.toString(member); + } + }, + new Converter<Key>(Key.class) { + @Override + public String toString(Key key) { + if (key.getAnnotationType() != null) { + return key.getTypeLiteral() + + " annotated with " + + (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType()); + } else { + return key.getTypeLiteral().toString(); + } + } + }); + + /** + * Returns the cause throwable if there is exactly one cause in {@code messages}. If there are + * zero or multiple messages with causes, null is returned. + */ + public static Throwable getOnlyCause(Collection<Message> messages) { + Throwable onlyCause = null; + for (Message message : messages) { + Throwable messageCause = message.getCause(); + if (messageCause == null) { + continue; + } + + if (onlyCause != null && !ThrowableEquivalence.INSTANCE.equivalent(onlyCause, messageCause)) { + return null; + } + + onlyCause = messageCause; + } + + return onlyCause; + } + + private static final class ThrowableEquivalence extends Equivalence<Throwable> { + static final ThrowableEquivalence INSTANCE = new ThrowableEquivalence(); + + @Override + protected boolean doEquivalent(Throwable a, Throwable b) { + return a.getClass().equals(b.getClass()) + && Objects.equal(a.getMessage(), b.getMessage()) + && Arrays.equals(a.getStackTrace(), b.getStackTrace()) + && equivalent(a.getCause(), b.getCause()); + } + + @Override + protected int doHash(Throwable t) { + return Objects.hashCode(t.getClass().hashCode(), t.getMessage(), hash(t.getCause())); + } + } +} diff --git a/core/src/com/google/inject/internal/MethodAspect.java b/core/src/com/google/inject/internal/MethodAspect.java index 7bdf193d..d04175fe 100644 --- a/core/src/com/google/inject/internal/MethodAspect.java +++ b/core/src/com/google/inject/internal/MethodAspect.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +19,10 @@ package com.google.inject.internal; import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.matcher.Matcher; - -import org.aopalliance.intercept.MethodInterceptor; - import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; +import org.aopalliance.intercept.MethodInterceptor; /** * Ties a matcher to a method interceptor. @@ -44,15 +42,19 @@ final class MethodAspect { * annotatedWith(Transactional.class)}. * @param interceptors to apply */ - MethodAspect(Matcher<? super Class<?>> classMatcher, - Matcher<? super Method> methodMatcher, List<MethodInterceptor> interceptors) { + MethodAspect( + Matcher<? super Class<?>> classMatcher, + Matcher<? super Method> methodMatcher, + List<MethodInterceptor> interceptors) { this.classMatcher = checkNotNull(classMatcher, "class matcher"); this.methodMatcher = checkNotNull(methodMatcher, "method matcher"); this.interceptors = checkNotNull(interceptors, "interceptors"); } - MethodAspect(Matcher<? super Class<?>> classMatcher, - Matcher<? super Method> methodMatcher, MethodInterceptor... interceptors) { + MethodAspect( + Matcher<? super Class<?>> classMatcher, + Matcher<? super Method> methodMatcher, + MethodInterceptor... interceptors) { this(classMatcher, methodMatcher, Arrays.asList(interceptors)); } diff --git a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java index 85c721d8..74c64b00 100644 --- a/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java +++ b/core/src/com/google/inject/internal/ModuleAnnotatedMethodScannerProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,8 @@ final class ModuleAnnotatedMethodScannerProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(ModuleAnnotatedMethodScannerBinding command) { + @Override + public Boolean visit(ModuleAnnotatedMethodScannerBinding command) { injector.state.addScanner(command); return true; } diff --git a/core/src/com/google/inject/internal/MoreTypes.java b/core/src/com/google/inject/internal/MoreTypes.java index bdf6029a..11e6ab32 100644 --- a/core/src/com/google/inject/internal/MoreTypes.java +++ b/core/src/com/google/inject/internal/MoreTypes.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +14,6 @@ * limitations under the License. */ - package com.google.inject.internal; import static com.google.common.base.Preconditions.checkArgument; @@ -26,7 +25,6 @@ import com.google.inject.ConfigurationException; import com.google.inject.Key; import com.google.inject.TypeLiteral; import com.google.inject.util.Types; - import java.io.Serializable; import java.lang.reflect.Array; import java.lang.reflect.GenericArrayType; @@ -36,12 +34,10 @@ import java.lang.reflect.Type; import java.lang.reflect.TypeVariable; import java.lang.reflect.WildcardType; import java.util.Arrays; -import java.util.Map; import java.util.NoSuchElementException; /** - * Static methods for working with types that we aren't publishing in the - * public {@code Types} API. + * Static methods for working with types that we aren't publishing in the public {@code Types} API. * * @author jessewilson@google.com (Jesse Wilson) */ @@ -51,8 +47,8 @@ public class MoreTypes { private MoreTypes() {} - private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER - = new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>() + private static final ImmutableMap<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER = + new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>() .put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class)) .put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class)) .put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class)) @@ -65,13 +61,12 @@ public class MoreTypes { .build(); /** - * Returns a key that doesn't hold any references to parent classes. - * This is necessary for anonymous keys, so ensure we don't hold a ref - * to the containing module (or class) forever. + * Returns a key that doesn't hold any references to parent classes. This is necessary for + * anonymous keys, so ensure we don't hold a ref to the containing module (or class) forever. */ public static <T> Key<T> canonicalizeKey(Key<T> key) { // If we know this isn't a subclass, return as-is. - // Otherwise, recreate the key to avoid the subclass + // Otherwise, recreate the key to avoid the subclass if (key.getClass() == Key.class) { return key; } else if (key.getAnnotation() != null) { @@ -106,8 +101,9 @@ public class MoreTypes { // the following casts are generally unsafe, but com.google.inject.Provider extends // javax.inject.Provider and is covariant @SuppressWarnings("unchecked") - TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get( - Types.providerOf(parameterizedType.getActualTypeArguments()[0])); + TypeLiteral<T> guiceProviderType = + (TypeLiteral<T>) + TypeLiteral.get(Types.providerOf(parameterizedType.getActualTypeArguments()[0])); return guiceProviderType; } @@ -129,9 +125,7 @@ public class MoreTypes { return recreated; } - /** - * Returns true if {@code type} is free from type variables. - */ + /** Returns true if {@code type} is free from type variables. */ private static boolean isFullySpecified(Type type) { if (type instanceof Class) { return true; @@ -139,7 +133,7 @@ public class MoreTypes { } else if (type instanceof CompositeType) { return ((CompositeType) type).isFullySpecified(); - } else if (type instanceof TypeVariable){ + } else if (type instanceof TypeVariable) { return false; } else { @@ -148,9 +142,8 @@ public class MoreTypes { } /** - * Returns a type that is functionally equal but not necessarily equal - * according to {@link Object#equals(Object) Object.equals()}. The returned - * type is {@link Serializable}. + * Returns a type that is functionally equal but not necessarily equal according to {@link + * Object#equals(Object) Object.equals()}. The returned type is {@link Serializable}. */ public static Type canonicalize(Type type) { if (type instanceof Class) { @@ -162,8 +155,8 @@ public class MoreTypes { } else if (type instanceof ParameterizedType) { ParameterizedType p = (ParameterizedType) type; - return new ParameterizedTypeImpl(p.getOwnerType(), - p.getRawType(), p.getActualTypeArguments()); + return new ParameterizedTypeImpl( + p.getOwnerType(), p.getRawType(), p.getActualTypeArguments()); } else if (type instanceof GenericArrayType) { GenericArrayType g = (GenericArrayType) type; @@ -191,28 +184,33 @@ public class MoreTypes { // Neal isn't either but suspects some pathological case related // to nested classes exists. Type rawType = parameterizedType.getRawType(); - checkArgument(rawType instanceof Class, - "Expected a Class, but <%s> is of type %s", type, type.getClass().getName()); + checkArgument( + rawType instanceof Class, + "Expected a Class, but <%s> is of type %s", + type, + type.getClass().getName()); return (Class<?>) rawType; } else if (type instanceof GenericArrayType) { - Type componentType = ((GenericArrayType)type).getGenericComponentType(); + Type componentType = ((GenericArrayType) type).getGenericComponentType(); return Array.newInstance(getRawType(componentType), 0).getClass(); - } else if (type instanceof TypeVariable) { + } else if (type instanceof TypeVariable || type instanceof WildcardType) { // we could use the variable's bounds, but that'll won't work if there are multiple. - // having a raw type that's more general than necessary is okay + // having a raw type that's more general than necessary is okay return Object.class; } else { - throw new IllegalArgumentException("Expected a Class, ParameterizedType, or " - + "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName()); + throw new IllegalArgumentException( + "Expected a Class, ParameterizedType, or " + + "GenericArrayType, but <" + + type + + "> is of type " + + type.getClass().getName()); } } - /** - * Returns true if {@code a} and {@code b} are equal. - */ + /** Returns true if {@code a} and {@code b} are equal. */ public static boolean equals(Type a, Type b) { if (a == b) { // also handles (a == null && b == null) @@ -278,8 +276,8 @@ public class MoreTypes { /** * Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet}, - * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result - * when the supertype is {@code Collection.class} is {@code Collection<Integer>}. + * the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result when + * the supertype is {@code Collection.class} is {@code Collection<Integer>}. */ public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) { if (toResolve == rawType) { @@ -347,9 +345,7 @@ public class MoreTypes { */ private static Class<?> declaringClassOf(TypeVariable typeVariable) { GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration(); - return genericDeclaration instanceof Class - ? (Class<?>) genericDeclaration - : null; + return genericDeclaration instanceof Class ? (Class<?>) genericDeclaration : null; } public static class ParameterizedTypeImpl @@ -372,18 +368,22 @@ public class MoreTypes { } } + @Override public Type[] getActualTypeArguments() { return typeArguments.clone(); } + @Override public Type getRawType() { return rawType; } + @Override public Type getOwnerType() { return ownerType; } + @Override public boolean isFullySpecified() { if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) { return false; @@ -402,18 +402,19 @@ public class MoreTypes { return true; } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof ParameterizedType && MoreTypes.equals(this, (ParameterizedType) other); } - @Override public int hashCode() { - return Arrays.hashCode(typeArguments) - ^ rawType.hashCode() - ^ hashCodeOrZero(ownerType); + @Override + public int hashCode() { + return Arrays.hashCode(typeArguments) ^ rawType.hashCode() ^ hashCodeOrZero(ownerType); } - @Override public String toString() { + @Override + public String toString() { StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1)); stringBuilder.append(typeToString(rawType)); @@ -431,10 +432,14 @@ public class MoreTypes { private static void ensureOwnerType(Type ownerType, Type rawType) { if (rawType instanceof Class<?>) { Class rawTypeAsClass = (Class) rawType; - checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null, - "No owner type for enclosed %s", rawType); - checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null, - "Owner type for unenclosed %s", rawType); + checkArgument( + ownerType != null || rawTypeAsClass.getEnclosingClass() == null, + "No owner type for enclosed %s", + rawType); + checkArgument( + ownerType == null || rawTypeAsClass.getEnclosingClass() != null, + "Owner type for unenclosed %s", + rawType); } } @@ -449,24 +454,28 @@ public class MoreTypes { this.componentType = canonicalize(componentType); } + @Override public Type getGenericComponentType() { return componentType; } + @Override public boolean isFullySpecified() { return MoreTypes.isFullySpecified(componentType); } - @Override public boolean equals(Object o) { - return o instanceof GenericArrayType - && MoreTypes.equals(this, (GenericArrayType) o); + @Override + public boolean equals(Object o) { + return o instanceof GenericArrayType && MoreTypes.equals(this, (GenericArrayType) o); } - @Override public int hashCode() { + @Override + public int hashCode() { return componentType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return typeToString(componentType) + "[]"; } @@ -474,9 +483,9 @@ public class MoreTypes { } /** - * The WildcardType interface supports multiple upper bounds and multiple - * lower bounds. We only support what the Java 6 language needs - at most one - * bound. If a lower bound is set, the upper bound must be Object.class. + * The WildcardType interface supports multiple upper bounds and multiple lower bounds. We only + * support what the Java 6 language needs - at most one bound. If a lower bound is set, the upper + * bound must be Object.class. */ public static class WildcardTypeImpl implements WildcardType, Serializable, CompositeType { private final Type upperBound; @@ -501,31 +510,35 @@ public class MoreTypes { } } + @Override public Type[] getUpperBounds() { - return new Type[] { upperBound }; + return new Type[] {upperBound}; } + @Override public Type[] getLowerBounds() { - return lowerBound != null ? new Type[] { lowerBound } : EMPTY_TYPE_ARRAY; + return lowerBound != null ? new Type[] {lowerBound} : EMPTY_TYPE_ARRAY; } + @Override public boolean isFullySpecified() { return MoreTypes.isFullySpecified(upperBound) && (lowerBound == null || MoreTypes.isFullySpecified(lowerBound)); } - @Override public boolean equals(Object other) { - return other instanceof WildcardType - && MoreTypes.equals(this, (WildcardType) other); + @Override + public boolean equals(Object other) { + return other instanceof WildcardType && MoreTypes.equals(this, (WildcardType) other); } - @Override public int hashCode() { - // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()); - return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) - ^ (31 + upperBound.hashCode()); + @Override + public int hashCode() { + // this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds()); + return (lowerBound != null ? 31 + lowerBound.hashCode() : 1) ^ (31 + upperBound.hashCode()); } - @Override public String toString() { + @Override + public String toString() { if (lowerBound != null) { return "? super " + typeToString(lowerBound); } else if (upperBound == Object.class) { @@ -539,8 +552,11 @@ public class MoreTypes { } private static void checkNotPrimitive(Type type, String use) { - checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(), - "Primitive types are not allowed in %s: %s", use, type); + checkArgument( + !(type instanceof Class<?>) || !((Class) type).isPrimitive(), + "Primitive types are not allowed in %s: %s", + use, + type); } /** A type formed from other types, such as arrays, parameterized types or wildcard types */ diff --git a/core/src/com/google/inject/internal/Nullability.java b/core/src/com/google/inject/internal/Nullability.java index 76f7e765..c8da51de 100644 --- a/core/src/com/google/inject/internal/Nullability.java +++ b/core/src/com/google/inject/internal/Nullability.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,14 +21,13 @@ import java.lang.annotation.Annotation; /** * Whether a member supports null values injected. * - * <p>Support for {@code Nullable} annotations in Guice is loose. - * Any annotation type whose simplename is "Nullable" is sufficient to indicate - * support for null values injected. + * <p>Support for {@code Nullable} annotations in Guice is loose. Any annotation type whose + * simplename is "Nullable" is sufficient to indicate support for null values injected. * - * <p>This allows support for JSR-305's - * <a href="http://groups.google.com/group/jsr-305/web/proposed-annotations"> - * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's - * <a href="http://www.jetbrains.com/idea/documentation/howto.html"> + * <p>This allows support for JSR-305's <a + * href="http://groups.google.com/group/jsr-305/web/proposed-annotations"> + * javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's <a + * href="http://www.jetbrains.com/idea/documentation/howto.html"> * org.jetbrains.annotations.Nullable</a>. * * @author jessewilson@google.com (Jesse Wilson) @@ -37,7 +36,7 @@ public class Nullability { private Nullability() {} public static boolean allowsNull(Annotation[] annotations) { - for(Annotation a : annotations) { + for (Annotation a : annotations) { Class<? extends Annotation> type = a.annotationType(); if ("Nullable".equals(type.getSimpleName())) { return true; diff --git a/core/src/com/google/inject/internal/PrivateElementProcessor.java b/core/src/com/google/inject/internal/PrivateElementProcessor.java index 4a641a98..7d45a7dd 100644 --- a/core/src/com/google/inject/internal/PrivateElementProcessor.java +++ b/core/src/com/google/inject/internal/PrivateElementProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.internal; import com.google.common.collect.Lists; import com.google.inject.spi.PrivateElements; - import java.util.List; /** @@ -34,10 +33,10 @@ final class PrivateElementProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(PrivateElements privateElements) { - InjectorShell.Builder builder = new InjectorShell.Builder() - .parent(injector) - .privateElements(privateElements); + @Override + public Boolean visit(PrivateElements privateElements) { + InjectorShell.Builder builder = + new InjectorShell.Builder().parent(injector).privateElements(privateElements); injectorShellBuilders.add(builder); return true; } diff --git a/core/src/com/google/inject/internal/PrivateElementsImpl.java b/core/src/com/google/inject/internal/PrivateElementsImpl.java index 6a3d9158..3ae71ccc 100644 --- a/core/src/com/google/inject/internal/PrivateElementsImpl.java +++ b/core/src/com/google/inject/internal/PrivateElementsImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Preconditions.checkState; -import com.google.common.base.Objects; +import com.google.common.base.MoreObjects; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; @@ -32,14 +32,11 @@ import com.google.inject.PrivateBinder; import com.google.inject.spi.Element; import com.google.inject.spi.ElementVisitor; import com.google.inject.spi.PrivateElements; - import java.util.List; import java.util.Map; import java.util.Set; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ public final class PrivateElementsImpl implements PrivateElements { /* @@ -58,16 +55,19 @@ public final class PrivateElementsImpl implements PrivateElements { /** lazily instantiated */ private ImmutableMap<Key<?>, Object> exposedKeysToSources; + private Injector injector; public PrivateElementsImpl(Object source) { this.source = checkNotNull(source, "source"); } + @Override public Object getSource() { return source; } + @Override public List<Element> getElements() { if (elements == null) { elements = ImmutableList.copyOf(elementsMutable); @@ -77,6 +77,7 @@ public final class PrivateElementsImpl implements PrivateElements { return elements; } + @Override public Injector getInjector() { return injector; } @@ -86,6 +87,7 @@ public final class PrivateElementsImpl implements PrivateElements { this.injector = checkNotNull(injector, "injector"); } + @Override public Set<Key<?>> getExposedKeys() { if (exposedKeysToSources == null) { Map<Key<?>, Object> exposedKeysToSourcesMutable = Maps.newLinkedHashMap(); @@ -99,6 +101,7 @@ public final class PrivateElementsImpl implements PrivateElements { return exposedKeysToSources.keySet(); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } @@ -111,6 +114,7 @@ public final class PrivateElementsImpl implements PrivateElements { exposureBuilders.add(exposureBuilder); } + @Override public void applyTo(Binder binder) { PrivateBinder privateBinder = binder.withSource(source).newPrivateBinder(); @@ -124,6 +128,7 @@ public final class PrivateElementsImpl implements PrivateElements { } } + @Override public Object getExposedSource(Key<?> key) { getExposedKeys(); // ensure exposedKeysToSources is populated Object source = exposedKeysToSources.get(key); @@ -131,8 +136,9 @@ public final class PrivateElementsImpl implements PrivateElements { return source; } - @Override public String toString() { - return Objects.toStringHelper(PrivateElements.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(PrivateElements.class) .add("exposedKeys", getExposedKeys()) .add("source", getSource()) .toString(); diff --git a/core/src/com/google/inject/internal/ProcessedBindingData.java b/core/src/com/google/inject/internal/ProcessedBindingData.java index 8cd26027..86a26c60 100644 --- a/core/src/com/google/inject/internal/ProcessedBindingData.java +++ b/core/src/com/google/inject/internal/ProcessedBindingData.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,38 +17,58 @@ package com.google.inject.internal; import com.google.common.collect.Lists; - import java.util.List; /** - * Keeps track of creation listeners & uninitialized bindings, - * so they can be processed after bindings are recorded. - * + * Keeps track of creation listeners & uninitialized bindings, so they can be processed after + * bindings are recorded. + * * @author sameb@google.com (Sam Berlin) */ class ProcessedBindingData { - + private final List<CreationListener> creationListeners = Lists.newArrayList(); private final List<Runnable> uninitializedBindings = Lists.newArrayList(); - + private final List<Runnable> delayedUninitializedBindings = Lists.newArrayList(); + void addCreationListener(CreationListener listener) { creationListeners.add(listener); } - + void addUninitializedBinding(Runnable runnable) { uninitializedBindings.add(runnable); } - + + void addDelayedUninitializedBinding(Runnable runnable) { + delayedUninitializedBindings.add(runnable); + } + + /** Initialize bindings. This may be done eagerly */ void initializeBindings() { for (Runnable initializer : uninitializedBindings) { initializer.run(); } } + /** + * Runs creation listeners. + * + * <p>TODO(lukes): figure out exactly why this case exists. + */ void runCreationListeners(Errors errors) { for (CreationListener creationListener : creationListeners) { creationListener.notify(errors); } } + /** + * Initialized bindings that need to be delayed until after all injection points and other + * bindings are processed. The main current usecase for this is resolving Optional dependencies + * for OptionalBinder bindings. + */ + void initializeDelayedBindings() { + for (Runnable initializer : delayedUninitializedBindings) { + initializer.run(); + } + } } diff --git a/core/src/com/google/inject/internal/ProvidedByInternalFactory.java b/core/src/com/google/inject/internal/ProvidedByInternalFactory.java index 1591c508..9d67374d 100644 --- a/core/src/com/google/inject/internal/ProvidedByInternalFactory.java +++ b/core/src/com/google/inject/internal/ProvidedByInternalFactory.java @@ -14,79 +14,85 @@ * limitations under the License. */ - package com.google.inject.internal; -import static com.google.common.base.Preconditions.checkState; - import com.google.inject.Key; import com.google.inject.ProvidedBy; -import com.google.inject.Provider; import com.google.inject.internal.InjectorImpl.JitLimitation; import com.google.inject.spi.Dependency; +import javax.inject.Provider; /** * An {@link InternalFactory} for {@literal @}{@link ProvidedBy} bindings. - * + * * @author sameb@google.com (Sam Berlin) */ -class ProvidedByInternalFactory<T> extends ProviderInternalFactory<T> - implements DelayedInitialize { - +class ProvidedByInternalFactory<T> extends ProviderInternalFactory<T> implements DelayedInitialize { + private final Class<?> rawType; private final Class<? extends Provider<?>> providerType; private final Key<? extends Provider<T>> providerKey; private BindingImpl<? extends Provider<T>> providerBinding; private ProvisionListenerStackCallback<T> provisionCallback; - + ProvidedByInternalFactory( Class<?> rawType, Class<? extends Provider<?>> providerType, Key<? extends Provider<T>> providerKey) { super(providerKey); this.rawType = rawType; - this.providerType = providerType; + this.providerType = providerType; this.providerKey = providerKey; } - + void setProvisionListenerCallback(ProvisionListenerStackCallback<T> listener) { provisionCallback = listener; } - + + @Override public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { providerBinding = injector.getBindingOrThrow(providerKey, errors, JitLimitation.NEW_OR_EXISTING_JIT); } - public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked) - throws ErrorsException { - checkState(providerBinding != null, "not initialized"); - - context.pushState(providerKey, providerBinding.getSource()); + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) + throws InternalProvisionException { + BindingImpl<? extends Provider<T>> localProviderBinding = providerBinding; + if (localProviderBinding == null) { + throw new IllegalStateException("not initialized"); + } + Key<? extends Provider<T>> localProviderKey = providerKey; + context.pushState(localProviderKey, localProviderBinding.getSource()); + try { - errors = errors.withSource(providerKey); - Provider<? extends T> provider = providerBinding.getInternalFactory().get( - errors, context, dependency, true); - return circularGet(provider, errors, context, dependency, provisionCallback); - } finally { - context.popState(); + Provider<? extends T> provider = + localProviderBinding.getInternalFactory().get(context, dependency, true); + return circularGet(provider, context, dependency, provisionCallback); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localProviderKey); + } finally { + context.popState(); + } } - + @Override - protected T provision(javax.inject.Provider<? extends T> provider, Errors errors, - Dependency<?> dependency, ConstructionContext<T> constructionContext) - throws ErrorsException { + protected T provision( + javax.inject.Provider<? extends T> provider, + Dependency<?> dependency, + ConstructionContext<T> constructionContext) + throws InternalProvisionException { try { - Object o = super.provision(provider, errors, dependency, constructionContext); + Object o = super.provision(provider, dependency, constructionContext); if (o != null && !rawType.isInstance(o)) { - throw errors.subtypeNotProvided(providerType, rawType).toException(); + throw InternalProvisionException.subtypeNotProvided(providerType, rawType); } @SuppressWarnings("unchecked") // protected by isInstance() check above T t = (T) o; return t; } catch (RuntimeException e) { - throw errors.errorInProvider(e).toException(); + throw InternalProvisionException.errorInProvider(e).addSource(source); } } } diff --git a/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java b/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java index f254b418..8db5a3e9 100644 --- a/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java +++ b/core/src/com/google/inject/internal/ProviderInstanceBindingImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,6 +16,7 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; @@ -28,17 +29,19 @@ import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.ProviderInstanceBinding; import com.google.inject.spi.ProviderWithExtensionVisitor; import com.google.inject.util.Providers; - import java.util.Set; -final class ProviderInstanceBindingImpl<T> extends BindingImpl<T> - implements ProviderInstanceBinding<T> { +class ProviderInstanceBindingImpl<T> extends BindingImpl<T> implements ProviderInstanceBinding<T> { final javax.inject.Provider<? extends T> providerInstance; final ImmutableSet<InjectionPoint> injectionPoints; - public ProviderInstanceBindingImpl(InjectorImpl injector, Key<T> key, - Object source, InternalFactory<? extends T> internalFactory, Scoping scoping, + public ProviderInstanceBindingImpl( + InjectorImpl injector, + Key<T> key, + Object source, + InternalFactory<? extends T> internalFactory, + Scoping scoping, javax.inject.Provider<? extends T> providerInstance, Set<InjectionPoint> injectionPoints) { super(injector, key, source, internalFactory, scoping); @@ -46,16 +49,21 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T> this.injectionPoints = ImmutableSet.copyOf(injectionPoints); } - public ProviderInstanceBindingImpl(Object source, Key<T> key, Scoping scoping, - Set<InjectionPoint> injectionPoints, javax.inject.Provider<? extends T> providerInstance) { + public ProviderInstanceBindingImpl( + Object source, + Key<T> key, + Scoping scoping, + Set<InjectionPoint> injectionPoints, + javax.inject.Provider<? extends T> providerInstance) { super(source, key, scoping); this.injectionPoints = ImmutableSet.copyOf(injectionPoints); this.providerInstance = providerInstance; } + @Override @SuppressWarnings("unchecked") // the extension type is always consistent with the provider type public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { - if(providerInstance instanceof ProviderWithExtensionVisitor) { + if (providerInstance instanceof ProviderWithExtensionVisitor) { return ((ProviderWithExtensionVisitor<? extends T>) providerInstance) .acceptExtensionVisitor(visitor, this); } else { @@ -66,39 +74,46 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T> public Provider<? extends T> getProviderInstance() { return Providers.guicify(providerInstance); } - + + @Override public javax.inject.Provider<? extends T> getUserSuppliedProvider() { return providerInstance; } + @Override public Set<InjectionPoint> getInjectionPoints() { return injectionPoints; } + @Override public Set<Dependency<?>> getDependencies() { return providerInstance instanceof HasDependencies ? ImmutableSet.copyOf(((HasDependencies) providerInstance).getDependencies()) : Dependency.forInjectionPoints(injectionPoints); } + @Override public BindingImpl<T> withScoping(Scoping scoping) { return new ProviderInstanceBindingImpl<T>( getSource(), getKey(), scoping, injectionPoints, providerInstance); } + @Override public BindingImpl<T> withKey(Key<T> key) { return new ProviderInstanceBindingImpl<T>( getSource(), key, getScoping(), injectionPoints, providerInstance); } + @Override public void applyTo(Binder binder) { - getScoping().applyTo( - binder.withSource(getSource()).bind(getKey()).toProvider(getUserSuppliedProvider())); + getScoping() + .applyTo( + binder.withSource(getSource()).bind(getKey()).toProvider(getUserSuppliedProvider())); } @Override public String toString() { - return Objects.toStringHelper(ProviderInstanceBinding.class) + return MoreObjects.toStringHelper(ProviderInstanceBinding.class) .add("key", getKey()) .add("source", getSource()) .add("scope", getScoping()) @@ -108,11 +123,11 @@ final class ProviderInstanceBindingImpl<T> extends BindingImpl<T> @Override public boolean equals(Object obj) { - if(obj instanceof ProviderInstanceBindingImpl) { - ProviderInstanceBindingImpl<?> o = (ProviderInstanceBindingImpl<?>)obj; + if (obj instanceof ProviderInstanceBindingImpl) { + ProviderInstanceBindingImpl<?> o = (ProviderInstanceBindingImpl<?>) obj; return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()) - && Objects.equal(providerInstance, o.providerInstance); + && getScoping().equals(o.getScoping()) + && Objects.equal(providerInstance, o.providerInstance); } else { return false; } diff --git a/core/src/com/google/inject/internal/ProviderInternalFactory.java b/core/src/com/google/inject/internal/ProviderInternalFactory.java index 8574535d..0cd6fc2b 100644 --- a/core/src/com/google/inject/internal/ProviderInternalFactory.java +++ b/core/src/com/google/inject/internal/ProviderInternalFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,57 +14,58 @@ * limitations under the License. */ - package com.google.inject.internal; import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback; import com.google.inject.spi.Dependency; - import javax.inject.Provider; /** - * Base class for InternalFactories that are used by Providers, to handle - * circular dependencies. + * Base class for InternalFactories that are used by Providers, to handle circular dependencies. * * @author sameb@google.com (Sam Berlin) */ abstract class ProviderInternalFactory<T> implements InternalFactory<T> { - + protected final Object source; - + ProviderInternalFactory(Object source) { this.source = checkNotNull(source, "source"); } - - protected T circularGet(final Provider<? extends T> provider, final Errors errors, - InternalContext context, final Dependency<?> dependency, - ProvisionListenerStackCallback<T> provisionCallback) - throws ErrorsException { + + protected T circularGet( + final Provider<? extends T> provider, + InternalContext context, + final Dependency<?> dependency, + /* @Nullable */ ProvisionListenerStackCallback<T> provisionCallback) + throws InternalProvisionException { final ConstructionContext<T> constructionContext = context.getConstructionContext(this); // We have a circular reference between constructors. Return a proxy. if (constructionContext.isConstructing()) { - Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType(); - // TODO: if we can't proxy this object, can we proxy the other object? - @SuppressWarnings("unchecked") - T proxyType = (T) constructionContext.createProxy( - errors, context.getInjectorOptions(), expectedType); - return proxyType; + Class<?> expectedType = dependency.getKey().getTypeLiteral().getRawType(); + // TODO: if we can't proxy this object, can we proxy the other object? + @SuppressWarnings("unchecked") + T proxyType = (T) constructionContext.createProxy(context.getInjectorOptions(), expectedType); + return proxyType; } // Optimization: Don't go through the callback stack if no one's listening. constructionContext.startConstruction(); try { - if (!provisionCallback.hasListeners()) { - return provision(provider, errors, dependency, constructionContext); + if (provisionCallback == null) { + return provision(provider, dependency, constructionContext); } else { - return provisionCallback.provision(errors, context, new ProvisionCallback<T>() { - public T call() throws ErrorsException { - return provision(provider, errors, dependency, constructionContext); - } - }); + return provisionCallback.provision( + context, + new ProvisionCallback<T>() { + @Override + public T call() throws InternalProvisionException { + return provision(provider, dependency, constructionContext); + } + }); } } finally { constructionContext.removeCurrentReference(); @@ -73,12 +74,18 @@ abstract class ProviderInternalFactory<T> implements InternalFactory<T> { } /** - * Provisions a new instance. Subclasses should override this to catch - * exceptions & rethrow as ErrorsExceptions. + * Provisions a new instance. Subclasses should override this to catch exceptions & rethrow as + * ErrorsExceptions. */ - protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency, - ConstructionContext<T> constructionContext) throws ErrorsException { - T t = errors.checkForNull(provider.get(), source, dependency); + protected T provision( + Provider<? extends T> provider, + Dependency<?> dependency, + ConstructionContext<T> constructionContext) + throws InternalProvisionException { + T t = provider.get(); + if (t == null && !dependency.isNullable()) { + InternalProvisionException.onNullInjectedIntoNonNullableDependency(source, dependency); + } constructionContext.setProxyDelegates(t); return t; } diff --git a/core/src/com/google/inject/internal/ProviderMethod.java b/core/src/com/google/inject/internal/ProviderMethod.java index beaf406e..0723252d 100644 --- a/core/src/com/google/inject/internal/ProviderMethod.java +++ b/core/src/com/google/inject/internal/ProviderMethod.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,15 +17,13 @@ package com.google.inject.internal; import com.google.common.base.Objects; -import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.inject.Binder; import com.google.inject.Exposed; import com.google.inject.Key; import com.google.inject.PrivateBinder; -import com.google.inject.Provider; import com.google.inject.Provides; -import com.google.inject.internal.BytecodeGen.Visibility; +import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming; import com.google.inject.internal.util.StackTraceElements; import com.google.inject.spi.BindingTargetVisitor; import com.google.inject.spi.Dependency; @@ -34,12 +32,10 @@ import com.google.inject.spi.ProviderInstanceBinding; import com.google.inject.spi.ProviderWithExtensionVisitor; import com.google.inject.spi.ProvidesMethodBinding; import com.google.inject.spi.ProvidesMethodTargetVisitor; - import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.util.List; import java.util.Set; /** @@ -47,50 +43,47 @@ import java.util.Set; * * @author jessewilson@google.com (Jesse Wilson) */ -public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor<T>, HasDependencies, - ProvidesMethodBinding<T> { +public abstract class ProviderMethod<T> extends InternalProviderInstanceBindingImpl.CyclicFactory<T> + implements HasDependencies, ProvidesMethodBinding<T>, ProviderWithExtensionVisitor<T> { /** * Creates a {@link ProviderMethod}. * - * <p>Unless {@code skipFastClassGeneration} is set, this will use - * {@link net.sf.cglib.reflect.FastClass} to invoke the actual method, since it is significantly - * faster. However, this will fail if the method is {@code private} or {@code protected}, since - * fastclass is subject to java access policies. + * <p>Unless {@code skipFastClassGeneration} is set, this will use {@link + * net.sf.cglib.reflect.FastClass} to invoke the actual method, since it is significantly faster. + * However, this will fail if the method is {@code private} or {@code protected}, since fastclass + * is subject to java access policies. */ - static <T> ProviderMethod<T> create(Key<T> key, Method method, Object instance, - ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders, - Class<? extends Annotation> scopeAnnotation, boolean skipFastClassGeneration, + static <T> ProviderMethod<T> create( + Key<T> key, + Method method, + Object instance, + ImmutableSet<Dependency<?>> dependencies, + Class<? extends Annotation> scopeAnnotation, + boolean skipFastClassGeneration, Annotation annotation) { int modifiers = method.getModifiers(); /*if[AOP]*/ - if (!skipFastClassGeneration && !Modifier.isPrivate(modifiers) - && !Modifier.isProtected(modifiers)) { + if (!skipFastClassGeneration) { try { - // We use an index instead of FastMethod to save a stack frame. - return new FastClassProviderMethod<T>(key, - method, - instance, - dependencies, - parameterProviders, - scopeAnnotation, - annotation); - } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */} + net.sf.cglib.reflect.FastClass fc = BytecodeGen.newFastClassForMember(method); + if (fc != null) { + return new FastClassProviderMethod<T>( + key, fc, method, instance, dependencies, scopeAnnotation, annotation); + } + } catch (net.sf.cglib.core.CodeGenerationException e) { + /* fall-through */ + } } /*end[AOP]*/ - if (!Modifier.isPublic(modifiers) || - !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { + if (!Modifier.isPublic(modifiers) + || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { method.setAccessible(true); } - return new ReflectionProviderMethod<T>(key, - method, - instance, - dependencies, - parameterProviders, - scopeAnnotation, - annotation); + return new ReflectionProviderMethod<T>( + key, method, instance, dependencies, scopeAnnotation, annotation); } protected final Object instance; @@ -99,22 +92,30 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor< private final Key<T> key; private final Class<? extends Annotation> scopeAnnotation; private final ImmutableSet<Dependency<?>> dependencies; - private final List<Provider<?>> parameterProviders; private final boolean exposed; private final Annotation annotation; /** - * @param method the method to invoke. It's return type must be the same type as {@code key}. + * Set by {@link #initialize(InjectorImpl, Errors)} so it is always available prior to injection. */ - private ProviderMethod(Key<T> key, Method method, Object instance, - ImmutableSet<Dependency<?>> dependencies, List<Provider<?>> parameterProviders, - Class<? extends Annotation> scopeAnnotation, Annotation annotation) { + private SingleParameterInjector<?>[] parameterInjectors; + + /** @param method the method to invoke. It's return type must be the same type as {@code key}. */ + private ProviderMethod( + Key<T> key, + Method method, + Object instance, + ImmutableSet<Dependency<?>> dependencies, + Class<? extends Annotation> scopeAnnotation, + Annotation annotation) { + // We can be safely initialized eagerly since our bindings must exist statically and it is an + // error for them not to. + super(InitializationTiming.EAGER); this.key = key; this.scopeAnnotation = scopeAnnotation; this.instance = instance; this.dependencies = dependencies; this.method = method; - this.parameterProviders = parameterProviders; this.exposed = method.isAnnotationPresent(Exposed.class); this.annotation = annotation; } @@ -133,12 +134,12 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor< public Object getInstance() { return instance; } - + @Override public Object getEnclosingInstance() { return instance; } - + @Override public Annotation getAnnotation() { return annotation; @@ -161,43 +162,48 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor< } @Override - public T get() { - Object[] parameters = new Object[parameterProviders.size()]; - for (int i = 0; i < parameters.length; i++) { - parameters[i] = parameterProviders.get(i).get(); - } + void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + parameterInjectors = injector.getParametersInjectors(dependencies.asList(), errors); + } + @Override + protected T doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException { try { - @SuppressWarnings({ "unchecked", "UnnecessaryLocalVariable" }) - T result = (T) doProvision(parameters); - return result; + T t = doProvision(SingleParameterInjector.getAll(context, parameterInjectors)); + if (t == null && !dependency.isNullable()) { + InternalProvisionException.onNullInjectedIntoNonNullableDependency(getMethod(), dependency); + } + return t; } catch (IllegalAccessException e) { throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw Exceptions.rethrowCause(e); + } catch (InvocationTargetException userException) { + Throwable cause = userException.getCause() != null ? userException.getCause() : userException; + throw InternalProvisionException.errorInProvider(cause).addSource(getSource()); } } /** Extension point for our subclasses to implement the provisioning strategy. */ - abstract Object doProvision(Object[] parameters) + abstract T doProvision(Object[] parameters) throws IllegalAccessException, InvocationTargetException; @Override public Set<Dependency<?>> getDependencies() { return dependencies; } - + @Override @SuppressWarnings("unchecked") - public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor, - ProviderInstanceBinding<? extends B> binding) { + public <B, V> V acceptExtensionVisitor( + BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding) { if (visitor instanceof ProvidesMethodTargetVisitor) { - return ((ProvidesMethodTargetVisitor<T, V>)visitor).visit(this); + return ((ProvidesMethodTargetVisitor<T, V>) visitor).visit(this); } return visitor.visit(binding); } - @Override public String toString() { + @Override + public String toString() { String annotationString = annotation.toString(); // Show @Provides w/o the com.google.inject prefix. if (annotation.annotationType() == Provides.class) { @@ -208,19 +214,19 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor< } return annotationString + " " + StackTraceElements.forMember(method); } - + @Override public boolean equals(Object obj) { if (obj instanceof ProviderMethod) { ProviderMethod<?> o = (ProviderMethod<?>) obj; return method.equals(o.method) - && instance.equals(o.instance) - && annotation.equals(o.annotation); + && instance.equals(o.instance) + && annotation.equals(o.annotation); } else { return false; } } - + @Override public int hashCode() { // Avoid calling hashCode on 'instance', which is a user-object @@ -238,65 +244,46 @@ public abstract class ProviderMethod<T> implements ProviderWithExtensionVisitor< final net.sf.cglib.reflect.FastClass fastClass; final int methodIndex; - FastClassProviderMethod(Key<T> key, + FastClassProviderMethod( + Key<T> key, + net.sf.cglib.reflect.FastClass fc, Method method, Object instance, ImmutableSet<Dependency<?>> dependencies, - List<Provider<?>> parameterProviders, Class<? extends Annotation> scopeAnnotation, Annotation annotation) { - super(key, - method, - instance, - dependencies, - parameterProviders, - scopeAnnotation, - annotation); - // We need to generate a FastClass for the method's class, not the object's class. - this.fastClass = - BytecodeGen.newFastClass(method.getDeclaringClass(), Visibility.forMember(method)); - // Use the Signature overload of getIndex because it properly uses return types to identify - // particular methods. This is normally irrelevant, except in the case of covariant overrides - // which java implements with a compiler generated bridge method to implement the override. - this.methodIndex = fastClass.getIndex( - new net.sf.cglib.core.Signature( - method.getName(), org.objectweb.asm.Type.getMethodDescriptor(method))); - Preconditions.checkArgument(this.methodIndex >= 0, - "Could not find method %s in fast class for class %s", - method, - method.getDeclaringClass()); + super(key, method, instance, dependencies, scopeAnnotation, annotation); + this.fastClass = fc; + this.methodIndex = fc.getMethod(method).getIndex(); } - @Override public Object doProvision(Object[] parameters) + @SuppressWarnings("unchecked") + @Override + public T doProvision(Object[] parameters) throws IllegalAccessException, InvocationTargetException { - return fastClass.invoke(methodIndex, instance, parameters); + return (T) fastClass.invoke(methodIndex, instance, parameters); } } /*end[AOP]*/ /** - * A {@link ProviderMethod} implementation that invokes the method using normal java reflection. + * A {@link ProviderMethod} implementation that invokes the method using normal java reflection. */ private static final class ReflectionProviderMethod<T> extends ProviderMethod<T> { - ReflectionProviderMethod(Key<T> key, + ReflectionProviderMethod( + Key<T> key, Method method, Object instance, ImmutableSet<Dependency<?>> dependencies, - List<Provider<?>> parameterProviders, Class<? extends Annotation> scopeAnnotation, Annotation annotation) { - super(key, - method, - instance, - dependencies, - parameterProviders, - scopeAnnotation, - annotation); + super(key, method, instance, dependencies, scopeAnnotation, annotation); } - @Override Object doProvision(Object[] parameters) throws IllegalAccessException, - InvocationTargetException { - return method.invoke(instance, parameters); + @SuppressWarnings("unchecked") + @Override + T doProvision(Object[] parameters) throws IllegalAccessException, InvocationTargetException { + return (T) method.invoke(instance, parameters); } } } diff --git a/core/src/com/google/inject/internal/ProviderMethodsModule.java b/core/src/com/google/inject/internal/ProviderMethodsModule.java index 7682dab5..a854f73f 100644 --- a/core/src/com/google/inject/internal/ProviderMethodsModule.java +++ b/core/src/com/google/inject/internal/ProviderMethodsModule.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,30 +18,26 @@ package com.google.inject.internal; import static com.google.common.base.Preconditions.checkNotNull; -import com.google.common.base.Optional; import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Multimap; import com.google.inject.Binder; import com.google.inject.Key; import com.google.inject.Module; -import com.google.inject.Provider; import com.google.inject.Provides; import com.google.inject.TypeLiteral; -import com.google.inject.spi.Dependency; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.Message; import com.google.inject.spi.ModuleAnnotatedMethodScanner; import com.google.inject.util.Modules; - import java.lang.annotation.Annotation; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.Arrays; import java.util.List; -import java.util.Set; /** * Creates bindings to methods annotated with {@literal @}{@link Provides}. Use the scope and @@ -51,61 +47,42 @@ import java.util.Set; * @author jessewilson@google.com (Jesse Wilson) */ public final class ProviderMethodsModule implements Module { - - private static ModuleAnnotatedMethodScanner PROVIDES_BUILDER = - new ModuleAnnotatedMethodScanner() { - @Override - public <T> Key<T> prepareMethod( - Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) { - return key; - } - - @Override - public Set<? extends Class<? extends Annotation>> annotationClasses() { - return ImmutableSet.of(Provides.class); - } - }; - private final Object delegate; private final TypeLiteral<?> typeLiteral; private final boolean skipFastClassGeneration; private final ModuleAnnotatedMethodScanner scanner; - private ProviderMethodsModule(Object delegate, boolean skipFastClassGeneration, - ModuleAnnotatedMethodScanner scanner) { + private ProviderMethodsModule( + Object delegate, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) { this.delegate = checkNotNull(delegate, "delegate"); this.typeLiteral = TypeLiteral.get(this.delegate.getClass()); this.skipFastClassGeneration = skipFastClassGeneration; this.scanner = scanner; } - /** - * Returns a module which creates bindings for provider methods from the given module. - */ + /** Returns a module which creates bindings for provider methods from the given module. */ public static Module forModule(Module module) { - return forObject(module, false, PROVIDES_BUILDER); + return forObject(module, false, ProvidesMethodScanner.INSTANCE); } - /** - * Returns a module which creates bindings methods in the module that match the scanner. - */ + /** Returns a module which creates bindings methods in the module that match the scanner. */ public static Module forModule(Object module, ModuleAnnotatedMethodScanner scanner) { return forObject(module, false, scanner); } /** - * Returns a module which creates bindings for provider methods from the given object. - * This is useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a> + * Returns a module which creates bindings for provider methods from the given object. This is + * useful notably for <a href="http://code.google.com/p/google-gin/">GIN</a> * * <p>This will skip bytecode generation for provider methods, since it is assumed that callers * are only interested in Module metadata. */ public static Module forObject(Object object) { - return forObject(object, true, PROVIDES_BUILDER); + return forObject(object, true, ProvidesMethodScanner.INSTANCE); } - private static Module forObject(Object object, boolean skipFastClassGeneration, - ModuleAnnotatedMethodScanner scanner) { + private static Module forObject( + Object object, boolean skipFastClassGeneration, ModuleAnnotatedMethodScanner scanner) { // avoid infinite recursion, since installing a module always installs itself if (object instanceof ProviderMethodsModule) { return Modules.EMPTY_MODULE; @@ -119,91 +96,115 @@ public final class ProviderMethodsModule implements Module { } @Override - public synchronized void configure(Binder binder) { + public void configure(Binder binder) { for (ProviderMethod<?> providerMethod : getProviderMethods(binder)) { providerMethod.configure(binder); } } public List<ProviderMethod<?>> getProviderMethods(Binder binder) { - List<ProviderMethod<?>> result = Lists.newArrayList(); - Multimap<Signature, Method> methodsBySignature = HashMultimap.create(); + List<ProviderMethod<?>> result = null; + // The highest class in the type hierarchy that contained a provider method definition. + Class<?> superMostClass = delegate.getClass(); for (Class<?> c = delegate.getClass(); c != Object.class; c = c.getSuperclass()) { for (Method method : c.getDeclaredMethods()) { - // private/static methods cannot override or be overridden by other methods, so there is no - // point in indexing them. - // Skip synthetic methods and bridge methods since java will automatically generate - // synthetic overrides in some cases where we don't want to generate an error (e.g. - // increasing visibility of a subclass). - if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0) - && !method.isBridge() && !method.isSynthetic()) { - methodsBySignature.put(new Signature(method), method); - } - Optional<Annotation> annotation = isProvider(binder, method); - if (annotation.isPresent()) { - result.add(createProviderMethod(binder, method, annotation.get())); + Annotation annotation = getAnnotation(binder, method); + if (annotation != null) { + if (result == null) { + result = Lists.newArrayList(); + } + result.add(createProviderMethod(binder, method, annotation)); + superMostClass = c; } } } - // we have found all the providers and now need to identify if any were overridden - // In the worst case this will have O(n^2) in the number of @Provides methods, but that is only - // assuming that every method is an override, in general it should be very quick. - for (ProviderMethod<?> provider : result) { - Method method = provider.getMethod(); - for (Method matchingSignature : methodsBySignature.get(new Signature(method))) { - // matching signature is in the same class or a super class, therefore method cannot be - // overridding it. - if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { - continue; + if (result == null) { + // We didn't find anything + return ImmutableList.of(); + } + // We have found some provider methods, now we need to check if any were overridden. + // We do this as a separate pass to avoid calculating all the signatures when there are no + // provides methods, or when all provides methods are defined in a single class. + Multimap<Signature, Method> methodsBySignature = null; + // We can stop scanning when we see superMostClass, since no superclass method can override + // a method in a subclass. Corrollary, if superMostClass == delegate.getClass(), there can be + // no overrides of a provides method. + for (Class<?> c = delegate.getClass(); c != superMostClass; c = c.getSuperclass()) { + for (Method method : c.getDeclaredMethods()) { + if (((method.getModifiers() & (Modifier.PRIVATE | Modifier.STATIC)) == 0) + && !method.isBridge() + && !method.isSynthetic()) { + if (methodsBySignature == null) { + methodsBySignature = HashMultimap.create(); + } + methodsBySignature.put(new Signature(typeLiteral, method), method); } - // now we know matching signature is in a subtype of method.getDeclaringClass() - if (overrides(matchingSignature, method)) { - String annotationString = provider.getAnnotation().annotationType() == Provides.class - ? "@Provides" : "@" + provider.getAnnotation().annotationType().getCanonicalName(); - binder.addError( - "Overriding " + annotationString + " methods is not allowed." - + "\n\t" + annotationString + " method: %s\n\toverridden by: %s", - method, - matchingSignature); - break; + } + } + if (methodsBySignature != null) { + // we have found all the signatures and now need to identify if any were overridden + // In the worst case this will have O(n^2) in the number of @Provides methods, but that is + // only assuming that every method is an override, in general it should be very quick. + for (ProviderMethod<?> provider : result) { + Method method = provider.getMethod(); + for (Method matchingSignature : + methodsBySignature.get(new Signature(typeLiteral, method))) { + // matching signature is in the same class or a super class, therefore method cannot be + // overridding it. + if (matchingSignature.getDeclaringClass().isAssignableFrom(method.getDeclaringClass())) { + continue; + } + // now we know matching signature is in a subtype of method.getDeclaringClass() + if (overrides(matchingSignature, method)) { + String annotationString = + provider.getAnnotation().annotationType() == Provides.class + ? "@Provides" + : "@" + provider.getAnnotation().annotationType().getCanonicalName(); + binder.addError( + "Overriding " + + annotationString + + " methods is not allowed." + + "\n\t" + + annotationString + + " method: %s\n\toverridden by: %s", + method, + matchingSignature); + break; + } } } } return result; } - /** - * Returns true if the method is a provider. - * - * Synthetic bridge methods are excluded. Starting with JDK 8, javac copies annotations onto - * bridge methods (which always have erased signatures). - */ - private Optional<Annotation> isProvider(Binder binder, Method method) { + /** Returns the annotation that is claimed by the scanner, or null if there is none. */ + private Annotation getAnnotation(Binder binder, Method method) { if (method.isBridge() || method.isSynthetic()) { - return Optional.absent(); + return null; } Annotation annotation = null; for (Class<? extends Annotation> annotationClass : scanner.annotationClasses()) { Annotation foundAnnotation = method.getAnnotation(annotationClass); if (foundAnnotation != null) { if (annotation != null) { - binder.addError("More than one annotation claimed by %s on method %s." - + " Methods can only have one annotation claimed per scanner.", + binder.addError( + "More than one annotation claimed by %s on method %s." + + " Methods can only have one annotation claimed per scanner.", scanner, method); - return Optional.absent(); + return null; } annotation = foundAnnotation; } } - return Optional.fromNullable(annotation); + return annotation; } - private final class Signature { + private static final class Signature { final Class<?>[] parameters; final String name; final int hashCode; - Signature(Method method) { + Signature(TypeLiteral<?> typeLiteral, Method method) { this.name = method.getName(); // We need to 'resolve' the parameters against the actual class type in case this method uses // type parameters. This is so we can detect overrides of generic superclass methods where @@ -219,7 +220,8 @@ public final class ProviderMethodsModule implements Module { this.hashCode = name.hashCode() + 31 * Arrays.hashCode(parameters); } - @Override public boolean equals(Object obj) { + @Override + public boolean equals(Object obj) { if (obj instanceof Signature) { Signature other = (Signature) obj; return other.name.equals(name) && Arrays.equals(parameters, other.parameters); @@ -227,7 +229,8 @@ public final class ProviderMethodsModule implements Module { return false; } - @Override public int hashCode() { + @Override + public int hashCode() { return hashCode; } } @@ -246,34 +249,34 @@ public final class ProviderMethodsModule implements Module { return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage()); } - private <T> ProviderMethod<T> createProviderMethod(Binder binder, Method method, - Annotation annotation) { + private <T> ProviderMethod<T> createProviderMethod( + Binder binder, Method method, Annotation annotation) { binder = binder.withSource(method); Errors errors = new Errors(method); // prepare the parameter providers InjectionPoint point = InjectionPoint.forMethod(method, typeLiteral); - List<Dependency<?>> dependencies = point.getDependencies(); - List<Provider<?>> parameterProviders = Lists.newArrayList(); - for (Dependency<?> dependency : point.getDependencies()) { - parameterProviders.add(binder.getProvider(dependency)); - } - @SuppressWarnings("unchecked") // Define T as the method's return type. TypeLiteral<T> returnType = (TypeLiteral<T>) typeLiteral.getReturnType(method); Key<T> key = getKey(errors, returnType, method, method.getAnnotations()); try { key = scanner.prepareMethod(binder, annotation, key, point); - } catch(Throwable t) { + } catch (Throwable t) { binder.addError(t); } - Class<? extends Annotation> scopeAnnotation - = Annotations.findScopeAnnotation(errors, method.getAnnotations()); + Class<? extends Annotation> scopeAnnotation = + Annotations.findScopeAnnotation(errors, method.getAnnotations()); for (Message message : errors.getMessages()) { binder.addError(message); } - return ProviderMethod.create(key, method, delegate, ImmutableSet.copyOf(dependencies), - parameterProviders, scopeAnnotation, skipFastClassGeneration, annotation); + return ProviderMethod.create( + key, + method, + delegate, + ImmutableSet.copyOf(point.getDependencies()), + scopeAnnotation, + skipFastClassGeneration, + annotation); } <T> Key<T> getKey(Errors errors, TypeLiteral<T> type, Member member, Annotation[] annotations) { @@ -281,13 +284,15 @@ public final class ProviderMethodsModule implements Module { return bindingAnnotation == null ? Key.get(type) : Key.get(type, bindingAnnotation); } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof ProviderMethodsModule && ((ProviderMethodsModule) o).delegate == delegate && ((ProviderMethodsModule) o).scanner == scanner; } - @Override public int hashCode() { + @Override + public int hashCode() { return delegate.hashCode(); } } diff --git a/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java b/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java index 672cf25c..490684dc 100644 --- a/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java +++ b/core/src/com/google/inject/internal/ProviderToInternalFactoryAdapter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,43 +17,42 @@ package com.google.inject.internal; import com.google.inject.Provider; -import com.google.inject.ProvisionException; -import com.google.inject.spi.Dependency; -/** - * @author crazybob@google.com (Bob Lee) - */ +/** @author crazybob@google.com (Bob Lee) */ final class ProviderToInternalFactoryAdapter<T> implements Provider<T> { private final InjectorImpl injector; private final InternalFactory<? extends T> internalFactory; - public ProviderToInternalFactoryAdapter(InjectorImpl injector, - InternalFactory<? extends T> internalFactory) { + public ProviderToInternalFactoryAdapter( + InjectorImpl injector, InternalFactory<? extends T> internalFactory) { this.injector = injector; this.internalFactory = internalFactory; } + @Override public T get() { - final Errors errors = new Errors(); + InternalContext context = injector.enterContext(); try { - T t = injector.callInContext(new ContextualCallable<T>() { - public T call(InternalContext context) throws ErrorsException { - Dependency dependency = context.getDependency(); - // Always pretend that we are a linked binding, to support - // scoping implicit bindings. If we are not actually a linked - // binding, we'll fail properly elsewhere in the chain. - return internalFactory.get(errors, context, dependency, true); - } - }); - errors.throwIfNewErrors(0); + // Always pretend that we are a linked binding, to support + // scoping implicit bindings. If we are not actually a linked + // binding, we'll fail properly elsewhere in the chain. + T t = internalFactory.get(context, context.getDependency(), true); return t; - } catch (ErrorsException e) { - throw new ProvisionException(errors.merge(e.getErrors()).getMessages()); + } catch (InternalProvisionException e) { + throw e.toProvisionException(); + } finally { + context.close(); } } - @Override public String toString() { + /** Exposed for SingletonScope. */ + InjectorImpl getInjector() { + return injector; + } + + @Override + public String toString() { return internalFactory.toString(); } } diff --git a/core/src/com/google/inject/internal/ProvidesMethodScanner.java b/core/src/com/google/inject/internal/ProvidesMethodScanner.java new file mode 100644 index 00000000..f7709b21 --- /dev/null +++ b/core/src/com/google/inject/internal/ProvidesMethodScanner.java @@ -0,0 +1,182 @@ +/* + * Copyright (C) 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.internal; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.Provides; +import com.google.inject.TypeLiteral; +import com.google.inject.multibindings.MapKey; +import com.google.inject.multibindings.ProvidesIntoMap; +import com.google.inject.multibindings.ProvidesIntoOptional; +import com.google.inject.multibindings.ProvidesIntoSet; +import com.google.inject.spi.InjectionPoint; +import com.google.inject.spi.ModuleAnnotatedMethodScanner; +import java.lang.annotation.Annotation; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Set; + +/** + * A {@link ModuleAnnotatedMethodScanner} that handles the {@Provides}, {@link ProvidesIntoSet}, + * {@link ProvidesIntoMap} and {@link ProvidesIntoOptional} annotations. + * + * <p>This is the default scanner used by ProviderMethodsModule and handles all the built in + * annotations. + */ +final class ProvidesMethodScanner extends ModuleAnnotatedMethodScanner { + static final ProvidesMethodScanner INSTANCE = new ProvidesMethodScanner(); + private static final ImmutableSet<Class<? extends Annotation>> ANNOTATIONS = + ImmutableSet.of( + Provides.class, ProvidesIntoSet.class, ProvidesIntoMap.class, ProvidesIntoOptional.class); + + private ProvidesMethodScanner() {} + + @Override + public Set<? extends Class<? extends Annotation>> annotationClasses() { + return ANNOTATIONS; + } + + @SuppressWarnings({"unchecked", "rawtypes"}) // mapKey doesn't know its key type + @Override + public <T> Key<T> prepareMethod( + Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) { + Method method = (Method) injectionPoint.getMember(); + AnnotationOrError mapKey = findMapKeyAnnotation(binder, method); + if (annotation instanceof Provides) { + if (mapKey.annotation != null) { + binder.addError("Found a MapKey annotation on non map binding at %s.", method); + } + // no key rewriting for plain old @Provides + return key; + } + if (annotation instanceof ProvidesIntoSet) { + if (mapKey.annotation != null) { + binder.addError("Found a MapKey annotation on non map binding at %s.", method); + } + return RealMultibinder.newRealSetBinder(binder, key).getKeyForNewItem(); + } else if (annotation instanceof ProvidesIntoMap) { + if (mapKey.error) { + // Already failed on the MapKey, don't bother doing more work. + return key; + } + if (mapKey.annotation == null) { + // If no MapKey, make an error and abort. + binder.addError("No MapKey found for map binding at %s.", method); + return key; + } + TypeAndValue typeAndValue = typeAndValueOfMapKey(mapKey.annotation); + return RealMapBinder.newRealMapBinder(binder, typeAndValue.type, key) + .getKeyForNewValue(typeAndValue.value); + } else if (annotation instanceof ProvidesIntoOptional) { + if (mapKey.annotation != null) { + binder.addError("Found a MapKey annotation on non map binding at %s.", method); + } + switch (((ProvidesIntoOptional) annotation).value()) { + case DEFAULT: + return RealOptionalBinder.newRealOptionalBinder(binder, key).getKeyForDefaultBinding(); + case ACTUAL: + return RealOptionalBinder.newRealOptionalBinder(binder, key).getKeyForActualBinding(); + } + } + throw new IllegalStateException("Invalid annotation: " + annotation); + } + + private static class AnnotationOrError { + final Annotation annotation; + final boolean error; + + AnnotationOrError(Annotation annotation, boolean error) { + this.annotation = annotation; + this.error = error; + } + + static AnnotationOrError forPossiblyNullAnnotation(Annotation annotation) { + return new AnnotationOrError(annotation, false); + } + + static AnnotationOrError forError() { + return new AnnotationOrError(null, true); + } + } + + private static AnnotationOrError findMapKeyAnnotation(Binder binder, Method method) { + Annotation foundAnnotation = null; + for (Annotation annotation : method.getAnnotations()) { + MapKey mapKey = annotation.annotationType().getAnnotation(MapKey.class); + if (mapKey != null) { + if (foundAnnotation != null) { + binder.addError("Found more than one MapKey annotations on %s.", method); + return AnnotationOrError.forError(); + } + if (mapKey.unwrapValue()) { + try { + // validate there's a declared method called "value" + Method valueMethod = annotation.annotationType().getDeclaredMethod("value"); + if (valueMethod.getReturnType().isArray()) { + binder.addError( + "Array types are not allowed in a MapKey with unwrapValue=true: %s", + annotation.annotationType()); + return AnnotationOrError.forError(); + } + } catch (NoSuchMethodException invalid) { + binder.addError( + "No 'value' method in MapKey with unwrapValue=true: %s", + annotation.annotationType()); + return AnnotationOrError.forError(); + } + } + foundAnnotation = annotation; + } + } + return AnnotationOrError.forPossiblyNullAnnotation(foundAnnotation); + } + + @SuppressWarnings({"unchecked", "rawtypes"}) + static TypeAndValue<?> typeAndValueOfMapKey(Annotation mapKeyAnnotation) { + if (!mapKeyAnnotation.annotationType().getAnnotation(MapKey.class).unwrapValue()) { + return new TypeAndValue(TypeLiteral.get(mapKeyAnnotation.annotationType()), mapKeyAnnotation); + } else { + try { + Method valueMethod = mapKeyAnnotation.annotationType().getDeclaredMethod("value"); + valueMethod.setAccessible(true); + TypeLiteral<?> returnType = + TypeLiteral.get(mapKeyAnnotation.annotationType()).getReturnType(valueMethod); + return new TypeAndValue(returnType, valueMethod.invoke(mapKeyAnnotation)); + } catch (NoSuchMethodException e) { + throw new IllegalStateException(e); + } catch (SecurityException e) { + throw new IllegalStateException(e); + } catch (IllegalAccessException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw new IllegalStateException(e); + } + } + } + + private static class TypeAndValue<T> { + final TypeLiteral<T> type; + final T value; + + TypeAndValue(TypeLiteral<T> type, T value) { + this.type = type; + this.value = value; + } + } +} diff --git a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java index 10746285..0e000dd9 100644 --- a/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java +++ b/core/src/com/google/inject/internal/ProvisionListenerCallbackStore.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,9 +28,7 @@ import com.google.inject.Key; import com.google.inject.Stage; import com.google.inject.spi.ProvisionListener; import com.google.inject.spi.ProvisionListenerBinding; - import java.util.List; -import java.util.Set; import java.util.logging.Logger; /** @@ -42,51 +40,57 @@ final class ProvisionListenerCallbackStore { // TODO(sameb): Consider exposing this in the API somehow? Maybe? // Lots of code often want to skip over the internal stuffs. - private static final Set<Key<?>> INTERNAL_BINDINGS = + private static final ImmutableSet<Key<?>> INTERNAL_BINDINGS = ImmutableSet.of(Key.get(Injector.class), Key.get(Stage.class), Key.get(Logger.class)); - + private final ImmutableList<ProvisionListenerBinding> listenerBindings; - private final LoadingCache<KeyBinding, ProvisionListenerStackCallback<?>> cache - = CacheBuilder.newBuilder().build( - new CacheLoader<KeyBinding, ProvisionListenerStackCallback<?>>() { - public ProvisionListenerStackCallback<?> load(KeyBinding key) { - return create(key.binding); - } - }); + private final LoadingCache<KeyBinding, ProvisionListenerStackCallback<?>> cache = + CacheBuilder.newBuilder() + .build( + new CacheLoader<KeyBinding, ProvisionListenerStackCallback<?>>() { + @Override + public ProvisionListenerStackCallback<?> load(KeyBinding key) { + return create(key.binding); + } + }); ProvisionListenerCallbackStore(List<ProvisionListenerBinding> listenerBindings) { this.listenerBindings = ImmutableList.copyOf(listenerBindings); } - /** Returns a new {@link ProvisionListenerStackCallback} for the key. + /** + * Returns a new {@link ProvisionListenerStackCallback} for the key or {@code null} if there are + * no listeners */ - @SuppressWarnings("unchecked") // the ProvisionListenerStackCallback type always agrees with the passed type + @SuppressWarnings( + "unchecked") // the ProvisionListenerStackCallback type always agrees with the passed type public <T> ProvisionListenerStackCallback<T> get(Binding<T> binding) { // Never notify any listeners for internal bindings. if (!INTERNAL_BINDINGS.contains(binding.getKey())) { - return (ProvisionListenerStackCallback<T>) cache.getUnchecked( - new KeyBinding(binding.getKey(), binding)); + ProvisionListenerStackCallback<T> callback = + (ProvisionListenerStackCallback<T>) + cache.getUnchecked(new KeyBinding(binding.getKey(), binding)); + return callback.hasListeners() ? callback : null; } - return ProvisionListenerStackCallback.emptyListener(); + return null; } /** - * Purges a key from the cache. Use this only if the type is not actually valid for - * binding and needs to be purged. (See issue 319 and + * Purges a key from the cache. Use this only if the type is not actually valid for binding and + * needs to be purged. (See issue 319 and * ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and * #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is * necessary.) - * - * Returns true if the type was stored in the cache, false otherwise. + * + * <p>Returns true if the type was stored in the cache, false otherwise. */ boolean remove(Binding<?> type) { return cache.asMap().remove(type) != null; } /** - * Creates a new {@link ProvisionListenerStackCallback} with the correct listeners - * for the key. + * Creates a new {@link ProvisionListenerStackCallback} with the correct listeners for the key. */ private <T> ProvisionListenerStackCallback<T> create(Binding<T> binding) { List<ProvisionListener> listeners = null; @@ -105,21 +109,22 @@ final class ProvisionListenerCallbackStore { } return new ProvisionListenerStackCallback<T>(binding, listeners); } - + /** A struct that holds key & binding but uses just key for equality/hashcode. */ private static class KeyBinding { final Key<?> key; final Binding<?> binding; - + KeyBinding(Key<?> key, Binding<?> binding) { this.key = key; this.binding = binding; } - + @Override public boolean equals(Object obj) { - return obj instanceof KeyBinding && key.equals(((KeyBinding)obj).key); + return obj instanceof KeyBinding && key.equals(((KeyBinding) obj).key); } + @Override public int hashCode() { return key.hashCode(); diff --git a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java index f72da256..01a3d2d2 100644 --- a/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java +++ b/core/src/com/google/inject/internal/ProvisionListenerStackCallback.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,10 +19,7 @@ package com.google.inject.internal; import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.google.inject.Binding; -import com.google.inject.ProvisionException; -import com.google.inject.spi.DependencyAndSource; import com.google.inject.spi.ProvisionListener; - import java.util.List; import java.util.Set; @@ -32,15 +29,16 @@ import java.util.Set; * @author sameb@google.com (Sam Berlin) */ final class ProvisionListenerStackCallback<T> { - - private static final ProvisionListener EMPTY_LISTENER[] = new ProvisionListener[0]; - @SuppressWarnings("rawtypes") + + private static final ProvisionListener[] EMPTY_LISTENER = new ProvisionListener[0]; + + @SuppressWarnings({"rawtypes", "unchecked"}) private static final ProvisionListenerStackCallback<?> EMPTY_CALLBACK = new ProvisionListenerStackCallback(null /* unused, so ok */, ImmutableList.of()); private final ProvisionListener[] listeners; private final Binding<T> binding; - + @SuppressWarnings("unchecked") public static <T> ProvisionListenerStackCallback<T> emptyListener() { return (ProvisionListenerStackCallback<T>) EMPTY_CALLBACK; @@ -55,30 +53,32 @@ final class ProvisionListenerStackCallback<T> { this.listeners = deDuplicated.toArray(new ProvisionListener[deDuplicated.size()]); } } - + public boolean hasListeners() { return listeners.length > 0; } - public T provision(Errors errors, InternalContext context, ProvisionCallback<T> callable) - throws ErrorsException { - Provision provision = new Provision(errors, context, callable); + public T provision(InternalContext context, ProvisionCallback<T> callable) + throws InternalProvisionException { + Provision provision = new Provision(context, callable); RuntimeException caught = null; try { provision.provision(); - } catch(RuntimeException t) { + } catch (RuntimeException t) { caught = t; } - + if (provision.exceptionDuringProvision != null) { throw provision.exceptionDuringProvision; } else if (caught != null) { - Object listener = provision.erredListener != null ? - provision.erredListener.getClass() : "(unknown)"; - throw errors - .errorInUserCode(caught, "Error notifying ProvisionListener %s of %s.%n" - + " Reason: %s", listener, binding.getKey(), caught) - .toException(); + Object listener = + provision.erredListener != null ? provision.erredListener.getClass() : "(unknown)"; + throw InternalProvisionException.errorInUserCode( + caught, + "Error notifying ProvisionListener %s of %s.%n Reason: %s", + listener, + binding.getKey(), + caught); } else { return provision.result; } @@ -86,25 +86,22 @@ final class ProvisionListenerStackCallback<T> { // TODO(sameb): Can this be more InternalFactory-like? public interface ProvisionCallback<T> { - public T call() throws ErrorsException; + public T call() throws InternalProvisionException; } private class Provision extends ProvisionListener.ProvisionInvocation<T> { - final Errors errors; - final int numErrorsBefore; final InternalContext context; + final ProvisionCallback<T> callable; int index = -1; T result; - ErrorsException exceptionDuringProvision; + InternalProvisionException exceptionDuringProvision; ProvisionListener erredListener; - public Provision(Errors errors, InternalContext context, ProvisionCallback<T> callable) { + public Provision(InternalContext context, ProvisionCallback<T> callable) { this.callable = callable; this.context = context; - this.errors = errors; - this.numErrorsBefore = errors.size(); } @Override @@ -113,18 +110,15 @@ final class ProvisionListenerStackCallback<T> { if (index == listeners.length) { try { result = callable.call(); - // Make sure we don't return the provisioned object if there were any errors - // injecting its field/method dependencies. - errors.throwIfNewErrors(numErrorsBefore); - } catch(ErrorsException ee) { - exceptionDuringProvision = ee; - throw new ProvisionException(errors.merge(ee.getErrors()).getMessages()); + } catch (InternalProvisionException ipe) { + exceptionDuringProvision = ipe; + throw ipe.toProvisionException(); } } else if (index < listeners.length) { int currentIdx = index; try { listeners[index].onProvision(this); - } catch(RuntimeException re) { + } catch (RuntimeException re) { erredListener = listeners[currentIdx]; throw re; } @@ -137,7 +131,7 @@ final class ProvisionListenerStackCallback<T> { } return result; } - + @Override public Binding<T> getBinding() { // TODO(sameb): Because so many places cast directly to BindingImpl & subclasses, @@ -145,10 +139,12 @@ final class ProvisionListenerStackCallback<T> { // if someone calls that they'll get strange errors. return binding; } - + + @Deprecated @Override - public List<DependencyAndSource> getDependencyChain() { + public List<com.google.inject.spi.DependencyAndSource> getDependencyChain() { return context.getDependencyChain(); } + } } diff --git a/core/src/com/google/inject/internal/ProxyFactory.java b/core/src/com/google/inject/internal/ProxyFactory.java index 13aff810..156a5c82 100644 --- a/core/src/com/google/inject/internal/ProxyFactory.java +++ b/core/src/com/google/inject/internal/ProxyFactory.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,7 @@ package com.google.inject.internal; -import static com.google.inject.internal.BytecodeGen.newFastClass; +import static com.google.inject.internal.BytecodeGen.newFastClassForMember; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -24,16 +24,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.inject.spi.InjectionPoint; - -import net.sf.cglib.core.MethodWrapper; -import net.sf.cglib.proxy.Callback; -import net.sf.cglib.proxy.CallbackFilter; -import net.sf.cglib.proxy.Enhancer; -import net.sf.cglib.reflect.FastClass; -import net.sf.cglib.reflect.FastConstructor; - -import org.aopalliance.intercept.MethodInterceptor; - import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -41,6 +31,12 @@ import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; +import net.sf.cglib.core.MethodWrapper; +import net.sf.cglib.proxy.Callback; +import net.sf.cglib.proxy.CallbackFilter; +import net.sf.cglib.proxy.Enhancer; +import net.sf.cglib.reflect.FastClass; +import org.aopalliance.intercept.MethodInterceptor; /** * Builds a construction proxy that can participate in AOP. This class manages applying type and @@ -49,7 +45,7 @@ import java.util.logging.Logger; * @author jessewilson@google.com (Jesse Wilson) */ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { - + private static final Logger logger = Logger.getLogger(ProxyFactory.class.getName()); private final InjectionPoint injectionPoint; @@ -68,7 +64,7 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { this.injectionPoint = injectionPoint; @SuppressWarnings("unchecked") // the member of injectionPoint is always a Constructor<T> - Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember(); + Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember(); declaringClass = constructor.getDeclaringClass(); // Find applicable aspects. Bow out if none are applicable to this class. @@ -101,12 +97,13 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { for (MethodAspect methodAspect : applicableAspects) { for (MethodInterceptorsPair pair : methodInterceptorsPairs) { if (methodAspect.matches(pair.method)) { - if(pair.method.isSynthetic()) { - logger.log(Level.WARNING, + if (pair.method.isSynthetic()) { + logger.log( + Level.WARNING, "Method [{0}] is synthetic and is being intercepted by {1}." - + " This could indicate a bug. The method may be intercepted twice," - + " or may not be intercepted at all.", - new Object[] { pair.method, methodAspect.interceptors() }); + + " This could indicate a bug. The method may be intercepted twice," + + " or may not be intercepted at all.", + new Object[] {pair.method, methodAspect.interceptors()}); } visibility = visibility.and(BytecodeGen.Visibility.forMember(pair.method)); pair.addAll(methodAspect.interceptors()); @@ -142,18 +139,18 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { callbacks[i] = new InterceptorStackCallback(pair.method, deDuplicated); } - interceptors = interceptorsMapBuilder != null - ? interceptorsMapBuilder.build() - : ImmutableMap.<Method, List<MethodInterceptor>>of(); + interceptors = + interceptorsMapBuilder != null + ? interceptorsMapBuilder.build() + : ImmutableMap.<Method, List<MethodInterceptor>>of(); } - /** - * Returns the interceptors that apply to the constructed type. - */ + /** Returns the interceptors that apply to the constructed type. */ public ImmutableMap<Method, List<MethodInterceptor>> getInterceptors() { return interceptors; } + @Override public ConstructionProxy<T> create() throws ErrorsException { if (interceptors.isEmpty()) { return new DefaultConstructionProxyFactory<T>(injectionPoint).create(); @@ -172,10 +169,10 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { // Create the proxied class. We're careful to ensure that all enhancer state is not-specific // to this injector. Otherwise, the proxies for each injector will waste PermGen memory try { - Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility); - enhancer.setCallbackFilter(new IndicesCallbackFilter(methods)); - enhancer.setCallbackTypes(callbackTypes); - return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors); + Enhancer enhancer = BytecodeGen.newEnhancer(declaringClass, visibility); + enhancer.setCallbackFilter(new IndicesCallbackFilter(methods)); + enhancer.setCallbackTypes(callbackTypes); + return new ProxyConstructor<T>(enhancer, injectionPoint, callbacks, interceptors); } catch (Throwable e) { throw new Errors().errorEnhancingClass(declaringClass, e).toException(); } @@ -202,10 +199,9 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { } /** - * A callback filter that maps methods to unique IDs. We define equals and - * hashCode without using any state related to the injector so that enhanced - * classes intercepting the same methods can be shared between injectors (and - * child injectors, etc). + * A callback filter that maps methods to unique IDs. We define equals and hashCode without using + * any state related to the injector so that enhanced classes intercepting the same methods can be + * shared between injectors (and child injectors, etc). */ private static class IndicesCallbackFilter implements CallbackFilter { final Map<Object, Integer> indices; @@ -220,63 +216,71 @@ final class ProxyFactory<T> implements ConstructionProxyFactory<T> { this.hashCode = indices.hashCode(); } + @Override public int accept(Method method) { return indices.get(MethodWrapper.create(method)); } - @Override public boolean equals(Object o) { - return o instanceof IndicesCallbackFilter && - ((IndicesCallbackFilter) o).indices.equals(indices); + @Override + public boolean equals(Object o) { + return o instanceof IndicesCallbackFilter + && ((IndicesCallbackFilter) o).indices.equals(indices); } - @Override public int hashCode() { + @Override + public int hashCode() { return hashCode; } } - /** - * Constructs instances that participate in AOP. - */ + /** Constructs instances that participate in AOP. */ private static class ProxyConstructor<T> implements ConstructionProxy<T> { final Class<?> enhanced; final InjectionPoint injectionPoint; final Constructor<T> constructor; final Callback[] callbacks; - final FastConstructor fastConstructor; + final int constructorIndex; final ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors; + final FastClass fastClass; @SuppressWarnings("unchecked") // the constructor promises to construct 'T's - ProxyConstructor(Enhancer enhancer, InjectionPoint injectionPoint, Callback[] callbacks, + ProxyConstructor( + Enhancer enhancer, + InjectionPoint injectionPoint, + Callback[] callbacks, ImmutableMap<Method, List<MethodInterceptor>> methodInterceptors) { this.enhanced = enhancer.createClass(); // this returns a cached class if possible this.injectionPoint = injectionPoint; this.constructor = (Constructor<T>) injectionPoint.getMember(); this.callbacks = callbacks; this.methodInterceptors = methodInterceptors; - - FastClass fastClass = newFastClass(enhanced, BytecodeGen.Visibility.forMember(constructor)); - this.fastConstructor = fastClass.getConstructor(constructor.getParameterTypes()); + this.fastClass = newFastClassForMember(enhanced, constructor); + this.constructorIndex = fastClass.getIndex(constructor.getParameterTypes()); } + @Override @SuppressWarnings("unchecked") // the constructor promises to produce 'T's public T newInstance(Object... arguments) throws InvocationTargetException { Enhancer.registerCallbacks(enhanced, callbacks); try { - return (T) fastConstructor.newInstance(arguments); + return (T) fastClass.newInstance(constructorIndex, arguments); } finally { Enhancer.registerCallbacks(enhanced, null); } } + @Override public InjectionPoint getInjectionPoint() { return injectionPoint; } + @Override public Constructor<T> getConstructor() { return constructor; } + @Override public ImmutableMap<Method, List<MethodInterceptor>> getMethodInterceptors() { return methodInterceptors; } diff --git a/core/src/com/google/inject/internal/RealElement.java b/core/src/com/google/inject/internal/RealElement.java new file mode 100644 index 00000000..8f984a6c --- /dev/null +++ b/core/src/com/google/inject/internal/RealElement.java @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.internal; + +import com.google.inject.internal.Element.Type; +import java.lang.annotation.Annotation; +import java.util.concurrent.atomic.AtomicInteger; + +/** An implementation of Element. */ +// TODO(cgruber): Use AutoAnnotation when available, here & wherever else is makes sense. +class RealElement implements Element { + private static final AtomicInteger nextUniqueId = new AtomicInteger(1); + + private final int uniqueId; + private final String setName; + private final Element.Type type; + private final String keyType; + + RealElement(String setName, Element.Type type, String keyType) { + this(setName, type, keyType, nextUniqueId.incrementAndGet()); + } + + RealElement(String setName, Element.Type type, String keyType, int uniqueId) { + this.uniqueId = uniqueId; + this.setName = setName; + this.type = type; + this.keyType = keyType; + } + + @Override + public String setName() { + return setName; + } + + @Override + public int uniqueId() { + return uniqueId; + } + + @Override + public Element.Type type() { + return type; + } + + @Override + public String keyType() { + return keyType; + } + + @Override + public Class<? extends Annotation> annotationType() { + return Element.class; + } + + @Override + public String toString() { + return "@" + + Element.class.getName() + + "(setName=" + + setName + + ",uniqueId=" + + uniqueId + + ", type=" + + type + + ", keyType=" + + keyType + + ")"; + } + + @Override + public boolean equals(Object o) { + return o instanceof Element + && ((Element) o).setName().equals(setName()) + && ((Element) o).uniqueId() == uniqueId() + && ((Element) o).type() == type() + && ((Element) o).keyType().equals(keyType()); + } + + @Override + public int hashCode() { + return ((127 * "setName".hashCode()) ^ setName.hashCode()) + + ((127 * "uniqueId".hashCode()) ^ uniqueId) + + ((127 * "type".hashCode()) ^ type.hashCode()) + + ((127 * "keyType".hashCode()) ^ keyType.hashCode()); + } +} diff --git a/core/src/com/google/inject/internal/RealMapBinder.java b/core/src/com/google/inject/internal/RealMapBinder.java new file mode 100644 index 00000000..1e28fb24 --- /dev/null +++ b/core/src/com/google/inject/internal/RealMapBinder.java @@ -0,0 +1,1344 @@ + +package com.google.inject.internal; + +import static com.google.inject.internal.Element.Type.MAPBINDER; +import static com.google.inject.internal.Errors.checkConfiguration; +import static com.google.inject.internal.Errors.checkNotNull; +import static com.google.inject.internal.RealMultibinder.setOf; +import static com.google.inject.util.Types.newParameterizedType; +import static com.google.inject.util.Types.newParameterizedTypeWithOwner; + +import com.google.common.base.Objects; +import com.google.common.base.Preconditions; +import com.google.common.collect.HashMultimap; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.LinkedHashMultimap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Multimap; +import com.google.common.collect.Sets; +import com.google.inject.Binder; +import com.google.inject.Binding; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming; +import com.google.inject.multibindings.MapBinderBinding; +import com.google.inject.multibindings.Multibinder; +import com.google.inject.multibindings.MultibindingsTargetVisitor; +import com.google.inject.spi.BindingTargetVisitor; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.Element; +import com.google.inject.spi.ProviderInstanceBinding; +import com.google.inject.spi.ProviderWithExtensionVisitor; +import com.google.inject.util.Types; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * The actual mapbinder plays several roles: + * + * <p>As a MapBinder, it acts as a factory for LinkedBindingBuilders for each of the map's values. + * It delegates to a {@link Multibinder} of entries (keys to value providers). + * + * <p>As a Module, it installs the binding to the map itself, as well as to a corresponding map + * whose values are providers. + * + * <p>As a module, this implements equals() and hashcode() in order to trick Guice into executing + * its configure() method only once. That makes it so that multiple mapbinders can be created for + * the same target map, but only one is bound. Since the list of bindings is retrieved from the + * injector itself (and not the mapbinder), each mapbinder has access to all contributions from all + * equivalent mapbinders. + * + * <p>Rather than binding a single Map.Entry<K, V>, the map binder binds keys and values + * independently. This allows the values to be properly scoped. + */ +public final class RealMapBinder<K, V> implements Module { + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with no binding annotation. + */ + public static <K, V> RealMapBinder<K, V> newMapRealBinder( + Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + binder = binder.skipSources(RealMapBinder.class); + return newRealMapBinder( + binder, + keyType, + valueType, + Key.get(mapOf(keyType, valueType)), + RealMultibinder.newRealSetBinder(binder, Key.get(entryOfProviderOf(keyType, valueType)))); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotation}. + */ + public static <K, V> RealMapBinder<K, V> newRealMapBinder( + Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) { + binder = binder.skipSources(RealMapBinder.class); + return newRealMapBinder( + binder, + keyType, + valueType, + Key.get(mapOf(keyType, valueType), annotation), + RealMultibinder.newRealSetBinder( + binder, Key.get(entryOfProviderOf(keyType, valueType), annotation))); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotationType}. + */ + public static <K, V> RealMapBinder<K, V> newRealMapBinder( + Binder binder, + TypeLiteral<K> keyType, + TypeLiteral<V> valueType, + Class<? extends Annotation> annotationType) { + binder = binder.skipSources(RealMapBinder.class); + return newRealMapBinder( + binder, + keyType, + valueType, + Key.get(mapOf(keyType, valueType), annotationType), + RealMultibinder.newRealSetBinder( + binder, Key.get(entryOfProviderOf(keyType, valueType), annotationType))); + } + + @SuppressWarnings("unchecked") // a map of <K, V> is safely a Map<K, V> + static <K, V> TypeLiteral<Map<K, V>> mapOf(TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, V>>) + TypeLiteral.get(Types.mapOf(keyType.getType(), valueType.getType())); + } + + @SuppressWarnings("unchecked") // a provider map <K, V> is safely a Map<K, Provider<V>> + static <K, V> TypeLiteral<Map<K, Provider<V>>> mapOfProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, Provider<V>>>) + TypeLiteral.get(Types.mapOf(keyType.getType(), Types.providerOf(valueType.getType()))); + } + + // provider map <K, V> is safely a Map<K, javax.inject.Provider<V>>> + @SuppressWarnings("unchecked") + static <K, V> TypeLiteral<Map<K, javax.inject.Provider<V>>> mapOfJavaxProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, javax.inject.Provider<V>>>) + TypeLiteral.get( + Types.mapOf( + keyType.getType(), + newParameterizedType(javax.inject.Provider.class, valueType.getType()))); + } + + @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>> + static <K, V> TypeLiteral<Map<K, Set<Provider<V>>>> mapOfSetOfProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, Set<Provider<V>>>>) + TypeLiteral.get( + Types.mapOf(keyType.getType(), Types.setOf(Types.providerOf(valueType.getType())))); + } + + @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>> + static <K, V> TypeLiteral<Map<K, Set<javax.inject.Provider<V>>>> mapOfSetOfJavaxProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, Set<javax.inject.Provider<V>>>>) + TypeLiteral.get( + Types.mapOf( + keyType.getType(), Types.setOf(Types.javaxProviderOf(valueType.getType())))); + } + + @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>> + static <K, V> TypeLiteral<Map<K, Collection<Provider<V>>>> mapOfCollectionOfProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, Collection<Provider<V>>>>) + TypeLiteral.get( + Types.mapOf( + keyType.getType(), Types.collectionOf(Types.providerOf(valueType.getType())))); + } + + @SuppressWarnings("unchecked") // a provider map <K, Set<V>> is safely a Map<K, Set<Provider<V>>> + static <K, V> + TypeLiteral<Map<K, Collection<javax.inject.Provider<V>>>> mapOfCollectionOfJavaxProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map<K, Collection<javax.inject.Provider<V>>>>) + TypeLiteral.get( + Types.mapOf( + keyType.getType(), Types.collectionOf(Types.javaxProviderOf(valueType.getType())))); + } + + @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>> + static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map.Entry<K, Provider<V>>>) + TypeLiteral.get( + newParameterizedTypeWithOwner( + Map.class, + Map.Entry.class, + keyType.getType(), + Types.providerOf(valueType.getType()))); + } + + @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>> + static <K, V> TypeLiteral<Map.Entry<K, Provider<V>>> entryOfJavaxProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Map.Entry<K, Provider<V>>>) + TypeLiteral.get( + newParameterizedTypeWithOwner( + Map.class, + Map.Entry.class, + keyType.getType(), + Types.javaxProviderOf(valueType.getType()))); + } + + @SuppressWarnings("unchecked") // a provider entry <K, V> is safely a Map.Entry<K, Provider<V>> + static <K, V> + TypeLiteral<Set<Map.Entry<K, javax.inject.Provider<V>>>> setOfEntryOfJavaxProviderOf( + TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return (TypeLiteral<Set<Map.Entry<K, javax.inject.Provider<V>>>>) + TypeLiteral.get(Types.setOf(entryOfJavaxProviderOf(keyType, valueType).getType())); + } + + /** Given a Key<T> will return a Key<Provider<T>> */ + @SuppressWarnings("unchecked") + private static <T> Key<Provider<T>> getKeyOfProvider(Key<T> valueKey) { + return (Key<Provider<T>>) + valueKey.ofType(Types.providerOf(valueKey.getTypeLiteral().getType())); + } + + // Note: We use valueTypeAndAnnotation effectively as a Pair<TypeLiteral, Annotation|Class> + // since it's an easy way to group a type and an optional annotation type or instance. + static <K, V> RealMapBinder<K, V> newRealMapBinder( + Binder binder, TypeLiteral<K> keyType, Key<V> valueTypeAndAnnotation) { + binder = binder.skipSources(RealMapBinder.class); + TypeLiteral<V> valueType = valueTypeAndAnnotation.getTypeLiteral(); + return newRealMapBinder( + binder, + keyType, + valueType, + valueTypeAndAnnotation.ofType(mapOf(keyType, valueType)), + RealMultibinder.newRealSetBinder( + binder, valueTypeAndAnnotation.ofType(entryOfProviderOf(keyType, valueType)))); + } + + private static <K, V> RealMapBinder<K, V> newRealMapBinder( + Binder binder, + TypeLiteral<K> keyType, + TypeLiteral<V> valueType, + Key<Map<K, V>> mapKey, + RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) { + RealMapBinder<K, V> mapBinder = + new RealMapBinder<K, V>(binder, keyType, valueType, mapKey, entrySetBinder); + binder.install(mapBinder); + return mapBinder; + } + + // Until the injector initializes us, we don't know what our dependencies are, + // so initialize to the whole Injector. + private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES = + ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class))); + + private final BindingSelection<K, V> bindingSelection; + private final Binder binder; + + private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder; + + private RealMapBinder( + Binder binder, + TypeLiteral<K> keyType, + TypeLiteral<V> valueType, + Key<Map<K, V>> mapKey, + RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) { + this.bindingSelection = new BindingSelection<>(keyType, valueType, mapKey, entrySetBinder); + this.binder = binder; + this.entrySetBinder = entrySetBinder; + } + + public void permitDuplicates() { + checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized"); + entrySetBinder.permitDuplicates(); + binder.install(new MultimapBinder<K, V>(bindingSelection)); + } + + /** Adds a binding to the map for the given key. */ + Key<V> getKeyForNewValue(K key) { + checkNotNull(key, "key"); + checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized"); + RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder = + bindingSelection.getEntrySetBinder(); + + Key<V> valueKey = + Key.get( + bindingSelection.getValueType(), + new RealElement( + entrySetBinder.getSetName(), MAPBINDER, bindingSelection.getKeyType().toString())); + entrySetBinder.addBinding().toProvider(new ProviderMapEntry<K, V>(key, valueKey)); + return valueKey; + } + + /** + * This creates two bindings. One for the {@code Map.Entry<K, Provider<V>>} and another for {@code + * V}. + */ + public LinkedBindingBuilder<V> addBinding(K key) { + return binder.bind(getKeyForNewValue(key)); + } + + @Override + public void configure(Binder binder) { + checkConfiguration(!bindingSelection.isInitialized(), "MapBinder was already initialized"); + + // Binds a Map<K, Provider<V>> + RealProviderMapProvider<K, V> providerMapProvider = + new RealProviderMapProvider<K, V>(bindingSelection); + binder.bind(bindingSelection.getProviderMapKey()).toProvider(providerMapProvider); + + // The map this exposes is internally an ImmutableMap, so it's OK to massage + // the guice Provider to javax Provider in the value (since Guice provider + // implements javax Provider). + @SuppressWarnings({"unchecked", "rawtypes"}) + Provider<Map<K, javax.inject.Provider<V>>> javaxProviderMapProvider = + (Provider) providerMapProvider; + binder.bind(bindingSelection.getJavaxProviderMapKey()).toProvider(javaxProviderMapProvider); + + RealMapProvider<K, V> mapProvider = new RealMapProvider<>(bindingSelection); + binder.bind(bindingSelection.getMapKey()).toProvider(mapProvider); + + // The Map.Entries are all ProviderMapEntry instances which do not allow setValue, so it is + // safe to massage the return type like this + @SuppressWarnings({"unchecked", "rawtypes"}) + Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> massagedEntrySetProviderKey = + (Key) bindingSelection.getEntrySetBinder().getSetKey(); + binder.bind(bindingSelection.getEntrySetJavaxProviderKey()).to(massagedEntrySetProviderKey); + } + + @Override + public boolean equals(Object o) { + return o instanceof RealMapBinder + && ((RealMapBinder<?, ?>) o).bindingSelection.equals(bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + + /** + * The BindingSelection contains some of the core state and logic for the MapBinder. + * + * <p>It lazily computes the value for keys for various permutations of Maps that are provided by + * this module. It also builds up maps from {@code K} to {@code Binding<V>}, which is used by all + * of the internal factories to actually provide the desired maps. + * + * <p>During initialization time there is only one BindingSelection. It is possible that multiple + * different BindingSelections are constructed. Specifically, in the case of two different modules + * each adding bindings to the same MapBinder. If that happens, we define the BindingSelection + * held by the {@link RealMapProvider} to be the authoritative one. The logic for this exists in + * {@link RealMultimapBinderProviderWithDependencies}. This is done to avoid confusion because the + * BindingSelection contains mutable state. + */ + private static final class BindingSelection<K, V> { + private enum InitializationState { + UNINITIALIZED, + INITIALIZED, + HAS_ERRORS; + } + + private final TypeLiteral<K> keyType; + private final TypeLiteral<V> valueType; + private final Key<Map<K, V>> mapKey; + + // Lazily computed + private Key<Map<K, javax.inject.Provider<V>>> javaxProviderMapKey; + private Key<Map<K, Provider<V>>> providerMapKey; + private Key<Map<K, Set<V>>> multimapKey; + private Key<Map<K, Set<Provider<V>>>> providerSetMultimapKey; + private Key<Map<K, Set<javax.inject.Provider<V>>>> javaxProviderSetMultimapKey; + private Key<Map<K, Collection<Provider<V>>>> providerCollectionMultimapKey; + private Key<Map<K, Collection<javax.inject.Provider<V>>>> javaxProviderCollectionMultimapKey; + private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> entrySetJavaxProviderKey; + + private final RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder; + + private InitializationState initializationState; + + /** + * These are built during initialization and used by all factories to actually provide the + * relevant maps. These contain all of the necessary information about the map binder. + */ + private ImmutableMap<K, Binding<V>> mapBindings; + + private ImmutableMap<K, Set<Binding<V>>> multimapBindings; + private ImmutableList<Map.Entry<K, Binding<V>>> entries; + + /** + * Indicates if this Map permits duplicates. It is initialized during initialization by querying + * the injector. This is done because multiple different modules can contribute to a MapBinder, + * and any one could set permitDuplicates. + */ + private boolean permitsDuplicates; + + private BindingSelection( + TypeLiteral<K> keyType, + TypeLiteral<V> valueType, + Key<Map<K, V>> mapKey, + RealMultibinder<Map.Entry<K, Provider<V>>> entrySetBinder) { + this.keyType = keyType; + this.valueType = valueType; + this.mapKey = mapKey; + this.entrySetBinder = entrySetBinder; + this.initializationState = InitializationState.UNINITIALIZED; + } + + /** + * Will initialize internal data structures. + * + * @return {@code true} if initialization was successful, {@code false} if there were errors + */ + private boolean tryInitialize(InjectorImpl injector, Errors errors) { + // Every one of our providers will call this method, so only execute the logic once. + if (initializationState != InitializationState.UNINITIALIZED) { + return initializationState != InitializationState.HAS_ERRORS; + } + + // Multiple different modules can all contribute to the same MapBinder, and if any + // one of them permits duplicates, then the map binder as a whole will permit duplicates. + // Since permitDuplicates() may not have been called on this instance, we need to go + // to the injector to see if permitDuplicates was set. + permitsDuplicates = entrySetBinder.permitsDuplicates(injector); + + // We now build the Map<K, Set<Binding<V>>> from the entrySetBinder. + // The entrySetBinder contains all of the ProviderMapEntrys, and once + // we have those, it's easy to iterate through them to organize them by K. + Map<K, ImmutableSet.Builder<Binding<V>>> bindingMultimapMutable = + new LinkedHashMap<K, ImmutableSet.Builder<Binding<V>>>(); + Map<K, Binding<V>> bindingMapMutable = new LinkedHashMap<>(); + Multimap<K, Indexer.IndexedBinding> index = HashMultimap.create(); + Indexer indexer = new Indexer(injector); + Multimap<K, Binding<V>> duplicates = null; + + ImmutableList.Builder<Map.Entry<K, Binding<V>>> entriesBuilder = ImmutableList.builder(); + + // We get all of the Bindings that were put into the entrySetBinder + for (Binding<Map.Entry<K, Provider<V>>> binding : + injector.findBindingsByType(entrySetBinder.getElementTypeLiteral())) { + if (entrySetBinder.containsElement(binding)) { + + // Protected by findBindingByType() and the fact that all providers are added by us + // in addBinding(). It would theoretically be possible for someone to directly + // add their own binding to the entrySetBinder, but they shouldn't do that. + @SuppressWarnings({"unchecked", "rawtypes"}) + ProviderInstanceBinding<ProviderMapEntry<K, V>> entryBinding = + (ProviderInstanceBinding) binding; + + // We added all these bindings initially, so we know they are ProviderMapEntrys + @SuppressWarnings({"unchecked", "rawtypes"}) + ProviderMapEntry<K, V> entry = (ProviderMapEntry) entryBinding.getUserSuppliedProvider(); + K key = entry.getKey(); + + Key<V> valueKey = entry.getValueKey(); + Binding<V> valueBinding = injector.getExistingBinding(valueKey); + + // Use the indexer to de-dupe user bindings. This is needed because of the + // uniqueId in RealElement. The uniqueId intentionally circumvents the regular + // Guice deduplication, so we need to re-implement our own here, ignoring + // uniqueId. + if (index.put(key, valueBinding.acceptTargetVisitor(indexer))) { + + entriesBuilder.add(Maps.immutableEntry(key, valueBinding)); + + Binding<V> previous = bindingMapMutable.put(key, valueBinding); + // Check if this is a duplicate binding + if (previous != null && !permitsDuplicates) { + if (duplicates == null) { + // This is linked for both keys and values to maintain order + duplicates = LinkedHashMultimap.create(); + } + + // We add both the previous and the current value to the duplicates map. + // This is because if there are three duplicates, we will only execute this code + // for the second and third, but we want all three values to display a helpful + // error message. We rely on the multimap to dedupe repeated values. + duplicates.put(key, previous); + duplicates.put(key, valueBinding); + } + + // Don't do extra work unless we need to + if (permitsDuplicates) { + // Create a set builder for this key if it's the first time we've seen it + if (!bindingMultimapMutable.containsKey(key)) { + bindingMultimapMutable.put(key, ImmutableSet.<Binding<V>>builder()); + } + + // Add the Binding<V> + bindingMultimapMutable.get(key).add(valueBinding); + } + } + } + } + + // It is safe to check if duplicates is non-null because if duplicates are allowed, + // we don't build up this data structure + if (duplicates != null) { + initializationState = InitializationState.HAS_ERRORS; + reportDuplicateKeysError(duplicates, errors); + + return false; + } + + // Build all of the ImmutableSet.Builders, + // transforming from Map<K, ImmutableSet.Builder<Binding<V>>> to + // ImmutableMap<K, Set<Binding<V>>> + ImmutableMap.Builder<K, Set<Binding<V>>> bindingsMultimapBuilder = ImmutableMap.builder(); + for (Map.Entry<K, ImmutableSet.Builder<Binding<V>>> entry : + bindingMultimapMutable.entrySet()) { + bindingsMultimapBuilder.put(entry.getKey(), entry.getValue().build()); + } + mapBindings = ImmutableMap.copyOf(bindingMapMutable); + multimapBindings = bindingsMultimapBuilder.build(); + + entries = entriesBuilder.build(); + + initializationState = InitializationState.INITIALIZED; + + return true; + } + + private static <K, V> void reportDuplicateKeysError( + Multimap<K, Binding<V>> duplicates, Errors errors) { + StringBuilder sb = new StringBuilder("Map injection failed due to duplicated key "); + boolean first = true; + for (Map.Entry<K, Collection<Binding<V>>> entry : duplicates.asMap().entrySet()) { + K dupKey = entry.getKey(); + + if (first) { + first = false; + sb.append("\"" + dupKey + "\", from bindings:\n"); + } else { + sb.append("\n and key: \"" + dupKey + "\", from bindings:\n"); + } + + for (Binding<V> dup : entry.getValue()) { + sb.append("\t at " + Errors.convert(dup.getSource()) + "\n"); + } + } + + // TODO(user): Add a different error for every duplicated key + errors.addMessage(sb.toString()); + } + + private boolean containsElement(Element element) { + if (entrySetBinder.containsElement(element)) { + return true; + } + + Key<?> key; + if (element instanceof Binding) { + key = ((Binding<?>) element).getKey(); + } else { + return false; // cannot match; + } + + return key.equals(getMapKey()) + || key.equals(getProviderMapKey()) + || key.equals(getJavaxProviderMapKey()) + || key.equals(getMultimapKey()) + || key.equals(getProviderSetMultimapKey()) + || key.equals(getJavaxProviderSetMultimapKey()) + || key.equals(getProviderCollectionMultimapKey()) + || key.equals(getJavaxProviderCollectionMultimapKey()) + || key.equals(entrySetBinder.getSetKey()) + || key.equals(getEntrySetJavaxProviderKey()) + || matchesValueKey(key); + } + + /** Returns true if the key indicates this is a value in the map. */ + private boolean matchesValueKey(Key<?> key) { + return key.getAnnotation() instanceof RealElement + && ((RealElement) key.getAnnotation()).setName().equals(entrySetBinder.getSetName()) + && ((RealElement) key.getAnnotation()).type() == MAPBINDER + && ((RealElement) key.getAnnotation()).keyType().equals(keyType.toString()) + && key.getTypeLiteral().equals(valueType); + } + + private Key<Map<K, Provider<V>>> getProviderMapKey() { + Key<Map<K, Provider<V>>> local = providerMapKey; + if (local == null) { + local = providerMapKey = mapKey.ofType(mapOfProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Map<K, javax.inject.Provider<V>>> getJavaxProviderMapKey() { + Key<Map<K, javax.inject.Provider<V>>> local = javaxProviderMapKey; + if (local == null) { + local = javaxProviderMapKey = mapKey.ofType(mapOfJavaxProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Map<K, Set<V>>> getMultimapKey() { + Key<Map<K, Set<V>>> local = multimapKey; + if (local == null) { + local = multimapKey = mapKey.ofType(mapOf(keyType, setOf(valueType))); + } + return local; + } + + private Key<Map<K, Set<Provider<V>>>> getProviderSetMultimapKey() { + Key<Map<K, Set<Provider<V>>>> local = providerSetMultimapKey; + if (local == null) { + local = providerSetMultimapKey = mapKey.ofType(mapOfSetOfProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Map<K, Set<javax.inject.Provider<V>>>> getJavaxProviderSetMultimapKey() { + Key<Map<K, Set<javax.inject.Provider<V>>>> local = javaxProviderSetMultimapKey; + if (local == null) { + local = + javaxProviderSetMultimapKey = + mapKey.ofType(mapOfSetOfJavaxProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Map<K, Collection<Provider<V>>>> getProviderCollectionMultimapKey() { + Key<Map<K, Collection<Provider<V>>>> local = providerCollectionMultimapKey; + if (local == null) { + local = + providerCollectionMultimapKey = + mapKey.ofType(mapOfCollectionOfProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Map<K, Collection<javax.inject.Provider<V>>>> + getJavaxProviderCollectionMultimapKey() { + Key<Map<K, Collection<javax.inject.Provider<V>>>> local = javaxProviderCollectionMultimapKey; + if (local == null) { + local = + javaxProviderCollectionMultimapKey = + mapKey.ofType(mapOfCollectionOfJavaxProviderOf(keyType, valueType)); + } + return local; + } + + private Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> getEntrySetJavaxProviderKey() { + Key<Set<Map.Entry<K, javax.inject.Provider<V>>>> local = entrySetJavaxProviderKey; + if (local == null) { + local = + entrySetJavaxProviderKey = + mapKey.ofType(setOfEntryOfJavaxProviderOf(keyType, valueType)); + } + return local; + } + + private ImmutableMap<K, Binding<V>> getMapBindings() { + checkConfiguration(isInitialized(), "MapBinder has not yet been initialized"); + return mapBindings; + } + + private ImmutableMap<K, Set<Binding<V>>> getMultimapBindings() { + checkConfiguration(isInitialized(), "MapBinder has not yet been initialized"); + return multimapBindings; + } + + private ImmutableList<Map.Entry<K, Binding<V>>> getEntries() { + checkConfiguration(isInitialized(), "MapBinder has not yet been initialized"); + return entries; + } + + private boolean isInitialized() { + return initializationState == InitializationState.INITIALIZED; + } + + private TypeLiteral<K> getKeyType() { + return keyType; + } + + private TypeLiteral<V> getValueType() { + return valueType; + } + + private Key<Map<K, V>> getMapKey() { + return mapKey; + } + + private RealMultibinder<Map.Entry<K, Provider<V>>> getEntrySetBinder() { + return entrySetBinder; + } + + private boolean permitsDuplicates() { + if (isInitialized()) { + return permitsDuplicates; + } else { + throw new UnsupportedOperationException( + "permitsDuplicates() not supported for module bindings"); + } + } + + @Override + public boolean equals(Object o) { + return o instanceof BindingSelection && ((BindingSelection<?, ?>) o).mapKey.equals(mapKey); + } + + @Override + public int hashCode() { + return mapKey.hashCode(); + } + } + + private static final class RealProviderMapProvider<K, V> + extends RealMapBinderProviderWithDependencies<K, V, Map<K, Provider<V>>> { + private Map<K, Provider<V>> mapOfProviders; + private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES; + + private RealProviderMapProvider(BindingSelection<K, V> bindingSelection) { + super(bindingSelection); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return dependencies; + } + + @Override + protected void doInitialize(InjectorImpl injector, Errors errors) { + ImmutableMap.Builder<K, Provider<V>> mapOfProvidersBuilder = ImmutableMap.builder(); + ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); + for (Map.Entry<K, Binding<V>> entry : bindingSelection.getMapBindings().entrySet()) { + mapOfProvidersBuilder.put(entry.getKey(), entry.getValue().getProvider()); + dependenciesBuilder.add(Dependency.get(getKeyOfProvider(entry.getValue().getKey()))); + } + + mapOfProviders = mapOfProvidersBuilder.build(); + dependencies = dependenciesBuilder.build(); + } + + @Override + protected Map<K, Provider<V>> doProvision(InternalContext context, Dependency<?> dependency) { + return mapOfProviders; + } + } + + private static final class RealMapProvider<K, V> + extends RealMapBinderProviderWithDependencies<K, V, Map<K, V>> + implements ProviderWithExtensionVisitor<Map<K, V>>, MapBinderBinding<Map<K, V>> { + private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES; + + /** + * An array of all the injectors. + * + * <p>This is parallel to array of keys below + */ + private SingleParameterInjector<V>[] injectors; + + private K[] keys; + + private RealMapProvider(BindingSelection<K, V> bindingSelection) { + super(bindingSelection); + } + + private BindingSelection<K, V> getBindingSelection() { + return bindingSelection; + } + + @Override + protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException { + @SuppressWarnings("unchecked") + K[] keysArray = (K[]) new Object[bindingSelection.getMapBindings().size()]; + keys = keysArray; + ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); + int i = 0; + for (Map.Entry<K, Binding<V>> entry : bindingSelection.getMapBindings().entrySet()) { + dependenciesBuilder.add(Dependency.get(entry.getValue().getKey())); + keys[i] = entry.getKey(); + i++; + } + + ImmutableSet<Dependency<?>> localDependencies = dependenciesBuilder.build(); + dependencies = localDependencies; + + List<Dependency<?>> dependenciesList = localDependencies.asList(); + + // We know the type because we built up our own sets of dependencies, it's just + // that the interface uses a "?" generic + @SuppressWarnings("unchecked") + SingleParameterInjector<V>[] typedInjectors = + (SingleParameterInjector<V>[]) injector.getParametersInjectors(dependenciesList, errors); + injectors = typedInjectors; + } + + @Override + protected Map<K, V> doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException { + SingleParameterInjector<V>[] localInjectors = injectors; + if (localInjectors == null) { + // if injectors == null, then we have no bindings so return the empty map. + return ImmutableMap.of(); + } + + ImmutableMap.Builder<K, V> resultBuilder = ImmutableMap.builder(); + K[] localKeys = keys; + for (int i = 0; i < localInjectors.length; i++) { + SingleParameterInjector<V> injector = localInjectors[i]; + K key = localKeys[i]; + + V value = injector.inject(context); + + if (value == null) { + throw createNullValueException(key, bindingSelection.getMapBindings().get(key)); + } + + resultBuilder.put(key, value); + } + + return resultBuilder.build(); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return dependencies; + } + + @Override + @SuppressWarnings("unchecked") + public <B, W> W acceptExtensionVisitor( + BindingTargetVisitor<B, W> visitor, ProviderInstanceBinding<? extends B> binding) { + if (visitor instanceof MultibindingsTargetVisitor) { + return ((MultibindingsTargetVisitor<Map<K, V>, W>) visitor).visit(this); + } else { + return visitor.visit(binding); + } + } + + @Override + public Key<Map<K, V>> getMapKey() { + return bindingSelection.getMapKey(); + } + + @Override + public TypeLiteral<K> getKeyTypeLiteral() { + return bindingSelection.getKeyType(); + } + + @Override + public TypeLiteral<V> getValueTypeLiteral() { + return bindingSelection.getValueType(); + } + + @Override + @SuppressWarnings("unchecked") + public List<Map.Entry<?, Binding<?>>> getEntries() { + if (bindingSelection.isInitialized()) { + return (List<Map.Entry<?, Binding<?>>>) (List<?>) bindingSelection.getEntries(); + } else { + throw new UnsupportedOperationException("getEntries() not supported for module bindings"); + } + } + + @Override + public List<Map.Entry<?, Binding<?>>> getEntries(Iterable<? extends Element> elements) { + // Iterate over the elements, building up the below maps + // This is a preprocessing step allowing us to only iterate over elements + // once and have O(n) runtime + ImmutableMultimap.Builder<K, Key<V>> keyToValueKeyBuilder = ImmutableMultimap.builder(); + ImmutableMap.Builder<Key<V>, Binding<V>> valueKeyToBindingBuilder = ImmutableMap.builder(); + ImmutableMap.Builder<Key<V>, K> valueKeyToKeyBuilder = ImmutableMap.builder(); + ImmutableMap.Builder<Key<V>, Binding<Map.Entry<K, Provider<V>>>> + valueKeyToEntryBindingBuilder = ImmutableMap.builder(); + for (Element element : elements) { + if (element instanceof Binding) { + Binding<?> binding = (Binding<?>) element; + if (bindingSelection.matchesValueKey(binding.getKey()) + && binding.getKey().getTypeLiteral().equals(bindingSelection.valueType)) { + // Safe because of the check on the type literal above + @SuppressWarnings("unchecked") + Binding<V> typedBinding = (Binding<V>) binding; + Key<V> typedKey = typedBinding.getKey(); + valueKeyToBindingBuilder.put(typedKey, typedBinding); + } + } + + if (element instanceof ProviderInstanceBinding + && bindingSelection.getEntrySetBinder().containsElement(element)) { + // Safe because of the instanceof check, and containsElement() check + @SuppressWarnings({"unchecked", "rawtypes"}) + ProviderInstanceBinding<Map.Entry<K, Provider<V>>> entryBinding = + (ProviderInstanceBinding) element; + + // Safe because of the check for containsElement() above + @SuppressWarnings("unchecked") + Provider<Map.Entry<K, Provider<V>>> typedProvider = + (Provider<Map.Entry<K, Provider<V>>>) entryBinding.getUserSuppliedProvider(); + Provider<Map.Entry<K, Provider<V>>> userSuppliedProvider = typedProvider; + + if (userSuppliedProvider instanceof ProviderMapEntry) { + // Safe because of the instanceof check + @SuppressWarnings("unchecked") + ProviderMapEntry<K, V> typedUserSuppliedProvider = + (ProviderMapEntry<K, V>) userSuppliedProvider; + ProviderMapEntry<K, V> entry = typedUserSuppliedProvider; + + keyToValueKeyBuilder.put(entry.getKey(), entry.getValueKey()); + valueKeyToEntryBindingBuilder.put(entry.getValueKey(), entryBinding); + valueKeyToKeyBuilder.put(entry.getValueKey(), entry.getKey()); + } + } + } + + ImmutableMultimap<K, Key<V>> keyToValueKey = keyToValueKeyBuilder.build(); + ImmutableMap<Key<V>, K> valueKeyToKey = valueKeyToKeyBuilder.build(); + ImmutableMap<Key<V>, Binding<V>> valueKeyToBinding = valueKeyToBindingBuilder.build(); + ImmutableMap<Key<V>, Binding<Map.Entry<K, Provider<V>>>> valueKeyToEntryBinding = + valueKeyToEntryBindingBuilder.build(); + + // Check that there is a 1:1 mapping from keys from the ProviderMapEntrys to the + // keys from the Bindings. + Set<Key<V>> keysFromProviderMapEntrys = Sets.newHashSet(keyToValueKey.values()); + Set<Key<V>> keysFromBindings = valueKeyToBinding.keySet(); + + if (!keysFromProviderMapEntrys.equals(keysFromBindings)) { + Set<Key<V>> keysOnlyFromProviderMapEntrys = + Sets.difference(keysFromProviderMapEntrys, keysFromBindings); + Set<Key<V>> keysOnlyFromBindings = + Sets.difference(keysFromBindings, keysFromProviderMapEntrys); + + StringBuilder sb = new StringBuilder("Expected a 1:1 mapping from map keys to values."); + + if (!keysOnlyFromBindings.isEmpty()) { + sb.append( + Errors.format("%nFound these Bindings that were missing an associated entry:%n")); + for (Key<V> key : keysOnlyFromBindings) { + sb.append( + Errors.format(" %s bound at: %s%n", key, valueKeyToBinding.get(key).getSource())); + } + } + + if (!keysOnlyFromProviderMapEntrys.isEmpty()) { + sb.append(Errors.format("%nFound these map keys without a corresponding value:%n")); + for (Key<V> key : keysOnlyFromProviderMapEntrys) { + sb.append( + Errors.format( + " '%s' bound at: %s%n", + valueKeyToKey.get(key), valueKeyToEntryBinding.get(key).getSource())); + } + } + + throw new IllegalArgumentException(sb.toString()); + } + + // Now that we have the two maps, generate the result map + ImmutableList.Builder<Map.Entry<?, Binding<?>>> resultBuilder = ImmutableList.builder(); + for (Map.Entry<K, Key<V>> entry : keyToValueKey.entries()) { + Binding<?> binding = valueKeyToBinding.get(entry.getValue()); + // No null check for binding needed because of the above check to make sure all the + // values in keyToValueKey are present as keys in valueKeyToBinding + + @SuppressWarnings({"unchecked", "rawtypes"}) + Map.Entry<?, Binding<?>> newEntry = + (Map.Entry) Maps.immutableEntry(entry.getKey(), binding); + resultBuilder.add(newEntry); + } + return resultBuilder.build(); + } + + @Override + public boolean permitsDuplicates() { + if (bindingSelection.isInitialized()) { + return bindingSelection.permitsDuplicates(); + } else { + throw new UnsupportedOperationException( + "permitsDuplicates() not supported for module bindings"); + } + } + + @Override + public boolean containsElement(Element element) { + return bindingSelection.containsElement(element); + } + } + + /** + * Binds {@code Map<K, Set<V>>} and {{@code Map<K, Set<Provider<V>>>}. + * + * <p>This will only exist if permitDuplicates() is called. + */ + private static final class MultimapBinder<K, V> implements Module { + private final BindingSelection<K, V> bindingSelection; + + private MultimapBinder(BindingSelection<K, V> bindingSelection) { + this.bindingSelection = bindingSelection; + } + + @Override + public void configure(Binder binder) { + // Binds a Map<K, Set<Provider<V>>> + Provider<Map<K, Set<Provider<V>>>> multimapProvider = + new RealProviderMultimapProvider<K, V>(bindingSelection.getMapKey()); + binder.bind(bindingSelection.getProviderSetMultimapKey()).toProvider(multimapProvider); + + // Provide links from a few different public keys to the providerMultimapKey. + // The collection this exposes is internally an ImmutableMap, so it's OK to massage + // the guice Provider to javax Provider in the value (since the guice Provider implements + // javax Provider). + @SuppressWarnings({"unchecked", "rawtypes"}) + Provider<Map<K, Set<javax.inject.Provider<V>>>> javaxProvider = (Provider) multimapProvider; + binder.bind(bindingSelection.getJavaxProviderSetMultimapKey()).toProvider(javaxProvider); + + @SuppressWarnings({"unchecked", "rawtypes"}) + Provider<Map<K, Collection<Provider<V>>>> collectionProvider = (Provider) multimapProvider; + binder + .bind(bindingSelection.getProviderCollectionMultimapKey()) + .toProvider(collectionProvider); + + @SuppressWarnings({"unchecked", "rawtypes"}) + Provider<Map<K, Collection<javax.inject.Provider<V>>>> collectionJavaxProvider = + (Provider) multimapProvider; + binder + .bind(bindingSelection.getJavaxProviderCollectionMultimapKey()) + .toProvider(collectionJavaxProvider); + + // Binds a Map<K, Set<V>> + @SuppressWarnings({"unchecked", "rawtypes"}) + Provider<Map<K, Set<V>>> realMultimapProvider = + new RealMultimapProvider(bindingSelection.getMapKey()); + binder.bind(bindingSelection.getMultimapKey()).toProvider(realMultimapProvider); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + + @Override + public boolean equals(Object o) { + return o instanceof MultimapBinder + && ((MultimapBinder<?, ?>) o).bindingSelection.equals(bindingSelection); + } + + private static final class RealProviderMultimapProvider<K, V> + extends RealMultimapBinderProviderWithDependencies<K, V, Map<K, Set<Provider<V>>>> { + private Map<K, Set<Provider<V>>> multimapOfProviders; + private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES; + + private RealProviderMultimapProvider(Key<Map<K, V>> mapKey) { + super(mapKey); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return dependencies; + } + + @Override + protected void doInitialize(InjectorImpl injector, Errors errors) { + ImmutableMap.Builder<K, Set<Provider<V>>> multimapOfProvidersBuilder = + ImmutableMap.builder(); + ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); + for (Map.Entry<K, Set<Binding<V>>> entry : + bindingSelection.getMultimapBindings().entrySet()) { + ImmutableSet.Builder<Provider<V>> providersBuilder = ImmutableSet.builder(); + for (Binding<V> binding : entry.getValue()) { + providersBuilder.add(binding.getProvider()); + dependenciesBuilder.add(Dependency.get(getKeyOfProvider(binding.getKey()))); + } + + multimapOfProvidersBuilder.put(entry.getKey(), providersBuilder.build()); + } + multimapOfProviders = multimapOfProvidersBuilder.build(); + dependencies = dependenciesBuilder.build(); + } + + @Override + protected Map<K, Set<Provider<V>>> doProvision( + InternalContext context, Dependency<?> dependency) { + return multimapOfProviders; + } + } + + private static final class RealMultimapProvider<K, V> + extends RealMultimapBinderProviderWithDependencies<K, V, Map<K, Set<V>>> { + + /** + * A simple class to hold a key and the associated bindings as an array. + * + * <p>Arrays are used for performance. + */ + private static final class PerKeyData<K, V> { + private final K key; + private final Binding<V>[] bindings; + private final SingleParameterInjector<V>[] injectors; + + private PerKeyData(K key, Binding<V>[] bindings, SingleParameterInjector<V>[] injectors) { + Preconditions.checkArgument(bindings.length == injectors.length); + + this.key = key; + this.bindings = bindings; + this.injectors = injectors; + } + } + + private Set<Dependency<?>> dependencies = RealMapBinder.MODULE_DEPENDENCIES; + + private PerKeyData<K, V>[] perKeyDatas; + + private RealMultimapProvider(Key<Map<K, V>> mapKey) { + super(mapKey); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return dependencies; + } + + @Override + protected void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException { + @SuppressWarnings({"unchecked", "rawtypes"}) + PerKeyData<K, V>[] typedPerKeyData = + new PerKeyData[bindingSelection.getMapBindings().size()]; + perKeyDatas = typedPerKeyData; + ImmutableSet.Builder<Dependency<?>> dependenciesBuilder = ImmutableSet.builder(); + List<Dependency<?>> dependenciesForKey = Lists.newArrayList(); + int i = 0; + for (Map.Entry<K, Set<Binding<V>>> entry : + bindingSelection.getMultimapBindings().entrySet()) { + // Clear the list of dependencies because we're reusing it for each different key + dependenciesForKey.clear(); + + Set<Binding<V>> bindings = entry.getValue(); + @SuppressWarnings({"unchecked", "rawtypes"}) + Binding<V>[] typedBindings = new Binding[bindings.size()]; + Binding<V>[] bindingsArray = typedBindings; + int j = 0; + for (Binding<V> binding : bindings) { + Dependency<V> dependency = Dependency.get(binding.getKey()); + dependenciesBuilder.add(dependency); + dependenciesForKey.add(dependency); + bindingsArray[j] = binding; + j++; + } + + @SuppressWarnings("unchecked") + SingleParameterInjector<V>[] injectors = + (SingleParameterInjector<V>[]) + injector.getParametersInjectors(dependenciesForKey, errors); + + perKeyDatas[i] = new PerKeyData<>(entry.getKey(), bindingsArray, injectors); + i++; + } + + dependencies = dependenciesBuilder.build(); + } + + @Override + protected Map<K, Set<V>> doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException { + ImmutableMap.Builder<K, Set<V>> resultBuilder = ImmutableMap.builder(); + + for (PerKeyData<K, V> perKeyData : perKeyDatas) { + ImmutableSet.Builder<V> bindingsBuilder = ImmutableSet.builder(); + SingleParameterInjector<V>[] injectors = perKeyData.injectors; + for (int i = 0; i < injectors.length; i++) { + SingleParameterInjector<V> injector = injectors[i]; + V value = injector.inject(context); + + if (value == null) { + throw createNullValueException(perKeyData.key, perKeyData.bindings[i]); + } + + bindingsBuilder.add(value); + } + + resultBuilder.put(perKeyData.key, bindingsBuilder.build()); + } + + return resultBuilder.build(); + } + } + } + + /** A factory for a {@code Map.Entry<K, Provider<V>>}. */ + //VisibleForTesting + static final class ProviderMapEntry<K, V> + extends InternalProviderInstanceBindingImpl.Factory<Map.Entry<K, Provider<V>>> { + private final K key; + private final Key<V> valueKey; + private Map.Entry<K, Provider<V>> entry; + + ProviderMapEntry(K key, Key<V> valueKey) { + super(InitializationTiming.EAGER); + this.key = key; + this.valueKey = valueKey; + } + + @Override + public Set<Dependency<?>> getDependencies() { + // The dependencies are Key<Provider<V>> + return ImmutableSet.<Dependency<?>>of(Dependency.get(getKeyOfProvider(valueKey))); + } + + @Override + void initialize(InjectorImpl injector, Errors errors) { + Binding<V> valueBinding = injector.getExistingBinding(valueKey); + entry = Maps.immutableEntry(key, valueBinding.getProvider()); + } + + @Override + protected Map.Entry<K, Provider<V>> doProvision( + InternalContext context, Dependency<?> dependency) { + return entry; + } + + K getKey() { + return key; + } + + Key<V> getValueKey() { + return valueKey; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof ProviderMapEntry) { + ProviderMapEntry<?, ?> o = (ProviderMapEntry<?, ?>) obj; + return key.equals(o.key) && valueKey.equals(o.valueKey); + } + return false; + } + + @Override + public int hashCode() { + return Objects.hashCode(key, valueKey); + } + + @Override + public String toString() { + return "ProviderMapEntry(" + key + ", " + valueKey + ")"; + } + } + + /** A base class for ProviderWithDependencies that need equality based on a specific object. */ + private abstract static class RealMapBinderProviderWithDependencies<K, V, P> + extends InternalProviderInstanceBindingImpl.Factory<P> { + final BindingSelection<K, V> bindingSelection; + + private RealMapBinderProviderWithDependencies(BindingSelection<K, V> bindingSelection) { + // While MapBinders only depend on bindings created in modules so we could theoretically + // initialize eagerly, they also depend on + // 1. findBindingsByType returning results + // 2. being able to call BindingImpl.acceptTargetVisitor + // neither of those is available during eager initialization, so we use DELAYED + super(InitializationTiming.DELAYED); + + this.bindingSelection = bindingSelection; + } + + @Override + final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + if (bindingSelection.tryInitialize(injector, errors)) { + doInitialize(injector, errors); + } + } + + /** + * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and + * this will be called prior to any provisioning. + */ + protected abstract void doInitialize(InjectorImpl injector, Errors errors) + throws ErrorsException; + + @Override + public boolean equals(Object obj) { + return obj != null + && this.getClass() == obj.getClass() + && bindingSelection.equals( + ((RealMapBinderProviderWithDependencies<?, ?, ?>) obj).bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + } + + /** + * A base class for ProviderWithDependencies that need equality based on a specific object. + * + * <p>This differs from {@link RealMapBinderProviderWithDependencies} in that it gets the {@code + * bindingSelection} from the injector at initialization time, rather than in the constructor. + * This is done to allow all the providers to operate on the same instance of the {@link + * BindingSelection}. + */ + private abstract static class RealMultimapBinderProviderWithDependencies<K, V, P> + extends InternalProviderInstanceBindingImpl.Factory<P> { + final Key<Map<K, V>> mapKey; + BindingSelection<K, V> bindingSelection; + + private RealMultimapBinderProviderWithDependencies(Key<Map<K, V>> mapKey) { + // While MapBinders only depend on bindings created in modules so we could theoretically + // initialize eagerly, they also depend on + // 1. findBindingsByType returning results + // 2. being able to call BindingImpl.acceptTargetVisitor + // neither of those is available during eager initialization, so we use DELAYED + super(InitializationTiming.DELAYED); + + this.mapKey = mapKey; + } + + /** + * This will get the authoritative {@link BindingSelection} from the map provider. This + * guarantees that everyone has the same instance of the bindingSelection and sees consistent + * state. + */ + @Override + final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + Binding<Map<K, V>> mapBinding = injector.getExistingBinding(mapKey); + ProviderInstanceBinding<Map<K, V>> providerInstanceBinding = + (ProviderInstanceBinding<Map<K, V>>) mapBinding; + @SuppressWarnings("unchecked") + RealMapProvider<K, V> mapProvider = + (RealMapProvider<K, V>) providerInstanceBinding.getUserSuppliedProvider(); + + this.bindingSelection = mapProvider.getBindingSelection(); + + if (bindingSelection.tryInitialize(injector, errors)) { + doInitialize(injector, errors); + } + } + + /** + * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and + * this will be called prior to any provisioning. + */ + abstract void doInitialize(InjectorImpl injector, Errors errors) throws ErrorsException; + + @Override + public boolean equals(Object obj) { + return obj != null + && this.getClass() == obj.getClass() + && mapKey.equals(((RealMultimapBinderProviderWithDependencies<?, ?, ?>) obj).mapKey); + } + + @Override + public int hashCode() { + return mapKey.hashCode(); + } + } + + private static <K, V> InternalProvisionException createNullValueException( + K key, Binding<V> binding) { + return InternalProvisionException.create( + "Map injection failed due to null value for key \"%s\", bound at: %s", + key, binding.getSource()); + } +} diff --git a/core/src/com/google/inject/internal/RealMultibinder.java b/core/src/com/google/inject/internal/RealMultibinder.java new file mode 100644 index 00000000..aa887f4e --- /dev/null +++ b/core/src/com/google/inject/internal/RealMultibinder.java @@ -0,0 +1,604 @@ +package com.google.inject.internal; + +import static com.google.inject.internal.Element.Type.MULTIBINDER; +import static com.google.inject.internal.Errors.checkConfiguration; +import static com.google.inject.internal.Errors.checkNotNull; +import static com.google.inject.name.Names.named; + +import com.google.common.base.Objects; +import com.google.common.collect.ImmutableList; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import com.google.inject.AbstractModule; +import com.google.inject.Binder; +import com.google.inject.Binding; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming; +import com.google.inject.multibindings.MultibinderBinding; +import com.google.inject.multibindings.MultibindingsTargetVisitor; +import com.google.inject.spi.BindingTargetVisitor; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.ProviderInstanceBinding; +import com.google.inject.spi.ProviderWithExtensionVisitor; +import com.google.inject.util.Types; +import java.lang.reflect.Type; +import java.util.Collection; +import java.util.List; +import java.util.Set; + +/** + * The actual multibinder plays several roles: + * + * <p>As a Multibinder, it acts as a factory for LinkedBindingBuilders for each of the set's + * elements. Each binding is given an annotation that identifies it as a part of this set. + * + * <p>As a Module, it installs the binding to the set itself. As a module, this implements equals() + * and hashcode() in order to trick Guice into executing its configure() method only once. That + * makes it so that multiple multibinders can be created for the same target collection, but only + * one is bound. Since the list of bindings is retrieved from the injector itself (and not the + * multibinder), each multibinder has access to all contributions from all multibinders. + * + * <p>As a Provider, this constructs the set instances. + * + * <p>We use a subclass to hide 'implements Module, Provider' from the public API. + */ +public final class RealMultibinder<T> implements Module { + + /** Implementation of newSetBinder. */ + public static <T> RealMultibinder<T> newRealSetBinder(Binder binder, Key<T> key) { + binder = binder.skipSources(RealMultibinder.class); + RealMultibinder<T> result = new RealMultibinder<>(binder, key); + binder.install(result); + return result; + } + + @SuppressWarnings("unchecked") // wrapping a T in a Set safely returns a Set<T> + static <T> TypeLiteral<Set<T>> setOf(TypeLiteral<T> elementType) { + Type type = Types.setOf(elementType.getType()); + return (TypeLiteral<Set<T>>) TypeLiteral.get(type); + } + + @SuppressWarnings("unchecked") + static <T> TypeLiteral<Collection<Provider<T>>> collectionOfProvidersOf( + TypeLiteral<T> elementType) { + Type providerType = Types.providerOf(elementType.getType()); + Type type = Types.collectionOf(providerType); + return (TypeLiteral<Collection<Provider<T>>>) TypeLiteral.get(type); + } + + @SuppressWarnings("unchecked") + static <T> TypeLiteral<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersOf( + TypeLiteral<T> elementType) { + Type providerType = + Types.newParameterizedType(javax.inject.Provider.class, elementType.getType()); + Type type = Types.collectionOf(providerType); + return (TypeLiteral<Collection<javax.inject.Provider<T>>>) TypeLiteral.get(type); + } + + private final BindingSelection<T> bindingSelection; + private final Binder binder; + + RealMultibinder(Binder binder, Key<T> key) { + this.binder = checkNotNull(binder, "binder"); + this.bindingSelection = new BindingSelection<>(key); + } + + @Override + public void configure(Binder binder) { + checkConfiguration(!bindingSelection.isInitialized(), "Multibinder was already initialized"); + binder + .bind(bindingSelection.getSetKey()) + .toProvider(new RealMultibinderProvider<T>(bindingSelection)); + Provider<Collection<Provider<T>>> collectionOfProvidersProvider = + new RealMultibinderCollectionOfProvidersProvider<T>(bindingSelection); + binder + .bind(bindingSelection.getCollectionOfProvidersKey()) + .toProvider(collectionOfProvidersProvider); + + // The collection this exposes is internally an ImmutableList, so it's OK to massage + // the guice Provider to javax Provider in the value (since the guice Provider implements + // javax Provider). + @SuppressWarnings("unchecked") + Provider<Collection<javax.inject.Provider<T>>> javaxProvider = + (Provider) collectionOfProvidersProvider; + binder.bind(bindingSelection.getCollectionOfJavaxProvidersKey()).toProvider(javaxProvider); + } + + public void permitDuplicates() { + binder.install(new PermitDuplicatesModule(bindingSelection.getPermitDuplicatesKey())); + } + + /** Adds a new entry to the set and returns the key for it. */ + Key<T> getKeyForNewItem() { + checkConfiguration(!bindingSelection.isInitialized(), "Multibinder was already initialized"); + return Key.get( + bindingSelection.getElementTypeLiteral(), + new RealElement(bindingSelection.getSetName(), MULTIBINDER, "")); + } + + public LinkedBindingBuilder<T> addBinding() { + return binder.bind(getKeyForNewItem()); + } + + // These methods are used by RealMapBinder + + Key<Set<T>> getSetKey() { + return bindingSelection.getSetKey(); + } + + TypeLiteral<T> getElementTypeLiteral() { + return bindingSelection.getElementTypeLiteral(); + } + + String getSetName() { + return bindingSelection.getSetName(); + } + + boolean permitsDuplicates(Injector injector) { + return bindingSelection.permitsDuplicates(injector); + } + + boolean containsElement(com.google.inject.spi.Element element) { + return bindingSelection.containsElement(element); + } + + private static final class RealMultibinderProvider<T> + extends InternalProviderInstanceBindingImpl.Factory<Set<T>> + implements ProviderWithExtensionVisitor<Set<T>>, MultibinderBinding<Set<T>> { + private final BindingSelection<T> bindingSelection; + private List<Binding<T>> bindings; + private SingleParameterInjector<T>[] injectors; + private boolean permitDuplicates; + + RealMultibinderProvider(BindingSelection<T> bindingSelection) { + // While Multibinders only depend on bindings created in modules so we could theoretically + // initialize eagerly, they also depend on + // 1. findBindingsByType returning results + // 2. being able to call BindingImpl.acceptTargetVisitor + // neither of those is available during eager initialization, so we use DELAYED + super(InitializationTiming.DELAYED); + this.bindingSelection = bindingSelection; + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.getDependencies(); + } + + @Override + void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + bindingSelection.initialize(injector, errors); + this.bindings = bindingSelection.getBindings(); + this.injectors = bindingSelection.getParameterInjectors(); + this.permitDuplicates = bindingSelection.permitsDuplicates(); + } + + @Override + protected Set<T> doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException { + SingleParameterInjector<T>[] localInjectors = injectors; + if (localInjectors == null) { + // if localInjectors == null, then we have no bindings so return the empty set. + return ImmutableSet.of(); + } + // Ideally we would just add to an ImmutableSet.Builder, but if we did that and there were + // duplicates we wouldn't be able to tell which one was the duplicate. So to manage this we + // first put everything into an array and then construct the set. This way if something gets + // dropped we can figure out what it is. + @SuppressWarnings("unchecked") + T[] values = (T[]) new Object[localInjectors.length]; + for (int i = 0; i < localInjectors.length; i++) { + SingleParameterInjector<T> parameterInjector = localInjectors[i]; + T newValue = parameterInjector.inject(context); + if (newValue == null) { + throw newNullEntryException(i); + } + values[i] = newValue; + } + ImmutableSet<T> set = ImmutableSet.copyOf(values); + // There are fewer items in the set than the array. Figure out which one got dropped. + if (!permitDuplicates && set.size() < values.length) { + throw newDuplicateValuesException(set, values); + } + return set; + } + + private InternalProvisionException newNullEntryException(int i) { + return InternalProvisionException.create( + "Set injection failed due to null element bound at: %s", bindings.get(i).getSource()); + } + + @SuppressWarnings("unchecked") + @Override + public <B, V> V acceptExtensionVisitor( + BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding) { + if (visitor instanceof MultibindingsTargetVisitor) { + return ((MultibindingsTargetVisitor<Set<T>, V>) visitor).visit(this); + } else { + return visitor.visit(binding); + } + } + + private InternalProvisionException newDuplicateValuesException( + ImmutableSet<T> set, T[] values) { + // TODO(lukes): consider reporting all duplicate values, the easiest way would be to rebuild + // a new set and detect dupes as we go + // Find the duplicate binding + // To do this we take advantage of the fact that set, values and bindings all have the same + // ordering for a non-empty prefix of the set. + // First we scan for the first item dropped from the set. + int newBindingIndex = 0; + for (T item : set) { + if (item != values[newBindingIndex]) { + break; + } + newBindingIndex++; + } + // once we exit the loop newBindingIndex will point at the first item in values that was + // dropped. + + Binding<T> newBinding = bindings.get(newBindingIndex); + T newValue = values[newBindingIndex]; + // Now we scan again to find the index of the value, we are guaranteed to find it. + int oldBindingIndex = set.asList().indexOf(newValue); + T oldValue = values[oldBindingIndex]; + Binding<T> duplicateBinding = bindings.get(oldBindingIndex); + String oldString = oldValue.toString(); + String newString = newValue.toString(); + if (Objects.equal(oldString, newString)) { + // When the value strings match, just show the source of the bindings + return InternalProvisionException.create( + "Set injection failed due to duplicated element \"%s\"" + + "\n Bound at %s\n Bound at %s", + newValue, duplicateBinding.getSource(), newBinding.getSource()); + } else { + // When the value strings don't match, include them both as they may be useful for debugging + return InternalProvisionException.create( + "Set injection failed due to multiple elements comparing equal:" + + "\n \"%s\"\n bound at %s" + + "\n \"%s\"\n bound at %s", + oldValue, duplicateBinding.getSource(), newValue, newBinding.getSource()); + } + } + + @Override + public boolean equals(Object obj) { + return obj instanceof RealMultibinderProvider + && bindingSelection.equals(((RealMultibinderProvider<?>) obj).bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + + @Override + public Key<Set<T>> getSetKey() { + return bindingSelection.getSetKey(); + } + + @Override + public TypeLiteral<?> getElementTypeLiteral() { + return bindingSelection.getElementTypeLiteral(); + } + + @Override + public List<Binding<?>> getElements() { + return bindingSelection.getElements(); + } + + @Override + public boolean permitsDuplicates() { + return bindingSelection.permitsDuplicates(); + } + + @Override + public boolean containsElement(com.google.inject.spi.Element element) { + return bindingSelection.containsElement(element); + } + } + + private static final class BindingSelection<T> { + // prior to initialization we declare just a dependency on the injector, but as soon as we are + // initialized we swap to dependencies on the elements. + private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES = + ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class))); + private final TypeLiteral<T> elementType; + private final Key<Set<T>> setKey; + + // these are all lazily allocated + private String setName; + private Key<Collection<Provider<T>>> collectionOfProvidersKey; + private Key<Collection<javax.inject.Provider<T>>> collectionOfJavaxProvidersKey; + private Key<Boolean> permitDuplicatesKey; + + private boolean isInitialized; + /* a binding for each element in the set. null until initialization, non-null afterwards */ + private ImmutableList<Binding<T>> bindings; + + // Starts out as Injector and gets set up properly after initialization + private ImmutableSet<Dependency<?>> dependencies = MODULE_DEPENDENCIES; + private ImmutableSet<Dependency<?>> providerDependencies = MODULE_DEPENDENCIES; + + /** whether duplicates are allowed. Possibly configured by a different instance */ + private boolean permitDuplicates; + + private SingleParameterInjector<T>[] parameterinjectors; + + BindingSelection(Key<T> key) { + this.setKey = key.ofType(setOf(key.getTypeLiteral())); + this.elementType = key.getTypeLiteral(); + } + + void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + // This will be called multiple times, once by each Factory. We only want + // to do the work to initialize everything once, so guard this code with + // isInitialized. + if (isInitialized) { + return; + } + List<Binding<T>> bindings = Lists.newArrayList(); + Set<Indexer.IndexedBinding> index = Sets.newHashSet(); + Indexer indexer = new Indexer(injector); + List<Dependency<?>> dependencies = Lists.newArrayList(); + List<Dependency<?>> providerDependencies = Lists.newArrayList(); + for (Binding<?> entry : injector.findBindingsByType(elementType)) { + if (keyMatches(entry.getKey())) { + @SuppressWarnings("unchecked") // protected by findBindingsByType() + Binding<T> binding = (Binding<T>) entry; + if (index.add(binding.acceptTargetVisitor(indexer))) { + // TODO(lukes): most of these are linked bindings since user bindings are linked to + // a user binding through the @Element annotation. Since this is an implementation + // detail we could 'dereference' the @Element if it is a LinkedBinding and avoid + // provisioning through the FactoryProxy at runtime. + // Ditto for OptionalBinder/MapBinder + bindings.add(binding); + Key<T> key = binding.getKey(); + // TODO(lukes): we should mark this as a non-nullable dependency since we don't accept + // null. + // Add a dependency on Key<T> + dependencies.add(Dependency.get(key)); + // and add a dependency on Key<Provider<T>> + providerDependencies.add( + Dependency.get(key.ofType(Types.providerOf(key.getTypeLiteral().getType())))); + } + } + } + + this.bindings = ImmutableList.copyOf(bindings); + this.dependencies = ImmutableSet.copyOf(dependencies); + this.providerDependencies = ImmutableSet.copyOf(providerDependencies); + this.permitDuplicates = permitsDuplicates(injector); + // This is safe because all our dependencies are assignable to T and we never assign to + // elements of this array. + @SuppressWarnings("unchecked") + SingleParameterInjector<T>[] typed = + (SingleParameterInjector<T>[]) injector.getParametersInjectors(dependencies, errors); + this.parameterinjectors = typed; + isInitialized = true; + } + + boolean permitsDuplicates(Injector injector) { + return injector.getBindings().containsKey(getPermitDuplicatesKey()); + } + + ImmutableList<Binding<T>> getBindings() { + checkConfiguration(isInitialized, "not initialized"); + return bindings; + } + + SingleParameterInjector<T>[] getParameterInjectors() { + checkConfiguration(isInitialized, "not initialized"); + return parameterinjectors; + } + + ImmutableSet<Dependency<?>> getDependencies() { + return dependencies; + } + + ImmutableSet<Dependency<?>> getProviderDependencies() { + return providerDependencies; + } + + String getSetName() { + // lazily initialized since most selectors don't survive module installation. + if (setName == null) { + setName = Annotations.nameOf(setKey); + } + return setName; + } + + Key<Boolean> getPermitDuplicatesKey() { + Key<Boolean> local = permitDuplicatesKey; + if (local == null) { + local = + permitDuplicatesKey = Key.get(Boolean.class, named(toString() + " permits duplicates")); + } + return local; + } + + Key<Collection<Provider<T>>> getCollectionOfProvidersKey() { + Key<Collection<Provider<T>>> local = collectionOfProvidersKey; + if (local == null) { + local = collectionOfProvidersKey = setKey.ofType(collectionOfProvidersOf(elementType)); + } + return local; + } + + Key<Collection<javax.inject.Provider<T>>> getCollectionOfJavaxProvidersKey() { + Key<Collection<javax.inject.Provider<T>>> local = collectionOfJavaxProvidersKey; + if (local == null) { + local = + collectionOfJavaxProvidersKey = + setKey.ofType(collectionOfJavaxProvidersOf(elementType)); + } + return local; + } + + boolean isInitialized() { + return isInitialized; + } + + // MultibinderBinding API methods + + TypeLiteral<T> getElementTypeLiteral() { + return elementType; + } + + Key<Set<T>> getSetKey() { + return setKey; + } + + @SuppressWarnings("unchecked") + List<Binding<?>> getElements() { + if (isInitialized()) { + return (List<Binding<?>>) (List<?>) bindings; // safe because bindings is immutable. + } else { + throw new UnsupportedOperationException("getElements() not supported for module bindings"); + } + } + + boolean permitsDuplicates() { + if (isInitialized()) { + return permitDuplicates; + } else { + throw new UnsupportedOperationException( + "permitsDuplicates() not supported for module bindings"); + } + } + + boolean containsElement(com.google.inject.spi.Element element) { + if (element instanceof Binding) { + Binding<?> binding = (Binding<?>) element; + return keyMatches(binding.getKey()) + || binding.getKey().equals(getPermitDuplicatesKey()) + || binding.getKey().equals(setKey) + || binding.getKey().equals(collectionOfProvidersKey) + || binding.getKey().equals(collectionOfJavaxProvidersKey); + } else { + return false; + } + } + + private boolean keyMatches(Key<?> key) { + return key.getTypeLiteral().equals(elementType) + && key.getAnnotation() instanceof Element + && ((Element) key.getAnnotation()).setName().equals(getSetName()) + && ((Element) key.getAnnotation()).type() == MULTIBINDER; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof BindingSelection) { + return setKey.equals(((BindingSelection<?>) obj).setKey); + } + return false; + } + + @Override + public int hashCode() { + return setKey.hashCode(); + } + + @Override + public String toString() { + return (getSetName().isEmpty() ? "" : getSetName() + " ") + + "Multibinder<" + + elementType + + ">"; + } + } + + @Override + public boolean equals(Object o) { + return o instanceof RealMultibinder + && ((RealMultibinder<?>) o).bindingSelection.equals(bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + + private static final class RealMultibinderCollectionOfProvidersProvider<T> + extends InternalProviderInstanceBindingImpl.Factory<Collection<Provider<T>>> { + + private final BindingSelection<T> bindingSelection; + private ImmutableList<Provider<T>> collectionOfProviders; + + RealMultibinderCollectionOfProvidersProvider(BindingSelection<T> bindingSelection) { + super(InitializationTiming.DELAYED); // See comment in RealMultibinderProvider + this.bindingSelection = bindingSelection; + } + + @Override + void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + bindingSelection.initialize(injector, errors); + ImmutableList.Builder<Provider<T>> providers = ImmutableList.builder(); + for (Binding<T> binding : bindingSelection.getBindings()) { + providers.add(binding.getProvider()); + } + this.collectionOfProviders = providers.build(); + } + + @Override + protected Collection<Provider<T>> doProvision( + InternalContext context, Dependency<?> dependency) { + return collectionOfProviders; + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.getProviderDependencies(); + } + + @Override + public boolean equals(Object obj) { + return obj instanceof RealMultibinderCollectionOfProvidersProvider + && bindingSelection.equals( + ((RealMultibinderCollectionOfProvidersProvider<?>) obj).bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + } + + /** + * We install the permit duplicates configuration as its own binding, all by itself. This way, if + * only one of a multibinder's users remember to call permitDuplicates(), they're still permitted. + * + * <p>This is like setting a global variable in the injector so that each instance of the + * multibinder will have the same value for permitDuplicates, even if it is only set on one of + * them. + */ + private static class PermitDuplicatesModule extends AbstractModule { + private final Key<Boolean> key; + + PermitDuplicatesModule(Key<Boolean> key) { + this.key = key; + } + + @Override + protected void configure() { + bind(key).toInstance(true); + } + + @Override + public boolean equals(Object o) { + return o instanceof PermitDuplicatesModule && ((PermitDuplicatesModule) o).key.equals(key); + } + + @Override + public int hashCode() { + return getClass().hashCode() ^ key.hashCode(); + } + } +} diff --git a/core/src/com/google/inject/internal/RealOptionalBinder.java b/core/src/com/google/inject/internal/RealOptionalBinder.java new file mode 100644 index 00000000..7072d2e8 --- /dev/null +++ b/core/src/com/google/inject/internal/RealOptionalBinder.java @@ -0,0 +1,844 @@ +/* + * Copyright (C) 2016 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.internal; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; +import static com.google.inject.internal.Errors.checkConfiguration; +import static com.google.inject.util.Types.newParameterizedType; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.common.base.Optional; +import com.google.common.base.Throwables; +import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Iterables; +import com.google.inject.Binder; +import com.google.inject.Binding; +import com.google.inject.Injector; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.Provider; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.InternalProviderInstanceBindingImpl.InitializationTiming; +import com.google.inject.multibindings.MultibindingsTargetVisitor; +import com.google.inject.multibindings.OptionalBinderBinding; +import com.google.inject.spi.BindingTargetVisitor; +import com.google.inject.spi.Dependency; +import com.google.inject.spi.Element; +import com.google.inject.spi.ProviderInstanceBinding; +import com.google.inject.spi.ProviderWithExtensionVisitor; +import com.google.inject.util.Types; +import java.io.Serializable; +import java.lang.annotation.Annotation; +import java.lang.annotation.Retention; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Type; +import java.util.Set; +import javax.inject.Qualifier; + +/** + * The actual OptionalBinder plays several roles. It implements Module to hide that fact from the + * public API, and installs the various bindings that are exposed to the user. + */ +public final class RealOptionalBinder<T> implements Module { + public static <T> RealOptionalBinder<T> newRealOptionalBinder(Binder binder, Key<T> type) { + binder = binder.skipSources(RealOptionalBinder.class); + RealOptionalBinder<T> optionalBinder = new RealOptionalBinder<>(binder, type); + binder.install(optionalBinder); + return optionalBinder; + } + + /* Reflectively capture java 8's Optional types so we can bind them if we're running in java8. */ + private static final Class<?> JAVA_OPTIONAL_CLASS; + private static final Object JAVA_OPTIONAL_EMPTY; + private static final Method JAVA_OPTIONAL_OF_METHOD; + + static { + Class<?> optional = null; + Object emptyObject = null; + Method of = null; + boolean useJavaOptional = false; + try { + optional = Class.forName("java.util.Optional"); + emptyObject = optional.getDeclaredMethod("empty").invoke(null); + of = optional.getDeclaredMethod("of", Object.class); + // only use optional support if all our reflection succeeded + useJavaOptional = true; + } catch (ClassNotFoundException ignored) { + } catch (NoSuchMethodException ignored) { + } catch (SecurityException ignored) { + } catch (IllegalAccessException ignored) { + } catch (InvocationTargetException ignored) { + } + JAVA_OPTIONAL_CLASS = useJavaOptional ? optional : null; + JAVA_OPTIONAL_EMPTY = useJavaOptional ? emptyObject : null; + JAVA_OPTIONAL_OF_METHOD = useJavaOptional ? of : null; + } + + /** + * Returns java.util.Optional.empty() if the parameter is null, calls {@link + * #invokeJavaOptionalOf} otherwise. + */ + private static Object invokeJavaOptionalOfNullable(Object o) { + if (o == null) { + return JAVA_OPTIONAL_EMPTY; + } + return invokeJavaOptionalOf(o); + } + + /** Invokes java.util.Optional.of. */ + private static Object invokeJavaOptionalOf(Object o) { + try { + return JAVA_OPTIONAL_OF_METHOD.invoke(null, o); + } catch (IllegalAccessException e) { + throw new SecurityException(e); + } catch (IllegalArgumentException e) { + throw new IllegalStateException(e); + } catch (InvocationTargetException e) { + throw Throwables.propagate(e.getCause()); + } + } + + @SuppressWarnings("unchecked") + static <T> TypeLiteral<Optional<T>> optionalOf(TypeLiteral<T> type) { + return (TypeLiteral<Optional<T>>) + TypeLiteral.get(Types.newParameterizedType(Optional.class, type.getType())); + } + + static <T> TypeLiteral<?> javaOptionalOf(TypeLiteral<T> type) { + checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found"); + return TypeLiteral.get(Types.newParameterizedType(JAVA_OPTIONAL_CLASS, type.getType())); + } + + @SuppressWarnings("unchecked") + static <T> TypeLiteral<Optional<javax.inject.Provider<T>>> optionalOfJavaxProvider( + TypeLiteral<T> type) { + return (TypeLiteral<Optional<javax.inject.Provider<T>>>) + TypeLiteral.get( + Types.newParameterizedType( + Optional.class, newParameterizedType(javax.inject.Provider.class, type.getType()))); + } + + static <T> TypeLiteral<?> javaOptionalOfJavaxProvider(TypeLiteral<T> type) { + checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found"); + return TypeLiteral.get( + Types.newParameterizedType( + JAVA_OPTIONAL_CLASS, + newParameterizedType(javax.inject.Provider.class, type.getType()))); + } + + @SuppressWarnings("unchecked") + static <T> TypeLiteral<Optional<Provider<T>>> optionalOfProvider(TypeLiteral<T> type) { + return (TypeLiteral<Optional<Provider<T>>>) + TypeLiteral.get( + Types.newParameterizedType( + Optional.class, newParameterizedType(Provider.class, type.getType()))); + } + + static <T> TypeLiteral<?> javaOptionalOfProvider(TypeLiteral<T> type) { + checkState(JAVA_OPTIONAL_CLASS != null, "java.util.Optional not found"); + return TypeLiteral.get( + Types.newParameterizedType( + JAVA_OPTIONAL_CLASS, newParameterizedType(Provider.class, type.getType()))); + } + + @SuppressWarnings("unchecked") + static <T> Key<Provider<T>> providerOf(Key<T> key) { + Type providerT = Types.providerOf(key.getTypeLiteral().getType()); + return (Key<Provider<T>>) key.ofType(providerT); + } + + enum Source { + DEFAULT, + ACTUAL + } + + @Retention(RUNTIME) + @Qualifier + @interface Default { + String value(); + } + + @Retention(RUNTIME) + @Qualifier + @interface Actual { + String value(); + } + + private final BindingSelection<T> bindingSelection; + private final Binder binder; + + private RealOptionalBinder(Binder binder, Key<T> typeKey) { + this.bindingSelection = new BindingSelection<>(typeKey); + this.binder = binder; + } + + /** + * Adds a binding for T. Multiple calls to this are safe, and will be collapsed as duplicate + * bindings. + */ + private void addDirectTypeBinding(Binder binder) { + binder + .bind(bindingSelection.getDirectKey()) + .toProvider(new RealDirectTypeProvider<T>(bindingSelection)); + } + + /** + * Returns the key to use for the default binding. + * + * <p>As a side effect this installs support for the 'direct type', so a binding for {@code T} + * will be made available. + */ + Key<T> getKeyForDefaultBinding() { + bindingSelection.checkNotInitialized(); + addDirectTypeBinding(binder); + return bindingSelection.getKeyForDefaultBinding(); + } + + public LinkedBindingBuilder<T> setDefault() { + return binder.bind(getKeyForDefaultBinding()); + } + + /** + * Returns the key to use for the actual binding, overrides the default if set. + * + * <p>As a side effect this installs support for the 'direct type', so a binding for {@code T} + * will be made available. + */ + Key<T> getKeyForActualBinding() { + bindingSelection.checkNotInitialized(); + addDirectTypeBinding(binder); + return bindingSelection.getKeyForActualBinding(); + } + + public LinkedBindingBuilder<T> setBinding() { + return binder.bind(getKeyForActualBinding()); + } + + @Override + public void configure(Binder binder) { + bindingSelection.checkNotInitialized(); + Key<T> key = bindingSelection.getDirectKey(); + // Every OptionalBinder get's the following types bound + // * Optional<Provider<T>> + // * Optional<javax.inject.Provider<T>> + // * Optional<T> + // If setDefault() or setBinding() is called then also + // * T is bound + // If java.util.Optional is on the classpath (because this is a jdk8+ vm), then you also get + // * java.util.Optional<Provider<T>> + // * java.util.Optional<javax.inject.Provider<T>> + // * java.util.Optional<T> + InternalProviderInstanceBindingImpl.Factory<Optional<Provider<T>>> optionalProviderFactory = + new RealOptionalProviderProvider<T>(bindingSelection); + binder + .bind(key.ofType(optionalOfProvider(key.getTypeLiteral()))) + .toProvider(optionalProviderFactory); + + // Provider is assignable to javax.inject.Provider and the provider that the factory contains + // cannot be modified so we can use some rawtypes hackery to share the same implementation. + @SuppressWarnings("unchecked") + InternalProviderInstanceBindingImpl.Factory<Optional<javax.inject.Provider<T>>> + optionalJavaxProviderFactory = + (InternalProviderInstanceBindingImpl.Factory) optionalProviderFactory; + binder + .bind(key.ofType(optionalOfJavaxProvider(key.getTypeLiteral()))) + .toProvider(optionalJavaxProviderFactory); + + Key<Optional<T>> optionalKey = key.ofType(optionalOf(key.getTypeLiteral())); + binder + .bind(optionalKey) + .toProvider(new RealOptionalKeyProvider<T>(bindingSelection, optionalKey)); + + // Bind the java-8 types if we know them. + bindJava8Optional(binder); + } + + @SuppressWarnings("unchecked") + private void bindJava8Optional(Binder binder) { + if (JAVA_OPTIONAL_CLASS != null) { + Key<?> key = bindingSelection.getDirectKey(); + TypeLiteral<?> typeLiteral = key.getTypeLiteral(); + InternalProviderInstanceBindingImpl.Factory<Object> javaOptionalProviderFactory = + new JavaOptionalProviderProvider(bindingSelection); + binder + .bind(key.ofType(javaOptionalOfProvider(typeLiteral))) + .toProvider((Provider) javaOptionalProviderFactory); + // Provider is assignable to javax.inject.Provider and the provider that the factory contains + // cannot be modified so we can use some rawtypes hackery to share the same implementation. + binder + .bind(key.ofType(javaOptionalOfJavaxProvider(typeLiteral))) + .toProvider((Provider) javaOptionalProviderFactory); + Key<?> javaOptionalKey = key.ofType(javaOptionalOf(typeLiteral)); + binder + .bind(javaOptionalKey) + .toProvider(new JavaOptionalProvider(bindingSelection, javaOptionalKey)); + } + } + + /** Provides the binding for java.util.Optional<T>. */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static final class JavaOptionalProvider extends RealOptionalBinderProviderWithDependencies + implements ProviderWithExtensionVisitor, OptionalBinderBinding { + + private final Key<?> optionalKey; + + private Dependency<?> targetDependency; + private InternalFactory<?> target; + + JavaOptionalProvider(BindingSelection<?> bindingSelection, Key<?> optionalKey) { + super(bindingSelection); + this.optionalKey = optionalKey; + } + + @Override + void doInitialize() { + if (bindingSelection.getBinding() != null) { + target = bindingSelection.getBinding().getInternalFactory(); + targetDependency = bindingSelection.getDependency(); + } + } + + @Override + protected Object doProvision(InternalContext context, Dependency dependency) + throws InternalProvisionException { + InternalFactory<?> local = target; + if (local == null) { + return JAVA_OPTIONAL_EMPTY; + } + Dependency<?> localDependency = targetDependency; + Object result; + Dependency previous = context.pushDependency(localDependency, getSource()); + + try { + // See comments in RealOptionalKeyProvider, about how localDependency may be more specific + // than what we actually need. + result = local.get(context, localDependency, false); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localDependency); + } finally { + context.popStateAndSetDependency(previous); + + } + return invokeJavaOptionalOfNullable(result); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.dependencies; + } + + @SuppressWarnings("unchecked") + @Override + public Object acceptExtensionVisitor( + BindingTargetVisitor visitor, ProviderInstanceBinding binding) { + if (visitor instanceof MultibindingsTargetVisitor) { + return ((MultibindingsTargetVisitor) visitor).visit(this); + } else { + return visitor.visit(binding); + } + } + + @Override + public boolean containsElement(Element element) { + return bindingSelection.containsElement(element); + } + + @Override + public Binding<?> getActualBinding() { + return bindingSelection.getActualBinding(); + } + + @Override + public Binding<?> getDefaultBinding() { + return bindingSelection.getDefaultBinding(); + } + + @Override + public Key getKey() { + return optionalKey; + } + } + + /** Provides the binding for java.util.Optional<Provider<T>>. */ + @SuppressWarnings({"rawtypes", "unchecked"}) + private static final class JavaOptionalProviderProvider + extends RealOptionalBinderProviderWithDependencies { + private Object value; + + JavaOptionalProviderProvider(BindingSelection<?> bindingSelection) { + super(bindingSelection); + } + + @Override + void doInitialize() { + if (bindingSelection.getBinding() == null) { + value = JAVA_OPTIONAL_EMPTY; + } else { + value = invokeJavaOptionalOf(bindingSelection.getBinding().getProvider()); + } + } + + @Override + protected Object doProvision(InternalContext context, Dependency dependency) { + return value; + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.providerDependencies(); + } + } + + /** Provides the binding for T, conditionally installed by calling setBinding/setDefault. */ + private static final class RealDirectTypeProvider<T> + extends RealOptionalBinderProviderWithDependencies<T, T> { + private Key<? extends T> targetKey; + + private Object targetSource; + + private InternalFactory<? extends T> targetFactory; + + RealDirectTypeProvider(BindingSelection<T> bindingSelection) { + super(bindingSelection); + } + + @Override + void doInitialize() { + BindingImpl<T> targetBinding = bindingSelection.getBinding(); + // we only install this factory if they call setBinding()/setDefault() so we know that + // targetBinding will be non-null. + this.targetKey = targetBinding.getKey(); + this.targetSource = targetBinding.getSource(); + this.targetFactory = targetBinding.getInternalFactory(); + } + + @Override + protected T doProvision(InternalContext context, Dependency<?> dependency) + throws InternalProvisionException { + // This is what linked bindings do (see FactoryProxy), and we are pretty similar. + context.pushState(targetKey, targetSource); + + try { + return targetFactory.get(context, dependency, true); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(targetKey); + } finally { + context.popState(); + + } + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.dependencies; + } + } + + /** Provides the binding for Optional<Provider<T>>. */ + private static final class RealOptionalProviderProvider<T> + extends RealOptionalBinderProviderWithDependencies<T, Optional<Provider<T>>> { + private Optional<Provider<T>> value; + + RealOptionalProviderProvider(BindingSelection<T> bindingSelection) { + super(bindingSelection); + } + + @Override + void doInitialize() { + if (bindingSelection.getBinding() == null) { + value = Optional.absent(); + } else { + value = Optional.of(bindingSelection.getBinding().getProvider()); + } + } + + @Override + protected Optional<Provider<T>> doProvision(InternalContext context, Dependency<?> dependency) { + return value; + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.providerDependencies(); + } + } + + /** Provides the binding for Optional<T>. */ + private static final class RealOptionalKeyProvider<T> + extends RealOptionalBinderProviderWithDependencies<T, Optional<T>> + implements ProviderWithExtensionVisitor<Optional<T>>, OptionalBinderBinding<Optional<T>> { + + private final Key<Optional<T>> optionalKey; + + // These are assigned to non-null values during initialization if and only if we have a binding + // to delegate to. + private Dependency<?> targetDependency; + private InternalFactory<? extends T> delegate; + + RealOptionalKeyProvider(BindingSelection<T> bindingSelection, Key<Optional<T>> optionalKey) { + super(bindingSelection); + this.optionalKey = optionalKey; + } + + @Override + void doInitialize() { + if (bindingSelection.getBinding() != null) { + delegate = bindingSelection.getBinding().getInternalFactory(); + targetDependency = bindingSelection.getDependency(); + } + } + + @Override + protected Optional<T> doProvision(InternalContext context, Dependency<?> currentDependency) + throws InternalProvisionException { + InternalFactory<? extends T> local = delegate; + if (local == null) { + return Optional.absent(); + } + Dependency<?> localDependency = targetDependency; + T result; + Dependency previous = context.pushDependency(localDependency, getSource()); + + try { + // currentDependency is Optional<? super T>, so we really just need to set the target + // dependency to ? super T, but we are currently setting it to T. We could hypothetically + // make it easier for our delegate to generate proxies by modifying the dependency, but that + // would also require us to rewrite the key on each call. So for now we don't do it. + result = local.get(context, localDependency, false); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localDependency); + } finally { + context.popStateAndSetDependency(previous); + + } + return Optional.fromNullable(result); + } + + @Override + public Set<Dependency<?>> getDependencies() { + return bindingSelection.dependencies(); + } + + @SuppressWarnings("unchecked") + @Override + public <B, R> R acceptExtensionVisitor( + BindingTargetVisitor<B, R> visitor, ProviderInstanceBinding<? extends B> binding) { + if (visitor instanceof MultibindingsTargetVisitor) { + return ((MultibindingsTargetVisitor<Optional<T>, R>) visitor).visit(this); + } else { + return visitor.visit(binding); + } + } + + @Override + public Key<Optional<T>> getKey() { + return optionalKey; + } + + @Override + public Binding<?> getActualBinding() { + return bindingSelection.getActualBinding(); + } + + @Override + public Binding<?> getDefaultBinding() { + return bindingSelection.getDefaultBinding(); + } + + @Override + public boolean containsElement(Element element) { + return bindingSelection.containsElement(element); + } + } + + /** + * A helper object that implements the core logic for deciding what the implementation of the + * binding will be. + * + * <p>This also implements the main OptionalBinderBinding logic. + */ + private static final class BindingSelection<T> { + private static final ImmutableSet<Dependency<?>> MODULE_DEPENDENCIES = + ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class))); + + /*@Nullable */ BindingImpl<T> actualBinding; + /*@Nullable */ BindingImpl<T> defaultBinding; + /*@Nullable */ BindingImpl<T> binding; + private boolean initialized; + private final Key<T> key; + + // Until the injector initializes us, we don't know what our dependencies are, + // so initialize to the whole Injector (like Multibinder, and MapBinder indirectly). + private ImmutableSet<Dependency<?>> dependencies = MODULE_DEPENDENCIES; + private ImmutableSet<Dependency<?>> providerDependencies = MODULE_DEPENDENCIES; + + /** lazily allocated, by {@link #getBindingName}. */ + private String bindingName; + + /** lazily allocated, by {@link #getKeyForDefaultBinding}. */ + private Key<T> defaultBindingKey; + + /** lazily allocated, by {@link #getKeyForActualBinding}. */ + private Key<T> actualBindingKey; + + BindingSelection(Key<T> key) { + this.key = key; + } + + void checkNotInitialized() { + checkConfiguration(!initialized, "already initialized"); + } + + void initialize(InjectorImpl injector) { + // Every one of our providers will call this method, so only execute the logic once. + if (initialized) { + return; + } + + actualBinding = injector.getExistingBinding(getKeyForActualBinding()); + defaultBinding = injector.getExistingBinding(getKeyForDefaultBinding()); + // We should never create Jit bindings, but we can use them if some other binding created it. + BindingImpl<T> userBinding = injector.getExistingBinding(key); + if (actualBinding != null) { + // TODO(sameb): Consider exposing an option that will allow + // ACTUAL to fallback to DEFAULT if ACTUAL's provider returns null. + // Right now, an ACTUAL binding can convert from present -> absent + // if it's bound to a provider that returns null. + binding = actualBinding; + } else if (defaultBinding != null) { + binding = defaultBinding; + } else if (userBinding != null) { + // If neither the actual or default is set, then we fallback + // to the value bound to the type itself and consider that the + // "actual binding" for the SPI. + binding = userBinding; + actualBinding = userBinding; + } + if (binding != null) { + dependencies = ImmutableSet.<Dependency<?>>of(Dependency.get(binding.getKey())); + providerDependencies = + ImmutableSet.<Dependency<?>>of(Dependency.get(providerOf(binding.getKey()))); + } else { + dependencies = ImmutableSet.of(); + providerDependencies = ImmutableSet.of(); + } + initialized = true; + } + + Key<T> getKeyForDefaultBinding() { + if (defaultBindingKey == null) { + defaultBindingKey = Key.get(key.getTypeLiteral(), new DefaultImpl(getBindingName())); + } + return defaultBindingKey; + } + + Key<T> getKeyForActualBinding() { + if (actualBindingKey == null) { + actualBindingKey = Key.get(key.getTypeLiteral(), new ActualImpl(getBindingName())); + } + return actualBindingKey; + } + + Key<T> getDirectKey() { + return key; + } + + private String getBindingName() { + // Lazily allocated, most instantiations will never need this because they are deduped during + // module installation. + if (bindingName == null) { + bindingName = Annotations.nameOf(key); + } + return bindingName; + } + + BindingImpl<T> getBinding() { + return binding; + } + + // Provide default implementations for most of the OptionalBinderBinding interface + BindingImpl<T> getDefaultBinding() { + return defaultBinding; + } + + BindingImpl<T> getActualBinding() { + return actualBinding; + } + + ImmutableSet<Dependency<?>> providerDependencies() { + return providerDependencies; + } + + ImmutableSet<Dependency<?>> dependencies() { + return dependencies; + } + + /** + * Returns the Dependency for the target binding, throws NoSuchElementException if no target + * exists. + * + * <p>Calls to this method should typically be guarded by checking if {@link #getBinding()} + * returns {@code null}. + */ + Dependency<?> getDependency() { + return Iterables.getOnlyElement(dependencies); + } + + /** Implementation of {@link OptionalBinderBinding#containsElement}. */ + boolean containsElement(Element element) { + // All of our bindings are ProviderInstanceBindings whose providers extend + // RealOptionalBinderProviderWithDependencies and have 'this' as its binding selection. + if (element instanceof ProviderInstanceBinding) { + javax.inject.Provider<?> providerInstance = + ((ProviderInstanceBinding<?>) element).getUserSuppliedProvider(); + if (providerInstance instanceof RealOptionalBinderProviderWithDependencies) { + return ((RealOptionalBinderProviderWithDependencies<?, ?>) providerInstance) + .bindingSelection.equals(this); + } + } + if (element instanceof Binding) { + Key<?> elementKey = ((Binding) element).getKey(); + // if it isn't one of the things we bound directly it might be an actual or default key + return elementKey.equals(getKeyForActualBinding()) + || elementKey.equals(getKeyForDefaultBinding()); + } + return false; // cannot match; + } + + @Override + public boolean equals(Object o) { + return o instanceof BindingSelection && ((BindingSelection) o).key.equals(key); + } + + @Override + public int hashCode() { + return key.hashCode(); + } + } + + @Override + public boolean equals(Object o) { + return o instanceof RealOptionalBinder + && ((RealOptionalBinder<?>) o).bindingSelection.equals(bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + + /** A base class for ProviderWithDependencies that need equality based on a specific object. */ + private abstract static class RealOptionalBinderProviderWithDependencies<T, P> + extends InternalProviderInstanceBindingImpl.Factory<P> { + protected final BindingSelection<T> bindingSelection; + + RealOptionalBinderProviderWithDependencies(BindingSelection<T> bindingSelection) { + // We need delayed initialization so we can detect jit bindings created by other bindings + // while not also creating jit bindings ourselves. This ensures we only pick up user bindings + // if the binding would have existed in the injector statically. + super(InitializationTiming.DELAYED); + this.bindingSelection = bindingSelection; + } + + @Override + final void initialize(InjectorImpl injector, Errors errors) throws ErrorsException { + bindingSelection.initialize(injector); + doInitialize(); + } + + /** + * Initialize the factory. BindingSelection is guaranteed to be initialized at this point and + * this will be called prior to any provisioning. + */ + abstract void doInitialize(); + + @Override + public boolean equals(Object obj) { + return obj != null + && this.getClass() == obj.getClass() + && bindingSelection.equals( + ((RealOptionalBinderProviderWithDependencies<?, ?>) obj).bindingSelection); + } + + @Override + public int hashCode() { + return bindingSelection.hashCode(); + } + } + + static class DefaultImpl extends BaseAnnotation implements Default { + public DefaultImpl(String value) { + super(Default.class, value); + } + } + + static class ActualImpl extends BaseAnnotation implements Actual { + public ActualImpl(String value) { + super(Actual.class, value); + } + } + + abstract static class BaseAnnotation implements Serializable, Annotation { + + private final String value; + private final Class<? extends Annotation> clazz; + + BaseAnnotation(Class<? extends Annotation> clazz, String value) { + this.clazz = checkNotNull(clazz, "clazz"); + this.value = checkNotNull(value, "value"); + } + + public String value() { + return this.value; + } + + @Override + public int hashCode() { + // This is specified in java.lang.Annotation. + return (127 * "value".hashCode()) ^ value.hashCode(); + } + + @Override + public boolean equals(Object o) { + // We check against each annotation type instead of BaseAnnotation + // so that we can compare against generated annotation implementations. + if (o instanceof Actual && clazz == Actual.class) { + Actual other = (Actual) o; + return value.equals(other.value()); + } else if (o instanceof Default && clazz == Default.class) { + Default other = (Default) o; + return value.equals(other.value()); + } + return false; + } + + @Override + public String toString() { + return "@" + clazz.getName() + (value.isEmpty() ? "" : "(value=" + value + ")"); + } + + @Override + public Class<? extends Annotation> annotationType() { + return clazz; + } + + private static final long serialVersionUID = 0; + } +} diff --git a/core/src/com/google/inject/internal/ScopeBindingProcessor.java b/core/src/com/google/inject/internal/ScopeBindingProcessor.java index 3e68b30a..83d7f8a0 100644 --- a/core/src/com/google/inject/internal/ScopeBindingProcessor.java +++ b/core/src/com/google/inject/internal/ScopeBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Scope; import com.google.inject.spi.ScopeBinding; - import java.lang.annotation.Annotation; /** @@ -35,9 +34,11 @@ final class ScopeBindingProcessor extends AbstractProcessor { super(errors); } - @Override public Boolean visit(ScopeBinding command) { + @Override + public Boolean visit(ScopeBinding command) { Scope scope = checkNotNull(command.getScope(), "scope"); - Class<? extends Annotation> annotationType = checkNotNull(command.getAnnotationType(), "annotation type"); + Class<? extends Annotation> annotationType = + checkNotNull(command.getAnnotationType(), "annotation type"); if (!Annotations.isScopeAnnotation(annotationType)) { errors.missingScopeAnnotation(annotationType); @@ -60,4 +61,4 @@ final class ScopeBindingProcessor extends AbstractProcessor { return true; } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/internal/Scoping.java b/core/src/com/google/inject/internal/Scoping.java index 334aaef4..53b72c0e 100644 --- a/core/src/com/google/inject/internal/Scoping.java +++ b/core/src/com/google/inject/internal/Scoping.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,7 +26,6 @@ import com.google.inject.Stage; import com.google.inject.binder.ScopedBindingBuilder; import com.google.inject.spi.BindingScopingVisitor; import com.google.inject.spi.ScopeBinding; - import java.lang.annotation.Annotation; /** @@ -41,98 +40,148 @@ public abstract class Scoping { * No scoping annotation has been applied. Note that this is different from {@code * in(Scopes.NO_SCOPE)}, where the 'NO_SCOPE' has been explicitly applied. */ - public static final Scoping UNSCOPED = new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { - return visitor.visitNoScoping(); - } - - @Override public Scope getScopeInstance() { - return Scopes.NO_SCOPE; - } - - @Override public String toString() { - return Scopes.NO_SCOPE.toString(); - } - - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { - // do nothing - } - }; - - public static final Scoping SINGLETON_ANNOTATION = new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { - return visitor.visitScopeAnnotation(Singleton.class); - } - - @Override public Class<? extends Annotation> getScopeAnnotation() { - return Singleton.class; - } - - @Override public String toString() { - return Singleton.class.getName(); - } - - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { - scopedBindingBuilder.in(Singleton.class); - } - }; - - public static final Scoping SINGLETON_INSTANCE = new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { - return visitor.visitScope(Scopes.SINGLETON); - } - - @Override public Scope getScopeInstance() { - return Scopes.SINGLETON; - } + public static final Scoping UNSCOPED = + new Scoping() { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + return visitor.visitNoScoping(); + } + + @Override + public Scope getScopeInstance() { + return Scopes.NO_SCOPE; + } + + @Override + public String toString() { + return Scopes.NO_SCOPE.toString(); + } + + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + // do nothing + } + }; - @Override public String toString() { - return Scopes.SINGLETON.toString(); - } - - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { - scopedBindingBuilder.in(Scopes.SINGLETON); - } - }; - - public static final Scoping EAGER_SINGLETON = new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { - return visitor.visitEagerSingleton(); - } - - @Override public Scope getScopeInstance() { - return Scopes.SINGLETON; - } - - @Override public String toString() { - return "eager singleton"; - } - - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { - scopedBindingBuilder.asEagerSingleton(); - } - }; + /** + * No scoping annotation has been applied explicitly. Note that this is is the same as {@code + * in(Scopes.NO_SCOPE)}. + */ + private static final Scoping EXPLICITLY_UNSCOPED = + new Scoping() { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + return visitor.visitNoScoping(); + } + + @Override + public Scope getScopeInstance() { + return Scopes.NO_SCOPE; + } + + @Override + public String toString() { + return Scopes.NO_SCOPE.toString(); + } + + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + scopedBindingBuilder.in(Scopes.NO_SCOPE); + } + }; + + public static final Scoping SINGLETON_ANNOTATION = + new Scoping() { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + return visitor.visitScopeAnnotation(Singleton.class); + } + + @Override + public Class<? extends Annotation> getScopeAnnotation() { + return Singleton.class; + } + + @Override + public String toString() { + return Singleton.class.getName(); + } + + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + scopedBindingBuilder.in(Singleton.class); + } + }; + + public static final Scoping SINGLETON_INSTANCE = + new Scoping() { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + return visitor.visitScope(Scopes.SINGLETON); + } + + @Override + public Scope getScopeInstance() { + return Scopes.SINGLETON; + } + + @Override + public String toString() { + return Scopes.SINGLETON.toString(); + } + + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + scopedBindingBuilder.in(Scopes.SINGLETON); + } + }; + + public static final Scoping EAGER_SINGLETON = + new Scoping() { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + return visitor.visitEagerSingleton(); + } + + @Override + public Scope getScopeInstance() { + return Scopes.SINGLETON; + } + + @Override + public String toString() { + return "eager singleton"; + } + + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + scopedBindingBuilder.asEagerSingleton(); + } + }; public static Scoping forAnnotation(final Class<? extends Annotation> scopingAnnotation) { - if (scopingAnnotation == Singleton.class - || scopingAnnotation == javax.inject.Singleton.class) { + if (scopingAnnotation == Singleton.class || scopingAnnotation == javax.inject.Singleton.class) { return SINGLETON_ANNOTATION; } return new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { return visitor.visitScopeAnnotation(scopingAnnotation); } - @Override public Class<? extends Annotation> getScopeAnnotation() { + @Override + public Class<? extends Annotation> getScopeAnnotation() { return scopingAnnotation; } - @Override public String toString() { + @Override + public String toString() { return scopingAnnotation.getName(); } - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { scopedBindingBuilder.in(scopingAnnotation); } }; @@ -141,22 +190,28 @@ public abstract class Scoping { public static Scoping forInstance(final Scope scope) { if (scope == Scopes.SINGLETON) { return SINGLETON_INSTANCE; + } else if (scope == Scopes.NO_SCOPE) { + return EXPLICITLY_UNSCOPED; } return new Scoping() { - @Override public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { + @Override + public <V> V acceptVisitor(BindingScopingVisitor<V> visitor) { return visitor.visitScope(scope); } - @Override public Scope getScopeInstance() { + @Override + public Scope getScopeInstance() { return scope; } - @Override public String toString() { + @Override + public String toString() { return scope.toString(); } - @Override public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { + @Override + public void applyTo(ScopedBindingBuilder scopedBindingBuilder) { scopedBindingBuilder.in(scope); } }; @@ -178,9 +233,7 @@ public abstract class Scoping { return getScopeInstance() == Scopes.NO_SCOPE; } - /** - * Returns true if this scope is a singleton that should be loaded eagerly in {@code stage}. - */ + /** Returns true if this scope is a singleton that should be loaded eagerly in {@code stage}. */ public boolean isEagerSingleton(Stage stage) { if (this == EAGER_SINGLETON) { return true; @@ -193,31 +246,27 @@ public abstract class Scoping { return false; } - /** - * Returns the scope instance, or {@code null} if that isn't known for this instance. - */ + /** Returns the scope instance, or {@code null} if that isn't known for this instance. */ public Scope getScopeInstance() { return null; } - /** - * Returns the scope annotation, or {@code null} if that isn't known for this instance. - */ + /** Returns the scope annotation, or {@code null} if that isn't known for this instance. */ public Class<? extends Annotation> getScopeAnnotation() { return null; } - + @Override public boolean equals(Object obj) { - if(obj instanceof Scoping) { - Scoping o = (Scoping)obj; + if (obj instanceof Scoping) { + Scoping o = (Scoping) obj; return Objects.equal(getScopeAnnotation(), o.getScopeAnnotation()) - && Objects.equal(getScopeInstance(), o.getScopeInstance()); + && Objects.equal(getScopeInstance(), o.getScopeInstance()); } else { return false; } } - + @Override public int hashCode() { return Objects.hashCode(getScopeAnnotation(), getScopeInstance()); @@ -230,8 +279,12 @@ public abstract class Scoping { private Scoping() {} /** Scopes an internal factory. */ - static <T> InternalFactory<? extends T> scope(Key<T> key, InjectorImpl injector, - InternalFactory<? extends T> creator, Object source, Scoping scoping) { + static <T> InternalFactory<? extends T> scope( + Key<T> key, + InjectorImpl injector, + InternalFactory<? extends T> creator, + Object source, + Scoping scoping) { if (scoping.isNoScope()) { return creator; @@ -239,8 +292,11 @@ public abstract class Scoping { Scope scope = scoping.getScopeInstance(); - Provider<T> scoped - = scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator)); + // NOTE: SingletonScope relies on the fact that we are passing a + // ProviderToInternalFactoryAdapter here. If you change the type make sure to update + // SingletonScope as well. + Provider<T> scoped = + scope.scope(key, new ProviderToInternalFactoryAdapter<T>(injector, creator)); return new InternalFactoryToProviderAdapter<T>(scoped, source); } diff --git a/core/src/com/google/inject/internal/SingleFieldInjector.java b/core/src/com/google/inject/internal/SingleFieldInjector.java index 52be1f45..5319d450 100644 --- a/core/src/com/google/inject/internal/SingleFieldInjector.java +++ b/core/src/com/google/inject/internal/SingleFieldInjector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +19,9 @@ package com.google.inject.internal; import com.google.inject.internal.InjectorImpl.JitLimitation; import com.google.inject.spi.Dependency; import com.google.inject.spi.InjectionPoint; - import java.lang.reflect.Field; -/** - * Sets an injectable field. - */ +/** Sets an injectable field. */ final class SingleFieldInjector implements SingleMemberInjector { final Field field; final InjectionPoint injectionPoint; @@ -42,23 +39,24 @@ final class SingleFieldInjector implements SingleMemberInjector { binding = injector.getBindingOrThrow(dependency.getKey(), errors, JitLimitation.NO_JIT); } + @Override public InjectionPoint getInjectionPoint() { return injectionPoint; } - public void inject(Errors errors, InternalContext context, Object o) { - errors = errors.withSource(dependency); - + @Override + public void inject(InternalContext context, Object o) throws InternalProvisionException { Dependency previous = context.pushDependency(dependency, binding.getSource()); + try { - Object value = binding.getInternalFactory().get(errors, context, dependency, false); + Object value = binding.getInternalFactory().get(context, dependency, false); field.set(o, value); - } catch (ErrorsException e) { - errors.withSource(injectionPoint).merge(e.getErrors()); + } catch (InternalProvisionException e) { + throw e.addSource(dependency); } catch (IllegalAccessException e) { throw new AssertionError(e); // a security manager is blocking us, we're hosed } finally { - context.popStateAndSetDependency(previous); - } + context.popStateAndSetDependency(previous); + } } } diff --git a/core/src/com/google/inject/internal/SingleMemberInjector.java b/core/src/com/google/inject/internal/SingleMemberInjector.java index fea5733f..f20a5e52 100644 --- a/core/src/com/google/inject/internal/SingleMemberInjector.java +++ b/core/src/com/google/inject/internal/SingleMemberInjector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,10 +18,9 @@ package com.google.inject.internal; import com.google.inject.spi.InjectionPoint; -/** - * Injects a field or method of a given object. - */ +/** Injects a field or method of a given object. */ interface SingleMemberInjector { - void inject(Errors errors, InternalContext context, Object o); + void inject(InternalContext context, Object o) throws InternalProvisionException; + InjectionPoint getInjectionPoint(); } diff --git a/core/src/com/google/inject/internal/SingleMethodInjector.java b/core/src/com/google/inject/internal/SingleMethodInjector.java index 8bc8a34e..9cf7d934 100644 --- a/core/src/com/google/inject/internal/SingleMethodInjector.java +++ b/core/src/com/google/inject/internal/SingleMethodInjector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,17 +16,13 @@ package com.google.inject.internal; -import com.google.inject.internal.BytecodeGen.Visibility; import com.google.inject.internal.InjectorImpl.MethodInvoker; import com.google.inject.spi.InjectionPoint; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -/** - * Invokes an injectable method. - */ +/** Invokes an injectable method. */ final class SingleMethodInjector implements SingleMemberInjector { private final MethodInvoker methodInvoker; private final SingleParameterInjector<?>[] parameterInjectors; @@ -42,31 +38,33 @@ final class SingleMethodInjector implements SingleMemberInjector { private MethodInvoker createMethodInvoker(final Method method) { - // We can't use FastMethod if the method is private. - int modifiers = method.getModifiers(); - if (!Modifier.isPrivate(modifiers) && !Modifier.isProtected(modifiers)) { - /*if[AOP]*/ - try { - final net.sf.cglib.reflect.FastMethod fastMethod - = BytecodeGen.newFastClass(method.getDeclaringClass(), Visibility.forMember(method)) - .getMethod(method); + /*if[AOP]*/ + try { + final net.sf.cglib.reflect.FastClass fastClass = BytecodeGen.newFastClassForMember(method); + if (fastClass != null) { + final int index = fastClass.getMethod(method).getIndex(); - return new MethodInvoker() { - public Object invoke(Object target, Object... parameters) - throws IllegalAccessException, InvocationTargetException { - return fastMethod.invoke(target, parameters); - } - }; - } catch (net.sf.cglib.core.CodeGenerationException e) {/* fall-through */} - /*end[AOP]*/ + return new MethodInvoker() { + @Override + public Object invoke(Object target, Object... parameters) + throws IllegalAccessException, InvocationTargetException { + return fastClass.invoke(index, target, parameters); + } + }; + } + } catch (net.sf.cglib.core.CodeGenerationException e) { + /* fall-through */ } + /*end[AOP]*/ - if (!Modifier.isPublic(modifiers) || - !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { + int modifiers = method.getModifiers(); + if (!Modifier.isPublic(modifiers) + || !Modifier.isPublic(method.getDeclaringClass().getModifiers())) { method.setAccessible(true); } return new MethodInvoker() { + @Override public Object invoke(Object target, Object... parameters) throws IllegalAccessException, InvocationTargetException { return method.invoke(target, parameters); @@ -74,28 +72,22 @@ final class SingleMethodInjector implements SingleMemberInjector { }; } + @Override public InjectionPoint getInjectionPoint() { return injectionPoint; } - public void inject(Errors errors, InternalContext context, Object o) { - Object[] parameters; - try { - parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); - return; - } + @Override + public void inject(InternalContext context, Object o) throws InternalProvisionException { + Object[] parameters = SingleParameterInjector.getAll(context, parameterInjectors); try { methodInvoker.invoke(o, parameters); } catch (IllegalAccessException e) { throw new AssertionError(e); // a security manager is blocking us, we're hosed } catch (InvocationTargetException userException) { - Throwable cause = userException.getCause() != null - ? userException.getCause() - : userException; - errors.withSource(injectionPoint).errorInjectingMethod(cause); + Throwable cause = userException.getCause() != null ? userException.getCause() : userException; + throw InternalProvisionException.errorInjectingMethod(cause).addSource(injectionPoint); } } } diff --git a/core/src/com/google/inject/internal/SingleParameterInjector.java b/core/src/com/google/inject/internal/SingleParameterInjector.java index 708b8b09..3e36ed72 100644 --- a/core/src/com/google/inject/internal/SingleParameterInjector.java +++ b/core/src/com/google/inject/internal/SingleParameterInjector.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,54 +18,52 @@ package com.google.inject.internal; import com.google.inject.spi.Dependency; -/** - * Resolves a single parameter, to be used in a constructor or method invocation. - */ +/** Resolves a single parameter, to be used in a constructor or method invocation. */ final class SingleParameterInjector<T> { - private static final Object[] NO_ARGUMENTS = {}; + private static final Object[] NO_ARGUMENTS = {}; private final Dependency<T> dependency; - private final BindingImpl<? extends T> binding; + + private final Object source; + + private final InternalFactory<? extends T> factory; SingleParameterInjector(Dependency<T> dependency, BindingImpl<? extends T> binding) { this.dependency = dependency; - this.binding = binding; + this.source = binding.getSource(); + this.factory = binding.getInternalFactory(); } - private T inject(Errors errors, InternalContext context) throws ErrorsException { - Dependency previous = context.pushDependency(dependency, binding.getSource()); + T inject(InternalContext context) throws InternalProvisionException { + Dependency<T> localDependency = dependency; + Dependency previous = context.pushDependency(localDependency, source); + try { - return binding.getInternalFactory().get(errors.withSource(dependency), context, dependency, false); - } finally { - context.popStateAndSetDependency(previous); + return factory.get(context, localDependency, false); + } catch (InternalProvisionException ipe) { + throw ipe.addSource(localDependency); + } finally { + context.popStateAndSetDependency(previous); + } } - /** - * Returns an array of parameter values. - */ - static Object[] getAll(Errors errors, InternalContext context, - SingleParameterInjector<?>[] parameterInjectors) throws ErrorsException { + // TODO(lukes): inline into callers to decrease stack depth + + /** Returns an array of parameter values. */ + static Object[] getAll(InternalContext context, SingleParameterInjector<?>[] parameterInjectors) + throws InternalProvisionException { if (parameterInjectors == null) { return NO_ARGUMENTS; } - int numErrorsBefore = errors.size(); - int size = parameterInjectors.length; Object[] parameters = new Object[size]; - // optimization: use manual for/each to save allocating an iterator here + // optimization: use manual for/each to save allocating an iterator here for (int i = 0; i < size; i++) { - SingleParameterInjector<?> parameterInjector = parameterInjectors[i]; - try { - parameters[i] = parameterInjector.inject(errors, context); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); - } + parameters[i] = parameterInjectors[i].inject(context); } - - errors.throwIfNewErrors(numErrorsBefore); return parameters; } } diff --git a/core/src/com/google/inject/internal/SingletonScope.java b/core/src/com/google/inject/internal/SingletonScope.java index fe6287aa..c07ccb7e 100644 --- a/core/src/com/google/inject/internal/SingletonScope.java +++ b/core/src/com/google/inject/internal/SingletonScope.java @@ -2,10 +2,8 @@ package com.google.inject.internal; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.Iterables; import com.google.common.collect.ListMultimap; -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Provider; @@ -15,58 +13,43 @@ import com.google.inject.Scopes; import com.google.inject.Singleton; import com.google.inject.internal.CycleDetectingLock.CycleDetectingLockFactory; import com.google.inject.spi.Dependency; -import com.google.inject.spi.DependencyAndSource; import com.google.inject.spi.Message; - -import java.util.Collections; +import java.util.Formatter; import java.util.List; -import java.util.Map; /** * One instance per {@link Injector}. Also see {@code @}{@link Singleton}. * - * Introduction from the author: - * Implementation of this class seems unreasonably complicated at the first sight. - * I fully agree with you, that the beast below is very complex - * and it's hard to reason on how does it work or not. - * Still I want to assure you that hundreds(?) of hours were thrown - * into making this code simple, while still maintaining Singleton contract. + * <p>Introduction from the author: Implementation of this class seems unreasonably complicated at + * the first sight. I fully agree with you, that the beast below is very complex and it's hard to + * reason on how does it work or not. Still I want to assure you that hundreds(?) of hours were + * thrown into making this code simple, while still maintaining Singleton contract. * - * Anyway, why is it so complex? Singleton scope does not seem to be that unique. - * 1) Guice has never truly expected to be used in multi threading environment - * with many Injectors working alongside each other. There is almost no - * code with Guice that propagates state between threads. And Singleton - * scope is The exception. - * 2) Guice supports circular dependencies and thus manages proxy objects. - * There is no interface that allows user defined Scopes to create proxies, - * it is expected to be done by Guice. Singleton scope needs to be - * able to detect circular dependencies spanning several threads, - * therefore Singleton scope needs to be able to create these proxies. - * 3) To make things worse, Guice has a very tricky definition for a binding - * resolution when Injectors are in in a parent/child relationship. - * And Scope does not have access to this information by design, - * the only real action that Scope can do is to call or not to call a creator. - * 4) There is no readily available code in Guice that can detect a potential - * deadlock, and no code for handling dependency cycles spanning several threads. - * This is significantly harder as all the dependencies in a thread at runtime - * can be represented with a list, where in a multi threaded environment - * we have more complex dependency trees. - * 5) Guice has a pretty strong contract regarding Garbage Collection, - * which often prevents us from linking objects directly. - * So simple domain specific code can not be written and intermediary - * id objects need to be managed. - * 6) Guice is relatively fast and we should not make things worse. - * We're trying our best to optimize synchronization for speed and memory. - * Happy path should be almost as fast as in a single threaded solution - * and should not take much more memory. - * 7) Error message generation in Guice was not meant to be used like this and to work around - * its APIs we need a lot of code. Additional complexity comes from inherent data races - * as message is only generated when failure occurs on proxy object generation. - * Things get ugly pretty fast. + * <p>Anyway, why is it so complex? Singleton scope does not seem to be that unique. 1) Guice has + * never truly expected to be used in multi threading environment with many Injectors working + * alongside each other. There is almost no code with Guice that propagates state between threads. + * And Singleton scope is The exception. 2) Guice supports circular dependencies and thus manages + * proxy objects. There is no interface that allows user defined Scopes to create proxies, it is + * expected to be done by Guice. Singleton scope needs to be able to detect circular dependencies + * spanning several threads, therefore Singleton scope needs to be able to create these proxies. 3) + * To make things worse, Guice has a very tricky definition for a binding resolution when Injectors + * are in in a parent/child relationship. And Scope does not have access to this information by + * design, the only real action that Scope can do is to call or not to call a creator. 4) There is + * no readily available code in Guice that can detect a potential deadlock, and no code for handling + * dependency cycles spanning several threads. This is significantly harder as all the dependencies + * in a thread at runtime can be represented with a list, where in a multi threaded environment we + * have more complex dependency trees. 5) Guice has a pretty strong contract regarding Garbage + * Collection, which often prevents us from linking objects directly. So simple domain specific code + * can not be written and intermediary id objects need to be managed. 6) Guice is relatively fast + * and we should not make things worse. We're trying our best to optimize synchronization for speed + * and memory. Happy path should be almost as fast as in a single threaded solution and should not + * take much more memory. 7) Error message generation in Guice was not meant to be used like this + * and to work around its APIs we need a lot of code. Additional complexity comes from inherent data + * races as message is only generated when failure occurs on proxy object generation. Things get + * ugly pretty fast. * * @see #scope(Key, Provider) * @see CycleDetectingLock - * * @author timofeyb (Timothy Basanov) */ public class SingletonScope implements Scope { @@ -78,36 +61,34 @@ public class SingletonScope implements Scope { * Allows us to detect when circular proxies are necessary. It's only used during singleton * instance initialization, after initialization direct access through volatile field is used. * - * NB: Factory uses {@link Key}s as a user locks ids, different injectors can - * share them. Cycles are detected properly as cycle detection does not rely on user locks ids, - * but error message generated could be less than ideal. - * - * TODO(user): we may use one factory per injector tree for optimization reasons + * <p>NB: Factory uses {@link Key}s as a user locks ids, different injectors can share them. + * Cycles are detected properly as cycle detection does not rely on user locks ids, but error + * message generated could be less than ideal. */ + // TODO(user): we may use one factory per injector tree for optimization reasons private static final CycleDetectingLockFactory<Key<?>> cycleDetectingLockFactory = new CycleDetectingLockFactory<Key<?>>(); /** - * Provides singleton scope with the following properties: - * - creates no more than one instance per Key as a creator is used no more than once, - * - result is cached and returned quickly on subsequent calls, - * - exception in a creator is not treated as instance creation and is not cached, - * - creates singletons in parallel whenever possible, - * - waits for dependent singletons to be created even across threads and when dependencies - * are shared as long as no circular dependencies are detected, - * - returns circular proxy only when circular dependencies are detected, - * - aside from that, blocking synchronization is only used for proxy creation and initialization, + * Provides singleton scope with the following properties: - creates no more than one instance per + * Key as a creator is used no more than once, - result is cached and returned quickly on + * subsequent calls, - exception in a creator is not treated as instance creation and is not + * cached, - creates singletons in parallel whenever possible, - waits for dependent singletons to + * be created even across threads and when dependencies are shared as long as no circular + * dependencies are detected, - returns circular proxy only when circular dependencies are + * detected, - aside from that, blocking synchronization is only used for proxy creation and + * initialization, + * * @see CycleDetectingLockFactory */ + @Override public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) { /** - * Locking strategy: - * - volatile instance: double-checked locking for quick exit when scope is initialized, - * - constructionContext: manipulations with proxies list or instance initialization - * - creationLock: singleton instance creation, - * -- allows to guarantee only one instance per singleton, - * -- special type of a lock, that prevents potential deadlocks, - * -- guards constructionContext for all operations except proxy creation + * Locking strategy: - volatile instance: double-checked locking for quick exit when scope is + * initialized, - constructionContext: manipulations with proxies list or instance + * initialization - creationLock: singleton instance creation, -- allows to guarantee only one + * instance per singleton, -- special type of a lock, that prevents potential deadlocks, -- + * guards constructionContext for all operations except proxy creation */ return new Provider<T>() { /** @@ -120,21 +101,43 @@ public class SingletonScope implements Scope { * Circular proxies are used when potential deadlocks are detected. Guarded by itself. * ConstructionContext is not thread-safe, so each call should be synchronized. */ - final ConstructionContext<T> constructionContext = new ConstructionContext<T>(); + final ConstructionContext<T> constructionContext = new ConstructionContext<>(); /** For each binding there is a separate lock that we hold during object creation. */ final CycleDetectingLock<Key<?>> creationLock = cycleDetectingLockFactory.create(key); + /** + * The singleton provider needs a reference back to the injector, in order to get ahold of + * InternalContext during instantiation. + */ + final /* @Nullable */ InjectorImpl injector; + + { + // If we are getting called by Scoping + if (creator instanceof ProviderToInternalFactoryAdapter) { + injector = ((ProviderToInternalFactoryAdapter) creator).getInjector(); + } else { + injector = null; + } + } + @SuppressWarnings("DoubleCheckedLocking") + @Override public T get() { // cache volatile variable for the usual case of already initialized object final Object initialInstance = instance; if (initialInstance == null) { // instance is not initialized yet + // first, store the current InternalContext in a map, so that if there is a circular + // dependency error, we can use the InternalContext objects to create a complete + // error message. + // Handle injector being null, which can happen when users call Scoping.scope themselves + final InternalContext context = injector == null ? null : injector.getLocalContext(); // acquire lock for current binding to initialize an instance - final ListMultimap<Long, Key<?>> locksCycle = + final ListMultimap<Thread, Key<?>> locksCycle = creationLock.lockOrDetectPotentialLocksCycle(); + if (locksCycle.isEmpty()) { // this thread now owns creation of an instance try { @@ -147,7 +150,7 @@ public class SingletonScope implements Scope { // scope called recursively can initialize instance as a side effect if (instance == null) { - // instance is still not initialized, se we can proceed + // instance is still not initialized, so we can proceed // don't remember proxies created by Guice on circular dependency // detection within the same thread; they are not real instances to cache @@ -162,7 +165,8 @@ public class SingletonScope implements Scope { } } else { // safety assert in case instance was initialized - Preconditions.checkState(instance == providedNotNull, + Preconditions.checkState( + instance == providedNotNull, "Singleton is called recursively returning different results"); } } @@ -178,50 +182,45 @@ public class SingletonScope implements Scope { creationLock.unlock(); } } else { + if (context == null) { + throw new ProvisionException( + ImmutableList.of(createCycleDependenciesMessage(locksCycle, null))); + } // potential deadlock detected, creation lock is not taken by this thread synchronized (constructionContext) { // guarantee thread-safety for instance and proxies initialization if (instance == null) { - // InjectorImpl.callInContext() sets this context when scope is called from Guice - Map<Thread, InternalContext> globalInternalContext = - InjectorImpl.getGlobalInternalContext(); - InternalContext internalContext = globalInternalContext.get(Thread.currentThread()); - // creating a proxy to satisfy circular dependency across several threads - Dependency<?> dependency = Preconditions.checkNotNull( - internalContext.getDependency(), - "globalInternalContext.get(currentThread()).getDependency()"); + Dependency<?> dependency = + Preconditions.checkNotNull( + context.getDependency(), "internalContext.getDependency()"); Class<?> rawType = dependency.getKey().getTypeLiteral().getRawType(); try { @SuppressWarnings("unchecked") - T proxy = (T) constructionContext.createProxy( - new Errors(), internalContext.getInjectorOptions(), rawType); + T proxy = + (T) constructionContext.createProxy(context.getInjectorOptions(), rawType); return proxy; - } catch (ErrorsException e) { + } catch (InternalProvisionException e) { // best effort to create a rich error message - List<Message> exceptionErrorMessages = e.getErrors().getMessages(); - // we expect an error thrown - Preconditions.checkState(exceptionErrorMessages.size() == 1); - // explicitly copy the map to guarantee iteration correctness - // it's ok to have a data race with other threads that are locked - Message cycleDependenciesMessage = createCycleDependenciesMessage( - ImmutableMap.copyOf(globalInternalContext), - locksCycle, - exceptionErrorMessages.get(0)); + Message proxyCreationError = Iterables.getOnlyElement(e.getErrors()); + Message cycleDependenciesMessage = + createCycleDependenciesMessage(locksCycle, proxyCreationError); // adding stack trace generated by us in addition to a standard one - throw new ProvisionException(ImmutableList.of( - cycleDependenciesMessage, exceptionErrorMessages.get(0))); + throw new ProvisionException( + ImmutableList.of(cycleDependenciesMessage, proxyCreationError)); } } } } + // at this point we're sure that singleton was initialized, // reread volatile variable to catch all corner cases // caching volatile variable to minimize number of reads performed final Object initializedInstance = instance; - Preconditions.checkState(initializedInstance != null, + Preconditions.checkState( + initializedInstance != null, "Internal error: Singleton is not initialized contrary to our expectations"); @SuppressWarnings("unchecked") T initializedTypedInstance = (T) initializedInstance; @@ -235,99 +234,45 @@ public class SingletonScope implements Scope { } /** - * Helper method to create beautiful and rich error descriptions. Best effort and slow. - * Tries its best to provide dependency information from injectors currently available - * in a global internal context. + * Helper method to create beautiful and rich error descriptions. Best effort and slow. Tries + * its best to provide dependency information from injectors currently available in a global + * internal context. + * + * <p>The main thing being done is creating a list of Dependencies involved into lock cycle + * across all the threads involved. This is a structure we're creating: * - * <p>The main thing being done is creating a list of Dependencies involved into - * lock cycle across all the threads involved. This is a structure we're creating: * <pre> * { Current Thread, C.class, B.class, Other Thread, B.class, C.class, Current Thread } * To be inserted in the beginning by Guice: { A.class, B.class, C.class } * </pre> - * When we're calling Guice to create A and it fails in the deadlock while trying to - * create C, which is being created by another thread, which waits for B. List would - * be reversed before printing it to the end user. + * + * When we're calling Guice to create A and it fails in the deadlock while trying to create C, + * which is being created by another thread, which waits for B. List would be reversed before + * printing it to the end user. */ private Message createCycleDependenciesMessage( - Map<Thread, InternalContext> globalInternalContext, - ListMultimap<Long, Key<?>> locksCycle, - Message proxyCreationError) { + ListMultimap<Thread, Key<?>> locksCycle, /* @Nullable */ Message proxyCreationError) { // this is the main thing that we'll show in an error message, // current thread is populate by Guice - List<Object> sourcesCycle = Lists.newArrayList(); - sourcesCycle.add(Thread.currentThread()); - // temp map to speed up look ups - Map<Long, Thread> threadById = Maps.newHashMap(); - for (Thread thread : globalInternalContext.keySet()) { - threadById.put(thread.getId(), thread); + StringBuilder sb = new StringBuilder(); + Formatter fmt = new Formatter(sb); + fmt.format("Encountered circular dependency spanning several threads."); + if (proxyCreationError != null) { + fmt.format(" %s", proxyCreationError.getMessage()); } - for (long lockedThreadId : locksCycle.keySet()) { - Thread lockedThread = threadById.get(lockedThreadId); - List<Key<?>> lockedKeys = Collections.unmodifiableList(locksCycle.get(lockedThreadId)); - if (lockedThread == null) { - // thread in a lock cycle is already terminated - continue; - } - List<DependencyAndSource> dependencyChain = null; - boolean allLockedKeysAreFoundInDependencies = false; - // thread in a cycle is still present - InternalContext lockedThreadInternalContext = globalInternalContext.get(lockedThread); - if (lockedThreadInternalContext != null) { - dependencyChain = lockedThreadInternalContext.getDependencyChain(); - - // check that all of the keys are still present in dependency chain in order - List<Key<?>> lockedKeysToFind = Lists.newLinkedList(lockedKeys); - // check stack trace of the thread - for (DependencyAndSource d : dependencyChain) { - Dependency<?> dependency = d.getDependency(); - if (dependency == null) { - continue; - } - if (dependency.getKey().equals(lockedKeysToFind.get(0))) { - lockedKeysToFind.remove(0); - if (lockedKeysToFind.isEmpty()) { - // everything is found! - allLockedKeysAreFoundInDependencies = true; - break; - } - } - } + fmt.format("%n"); + for (Thread lockedThread : locksCycle.keySet()) { + List<Key<?>> lockedKeys = locksCycle.get(lockedThread); + fmt.format("%s is holding locks the following singletons in the cycle:%n", lockedThread); + for (Key<?> lockedKey : lockedKeys) { + fmt.format("%s%n", Errors.convert(lockedKey)); } - if (allLockedKeysAreFoundInDependencies) { - // all keys are present in a dependency chain of a thread's last injector, - // highly likely that we just have discovered a dependency - // chain that is part of a lock cycle starting with the first lock owned - Key<?> firstLockedKey = lockedKeys.get(0); - boolean firstLockedKeyFound = false; - for (DependencyAndSource d : dependencyChain) { - Dependency<?> dependency = d.getDependency(); - if (dependency == null) { - continue; - } - if (firstLockedKeyFound) { - sourcesCycle.add(dependency); - sourcesCycle.add(d.getBindingSource()); - } else if (dependency.getKey().equals(firstLockedKey)) { - firstLockedKeyFound = true; - // for the very first one found we don't care why, so no dependency is added - sourcesCycle.add(d.getBindingSource()); - } - } - } else { - // something went wrong and not all keys are present in a state of an injector - // that was used last for a current thread. - // let's add all keys we're aware of, still better than nothing - sourcesCycle.addAll(lockedKeys); + for (StackTraceElement traceElement : lockedThread.getStackTrace()) { + fmt.format("\tat %s%n", traceElement); } - // mentions that a tread is a part of a cycle - sourcesCycle.add(lockedThread); } - return new Message( - sourcesCycle, - String.format("Encountered circular dependency spanning several threads. %s", - proxyCreationError.getMessage()), - null); + fmt.close(); + return new Message(Thread.currentThread(), sb.toString()); } @Override @@ -337,7 +282,8 @@ public class SingletonScope implements Scope { }; } - @Override public String toString() { + @Override + public String toString() { return "Scopes.SINGLETON"; } } diff --git a/core/src/com/google/inject/internal/State.java b/core/src/com/google/inject/internal/State.java index 32c2da61..e49d2691 100644 --- a/core/src/com/google/inject/internal/State.java +++ b/core/src/com/google/inject/internal/State.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,13 +23,11 @@ import com.google.inject.Binding; import com.google.inject.Key; import com.google.inject.Scope; import com.google.inject.TypeLiteral; -import com.google.inject.spi.ModuleAnnotatedMethodScanner; import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; import com.google.inject.spi.ProvisionListenerBinding; import com.google.inject.spi.ScopeBinding; import com.google.inject.spi.TypeConverterBinding; import com.google.inject.spi.TypeListenerBinding; - import java.lang.annotation.Annotation; import java.util.List; import java.util.Map; @@ -43,101 +41,124 @@ import java.util.Set; */ interface State { - static final State NONE = new State() { - public State parent() { - throw new UnsupportedOperationException(); - } - - public <T> BindingImpl<T> getExplicitBinding(Key<T> key) { - return null; - } - - public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() { - throw new UnsupportedOperationException(); - } - - public void putBinding(Key<?> key, BindingImpl<?> binding) { - throw new UnsupportedOperationException(); - } - - public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) { - return null; - } - - public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) { - throw new UnsupportedOperationException(); - } - - public void addConverter(TypeConverterBinding typeConverterBinding) { - throw new UnsupportedOperationException(); - } - - public TypeConverterBinding getConverter(String stringValue, TypeLiteral<?> type, Errors errors, - Object source) { - throw new UnsupportedOperationException(); - } - - public Iterable<TypeConverterBinding> getConvertersThisLevel() { - return ImmutableSet.of(); - } - - /*if[AOP]*/ - public void addMethodAspect(MethodAspect methodAspect) { - throw new UnsupportedOperationException(); - } - - public ImmutableList<MethodAspect> getMethodAspects() { - return ImmutableList.of(); - } - /*end[AOP]*/ - - public void addTypeListener(TypeListenerBinding typeListenerBinding) { - throw new UnsupportedOperationException(); - } - - public List<TypeListenerBinding> getTypeListenerBindings() { - return ImmutableList.of(); - } - - public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) { - throw new UnsupportedOperationException(); - } - - public List<ProvisionListenerBinding> getProvisionListenerBindings() { - return ImmutableList.of(); - } - - public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) { - throw new UnsupportedOperationException(); - } - - public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() { - return ImmutableList.of(); - } - - public void blacklist(Key<?> key, State state, Object source) { - } - - public boolean isBlacklisted(Key<?> key) { - return true; - } - - public Set<Object> getSourcesForBlacklistedKey(Key<?> key) { - throw new UnsupportedOperationException(); - } - - public Object lock() { - throw new UnsupportedOperationException(); - } - - public Object singletonCreationLock() { - throw new UnsupportedOperationException(); - } - - public Map<Class<? extends Annotation>, Scope> getScopes() { - return ImmutableMap.of(); - } - }; + static final State NONE = + new State() { + @Override + public State parent() { + throw new UnsupportedOperationException(); + } + + @Override + public <T> BindingImpl<T> getExplicitBinding(Key<T> key) { + return null; + } + + @Override + public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() { + throw new UnsupportedOperationException(); + } + + @Override + public void putBinding(Key<?> key, BindingImpl<?> binding) { + throw new UnsupportedOperationException(); + } + + @Override + public ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation) { + return null; + } + + @Override + public void putScopeBinding( + Class<? extends Annotation> annotationType, ScopeBinding scope) { + throw new UnsupportedOperationException(); + } + + @Override + public void addConverter(TypeConverterBinding typeConverterBinding) { + throw new UnsupportedOperationException(); + } + + @Override + public TypeConverterBinding getConverter( + String stringValue, TypeLiteral<?> type, Errors errors, Object source) { + throw new UnsupportedOperationException(); + } + + @Override + public Iterable<TypeConverterBinding> getConvertersThisLevel() { + return ImmutableSet.of(); + } + + /*if[AOP]*/ + @Override + public void addMethodAspect(MethodAspect methodAspect) { + throw new UnsupportedOperationException(); + } + + @Override + public ImmutableList<MethodAspect> getMethodAspects() { + return ImmutableList.of(); + } + /*end[AOP]*/ + + @Override + public void addTypeListener(TypeListenerBinding typeListenerBinding) { + throw new UnsupportedOperationException(); + } + + @Override + public List<TypeListenerBinding> getTypeListenerBindings() { + return ImmutableList.of(); + } + + @Override + public void addProvisionListener(ProvisionListenerBinding provisionListenerBinding) { + throw new UnsupportedOperationException(); + } + + @Override + public List<ProvisionListenerBinding> getProvisionListenerBindings() { + return ImmutableList.of(); + } + + @Override + public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) { + throw new UnsupportedOperationException(); + } + + @Override + public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() { + return ImmutableList.of(); + } + + @Override + public void blacklist(Key<?> key, State state, Object source) {} + + @Override + public boolean isBlacklisted(Key<?> key) { + return true; + } + + @Override + public Set<Object> getSourcesForBlacklistedKey(Key<?> key) { + throw new UnsupportedOperationException(); + } + + @Override + public Object lock() { + throw new UnsupportedOperationException(); + } + + public Object singletonCreationLock() { + throw new UnsupportedOperationException(); + } + + @Override + public Map<Class<? extends Annotation>, Scope> getScopes() { + return ImmutableMap.of(); + } + }; State parent(); @@ -148,7 +169,7 @@ interface State { Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel(); void putBinding(Key<?> key, BindingImpl<?> binding); - + ScopeBinding getScopeBinding(Class<? extends Annotation> scopingAnnotation); void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope); @@ -169,11 +190,11 @@ interface State { /*end[AOP]*/ void addTypeListener(TypeListenerBinding typeListenerBinding); - + List<TypeListenerBinding> getTypeListenerBindings(); - + void addProvisionListener(ProvisionListenerBinding provisionListenerBinding); - + List<ProvisionListenerBinding> getProvisionListenerBindings(); void addScanner(ModuleAnnotatedMethodScannerBinding scanner); @@ -192,7 +213,7 @@ interface State { * one of this injector's descendent's has bound the key. */ boolean isBlacklisted(Key<?> key); - + /** Returns the source of a blacklisted key. */ Set<Object> getSourcesForBlacklistedKey(Key<?> key); @@ -202,8 +223,6 @@ interface State { */ Object lock(); - /** - * Returns all the scope bindings at this level and parent levels. - */ + /** Returns all the scope bindings at this level and parent levels. */ Map<Class<? extends Annotation>, Scope> getScopes(); } diff --git a/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java b/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java index 7ab52ce5..34f2cd09 100644 --- a/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java +++ b/core/src/com/google/inject/internal/TypeConverterBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.inject.matcher.Matcher; import com.google.inject.matcher.Matchers; import com.google.inject.spi.TypeConverter; import com.google.inject.spi.TypeConverterBinding; - import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Type; @@ -51,79 +50,97 @@ final class TypeConverterBindingProcessor extends AbstractProcessor { convertToPrimitiveType(injector, float.class, Float.class); convertToPrimitiveType(injector, double.class, Double.class); - convertToClass(injector, Character.class, new TypeConverter() { - public Object convert(String value, TypeLiteral<?> toType) { - value = value.trim(); - if (value.length() != 1) { - throw new RuntimeException("Length != 1."); - } - return value.charAt(0); - } - - @Override public String toString() { - return "TypeConverter<Character>"; - } - }); - - convertToClasses(injector, Matchers.subclassesOf(Enum.class), new TypeConverter() { - @SuppressWarnings("unchecked") - public Object convert(String value, TypeLiteral<?> toType) { - return Enum.valueOf((Class) toType.getRawType(), value); - } - - @Override public String toString() { - return "TypeConverter<E extends Enum<E>>"; - } - }); - - internalConvertToTypes(injector, new AbstractMatcher<TypeLiteral<?>>() { - public boolean matches(TypeLiteral<?> typeLiteral) { - return typeLiteral.getRawType() == Class.class; - } - - @Override public String toString() { - return "Class<?>"; - } - }, - new TypeConverter() { - @SuppressWarnings("unchecked") - public Object convert(String value, TypeLiteral<?> toType) { - try { - return Class.forName(value); - } catch (ClassNotFoundException e) { - throw new RuntimeException(e.getMessage()); + convertToClass( + injector, + Character.class, + new TypeConverter() { + @Override + public Object convert(String value, TypeLiteral<?> toType) { + value = value.trim(); + if (value.length() != 1) { + throw new RuntimeException("Length != 1."); + } + return value.charAt(0); } - } - @Override public String toString() { - return "TypeConverter<Class<?>>"; - } - } - ); - } + @Override + public String toString() { + return "TypeConverter<Character>"; + } + }); + + convertToClasses( + injector, + Matchers.subclassesOf(Enum.class), + new TypeConverter() { + @Override + @SuppressWarnings("unchecked") + public Object convert(String value, TypeLiteral<?> toType) { + return Enum.valueOf((Class) toType.getRawType(), value); + } - private static <T> void convertToPrimitiveType(InjectorImpl injector, Class<T> primitiveType, - final Class<T> wrapperType) { - try { - final Method parser = wrapperType.getMethod( - "parse" + capitalize(primitiveType.getName()), String.class); - - TypeConverter typeConverter = new TypeConverter() { - @SuppressWarnings("unchecked") - public Object convert(String value, TypeLiteral<?> toType) { - try { - return parser.invoke(null, value); - } catch (IllegalAccessException e) { - throw new AssertionError(e); - } catch (InvocationTargetException e) { - throw new RuntimeException(e.getTargetException().getMessage()); + @Override + public String toString() { + return "TypeConverter<E extends Enum<E>>"; + } + }); + + internalConvertToTypes( + injector, + new AbstractMatcher<TypeLiteral<?>>() { + @Override + public boolean matches(TypeLiteral<?> typeLiteral) { + return typeLiteral.getRawType() == Class.class; + } + + @Override + public String toString() { + return "Class<?>"; + } + }, + new TypeConverter() { + @Override + @SuppressWarnings("unchecked") + public Object convert(String value, TypeLiteral<?> toType) { + try { + return Class.forName(value); + } catch (ClassNotFoundException e) { + throw new RuntimeException(e.getMessage()); + } } - } - @Override public String toString() { - return "TypeConverter<" + wrapperType.getSimpleName() + ">"; - } - }; + @Override + public String toString() { + return "TypeConverter<Class<?>>"; + } + }); + } + + private static <T> void convertToPrimitiveType( + InjectorImpl injector, Class<T> primitiveType, final Class<T> wrapperType) { + try { + final Method parser = + wrapperType.getMethod("parse" + capitalize(primitiveType.getName()), String.class); + + TypeConverter typeConverter = + new TypeConverter() { + @Override + @SuppressWarnings("unchecked") + public Object convert(String value, TypeLiteral<?> toType) { + try { + return parser.invoke(null, value); + } catch (IllegalAccessException e) { + throw new AssertionError(e); + } catch (InvocationTargetException e) { + throw new RuntimeException(e.getTargetException().getMessage()); + } + } + + @Override + public String toString() { + return "TypeConverter<" + wrapperType.getSimpleName() + ">"; + } + }; convertToClass(injector, wrapperType, typeConverter); } catch (NoSuchMethodException e) { @@ -131,51 +148,54 @@ final class TypeConverterBindingProcessor extends AbstractProcessor { } } - private static <T> void convertToClass(InjectorImpl injector, Class<T> type, - TypeConverter converter) { + private static <T> void convertToClass( + InjectorImpl injector, Class<T> type, TypeConverter converter) { convertToClasses(injector, Matchers.identicalTo(type), converter); } - private static void convertToClasses(InjectorImpl injector, - final Matcher<? super Class<?>> typeMatcher, TypeConverter converter) { - internalConvertToTypes(injector, new AbstractMatcher<TypeLiteral<?>>() { - public boolean matches(TypeLiteral<?> typeLiteral) { - Type type = typeLiteral.getType(); - if (!(type instanceof Class)) { - return false; - } - Class<?> clazz = (Class<?>) type; - return typeMatcher.matches(clazz); - } - - @Override public String toString() { - return typeMatcher.toString(); - } - }, converter); + private static void convertToClasses( + InjectorImpl injector, final Matcher<? super Class<?>> typeMatcher, TypeConverter converter) { + internalConvertToTypes( + injector, + new AbstractMatcher<TypeLiteral<?>>() { + @Override + public boolean matches(TypeLiteral<?> typeLiteral) { + Type type = typeLiteral.getType(); + if (!(type instanceof Class)) { + return false; + } + Class<?> clazz = (Class<?>) type; + return typeMatcher.matches(clazz); + } + + @Override + public String toString() { + return typeMatcher.toString(); + } + }, + converter); } - private static void internalConvertToTypes(InjectorImpl injector, - Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter converter) { + private static void internalConvertToTypes( + InjectorImpl injector, Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) { injector.state.addConverter( new TypeConverterBinding(SourceProvider.UNKNOWN_SOURCE, typeMatcher, converter)); } - @Override public Boolean visit(TypeConverterBinding command) { - injector.state.addConverter(new TypeConverterBinding( - command.getSource(), command.getTypeMatcher(), command.getTypeConverter())); + @Override + public Boolean visit(TypeConverterBinding command) { + injector.state.addConverter( + new TypeConverterBinding( + command.getSource(), command.getTypeMatcher(), command.getTypeConverter())); return true; } - + private static String capitalize(String s) { if (s.length() == 0) { return s; } char first = s.charAt(0); char capitalized = Character.toUpperCase(first); - return (first == capitalized) - ? s - : capitalized + s.substring(1); + return (first == capitalized) ? s : capitalized + s.substring(1); } - } diff --git a/core/src/com/google/inject/internal/UniqueAnnotations.java b/core/src/com/google/inject/internal/UniqueAnnotations.java index 924175e6..36b213d2 100644 --- a/core/src/com/google/inject/internal/UniqueAnnotations.java +++ b/core/src/com/google/inject/internal/UniqueAnnotations.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,21 +19,19 @@ package com.google.inject.internal; import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.google.inject.BindingAnnotation; - import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import java.util.concurrent.atomic.AtomicInteger; -/** - * @author jessewilson@google.com (Jesse Wilson) - */ +/** @author jessewilson@google.com (Jesse Wilson) */ public class UniqueAnnotations { private UniqueAnnotations() {} + private static final AtomicInteger nextUniqueValue = new AtomicInteger(1); /** - * Returns an annotation instance that is not equal to any other annotation - * instances, for use in creating distinct {@link com.google.inject.Key}s. + * Returns an annotation instance that is not equal to any other annotation instances, for use in + * creating distinct {@link com.google.inject.Key}s. */ public static Annotation create() { return create(nextUniqueValue.getAndIncrement()); @@ -41,30 +39,35 @@ public class UniqueAnnotations { static Annotation create(final int value) { return new Internal() { + @Override public int value() { return value; } + @Override public Class<? extends Annotation> annotationType() { return Internal.class; } - @Override public String toString() { + @Override + public String toString() { return "@" + Internal.class.getName() + "(value=" + value + ")"; } - @Override public boolean equals(Object o) { - return o instanceof Internal - && ((Internal) o).value() == value(); + @Override + public boolean equals(Object o) { + return o instanceof Internal && ((Internal) o).value() == value(); } - @Override public int hashCode() { + @Override + public int hashCode() { return (127 * "value".hashCode()) ^ value; } }; } - @Retention(RUNTIME) @BindingAnnotation + @Retention(RUNTIME) + @BindingAnnotation @interface Internal { int value(); } diff --git a/core/src/com/google/inject/internal/UntargettedBindingImpl.java b/core/src/com/google/inject/internal/UntargettedBindingImpl.java index a2d3365d..18f0d947 100644 --- a/core/src/com/google/inject/internal/UntargettedBindingImpl.java +++ b/core/src/com/google/inject/internal/UntargettedBindingImpl.java @@ -16,6 +16,7 @@ package com.google.inject.internal; +import com.google.common.base.MoreObjects; import com.google.common.base.Objects; import com.google.inject.Binder; import com.google.inject.Key; @@ -26,35 +27,46 @@ import com.google.inject.spi.UntargettedBinding; final class UntargettedBindingImpl<T> extends BindingImpl<T> implements UntargettedBinding<T> { UntargettedBindingImpl(InjectorImpl injector, Key<T> key, Object source) { - super(injector, key, source, new InternalFactory<T>() { - public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) { - throw new AssertionError(); - } - }, Scoping.UNSCOPED); + super( + injector, + key, + source, + new InternalFactory<T>() { + @Override + public T get(InternalContext context, Dependency<?> dependency, boolean linked) { + throw new AssertionError(); + } + }, + Scoping.UNSCOPED); } public UntargettedBindingImpl(Object source, Key<T> key, Scoping scoping) { super(source, key, scoping); } + @Override public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) { return visitor.visit(this); } + @Override public BindingImpl<T> withScoping(Scoping scoping) { return new UntargettedBindingImpl<T>(getSource(), getKey(), scoping); } + @Override public BindingImpl<T> withKey(Key<T> key) { return new UntargettedBindingImpl<T>(getSource(), key, getScoping()); } + @Override public void applyTo(Binder binder) { getScoping().applyTo(binder.withSource(getSource()).bind(getKey())); } - @Override public String toString() { - return Objects.toStringHelper(UntargettedBinding.class) + @Override + public String toString() { + return MoreObjects.toStringHelper(UntargettedBinding.class) .add("key", getKey()) .add("source", getSource()) .toString(); @@ -62,10 +74,9 @@ final class UntargettedBindingImpl<T> extends BindingImpl<T> implements Untarget @Override public boolean equals(Object obj) { - if(obj instanceof UntargettedBindingImpl) { - UntargettedBindingImpl<?> o = (UntargettedBindingImpl<?>)obj; - return getKey().equals(o.getKey()) - && getScoping().equals(o.getScoping()); + if (obj instanceof UntargettedBindingImpl) { + UntargettedBindingImpl<?> o = (UntargettedBindingImpl<?>) obj; + return getKey().equals(o.getKey()) && getScoping().equals(o.getScoping()); } else { return false; } diff --git a/core/src/com/google/inject/internal/UntargettedBindingProcessor.java b/core/src/com/google/inject/internal/UntargettedBindingProcessor.java index 8ca2ecc8..0e569957 100644 --- a/core/src/com/google/inject/internal/UntargettedBindingProcessor.java +++ b/core/src/com/google/inject/internal/UntargettedBindingProcessor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,45 +25,47 @@ import com.google.inject.spi.UntargettedBinding; * @author sameb@google.com (Sam Berlin) */ class UntargettedBindingProcessor extends AbstractBindingProcessor { - + UntargettedBindingProcessor(Errors errors, ProcessedBindingData bindingData) { super(errors, bindingData); } - + @Override public <T> Boolean visit(Binding<T> binding) { - return binding.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>)binding) { - public Boolean visit(UntargettedBinding<? extends T> untargetted) { - prepareBinding(); + return binding.acceptTargetVisitor( + new Processor<T, Boolean>((BindingImpl<T>) binding) { + @Override + public Boolean visit(UntargettedBinding<? extends T> untargetted) { + prepareBinding(); + + // Error: Missing implementation. + // Example: bind(Date.class).annotatedWith(Red.class); + // We can't assume abstract types aren't injectable. They may have an + // @ImplementedBy annotation or something. + if (key.getAnnotationType() != null) { + errors.missingImplementationWithHint(key, injector); + putBinding(invalidBinding(injector, key, source)); + return true; + } + + // This cast is safe after the preceeding check. + try { + BindingImpl<T> binding = + injector.createUninitializedBinding(key, scoping, source, errors, false); + scheduleInitialization(binding); + putBinding(binding); + } catch (ErrorsException e) { + errors.merge(e.getErrors()); + putBinding(invalidBinding(injector, key, source)); + } + + return true; + } - // Error: Missing implementation. - // Example: bind(Date.class).annotatedWith(Red.class); - // We can't assume abstract types aren't injectable. They may have an - // @ImplementedBy annotation or something. - if (key.getAnnotationType() != null) { - errors.missingImplementation(key); - putBinding(invalidBinding(injector, key, source)); - return true; - } - - // This cast is safe after the preceeding check. - try { - BindingImpl<T> binding = injector.createUninitializedBinding( - key, scoping, source, errors, false); - scheduleInitialization(binding); - putBinding(binding); - } catch (ErrorsException e) { - errors.merge(e.getErrors()); - putBinding(invalidBinding(injector, key, source)); - } - - return true; - } - - @Override - protected Boolean visitOther(Binding<? extends T> binding) { - return false; - } - }); + @Override + protected Boolean visitOther(Binding<? extends T> binding) { + return false; + } + }); } } diff --git a/core/src/com/google/inject/internal/WeakKeySet.java b/core/src/com/google/inject/internal/WeakKeySet.java index ca137df6..c0cf668c 100644 --- a/core/src/com/google/inject/internal/WeakKeySet.java +++ b/core/src/com/google/inject/internal/WeakKeySet.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,7 +29,6 @@ import com.google.common.collect.Multiset; import com.google.common.collect.Sets; import com.google.inject.Key; import com.google.inject.internal.util.SourceProvider; - import java.util.Map; import java.util.Set; @@ -52,18 +51,19 @@ final class WeakKeySet { * Tracks child injector lifetimes and evicts blacklisted keys/sources after the child injector is * garbage collected. */ - private final Cache<State, Set<KeyAndSource>> evictionCache = CacheBuilder.newBuilder() - .weakKeys() - .removalListener( - new RemovalListener<State, Set<KeyAndSource>>() { - @Override - public void onRemoval(RemovalNotification<State, Set<KeyAndSource>> notification) { - Preconditions.checkState(RemovalCause.COLLECTED.equals(notification.getCause())); - - cleanUpForCollectedState(notification.getValue()); - } - }) - .build(); + private final Cache<State, Set<KeyAndSource>> evictionCache = + CacheBuilder.newBuilder() + .weakKeys() + .removalListener( + new RemovalListener<State, Set<KeyAndSource>>() { + @Override + public void onRemoval(RemovalNotification<State, Set<KeyAndSource>> notification) { + Preconditions.checkState(RemovalCause.COLLECTED.equals(notification.getCause())); + + cleanUpForCollectedState(notification.getValue()); + } + }) + .build(); /** * There may be multiple child injectors blacklisting a certain key so only remove the source @@ -150,8 +150,7 @@ final class WeakKeySet { } KeyAndSource other = (KeyAndSource) obj; - return Objects.equal(key, other.key) - && Objects.equal(source, other.source); + return Objects.equal(key, other.key) && Objects.equal(source, other.source); } } } diff --git a/core/src/com/google/inject/internal/package-info.java b/core/src/com/google/inject/internal/package-info.java index 4116f110..8e88e927 100644 --- a/core/src/com/google/inject/internal/package-info.java +++ b/core/src/com/google/inject/internal/package-info.java @@ -14,7 +14,5 @@ * limitations under the License. */ -/** - * <i>Guice</i> (sounds like like "juice") - */ +/** <i>Guice</i> (sounds like "juice") */ package com.google.inject.internal; diff --git a/core/src/com/google/inject/internal/util/Classes.java b/core/src/com/google/inject/internal/util/Classes.java index 0badab12..47174606 100644 --- a/core/src/com/google/inject/internal/util/Classes.java +++ b/core/src/com/google/inject/internal/util/Classes.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2007 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,14 +24,11 @@ import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -/** - * Class utilities. - */ +/** Class utilities. */ public final class Classes { public static boolean isInnerClass(Class<?> clazz) { - return !Modifier.isStatic(clazz.getModifiers()) - && clazz.getEnclosingClass() != null; + return !Modifier.isStatic(clazz.getModifiers()) && clazz.getEnclosingClass() != null; } public static boolean isConcrete(Class<?> clazz) { @@ -40,12 +37,12 @@ public final class Classes { } /** - * Formats a member as concise string, such as {@code java.util.ArrayList.size}, - * {@code java.util.ArrayList<init>()} or {@code java.util.List.remove()}. + * Formats a member as concise string, such as {@code java.util.ArrayList.size}, {@code + * java.util.ArrayList<init>()} or {@code java.util.List.remove()}. */ public static String toString(Member member) { Class<? extends Member> memberType = Classes.memberType(member); - + if (memberType == Method.class) { return member.getDeclaringClass().getName() + "." + member.getName() + "()"; } else if (memberType == Field.class) { @@ -57,21 +54,19 @@ public final class Classes { } } - /** - * Returns {@code Field.class}, {@code Method.class} or {@code Constructor.class}. - */ + /** Returns {@code Field.class}, {@code Method.class} or {@code Constructor.class}. */ public static Class<? extends Member> memberType(Member member) { checkNotNull(member, "member"); - + if (member instanceof Field) { return Field.class; - + } else if (member instanceof Method) { return Method.class; - + } else if (member instanceof Constructor) { return Constructor.class; - + } else { throw new IllegalArgumentException( "Unsupported implementation class for Member, " + member.getClass()); diff --git a/core/src/com/google/inject/internal/util/LineNumbers.java b/core/src/com/google/inject/internal/util/LineNumbers.java index 57c98b92..0179e8a0 100644 --- a/core/src/com/google/inject/internal/util/LineNumbers.java +++ b/core/src/com/google/inject/internal/util/LineNumbers.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,15 +20,6 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.base.Preconditions; import com.google.common.collect.Maps; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Constructor; @@ -36,6 +27,13 @@ import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.util.Map; +import org.objectweb.asm.AnnotationVisitor; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.FieldVisitor; +import org.objectweb.asm.Label; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; /** * Looks up line numbers for classes and their members. @@ -62,7 +60,14 @@ final class LineNumbers { if (!type.isArray()) { InputStream in = type.getResourceAsStream("/" + type.getName().replace('.', '/') + ".class"); if (in != null) { - new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES); + try { + new ClassReader(in).accept(new LineNumberReader(), ClassReader.SKIP_FRAMES); + } finally { + try { + in.close(); + } catch (IOException ignored) { + } + } } } } @@ -82,11 +87,15 @@ final class LineNumbers { * @param member a field, constructor, or method belonging to the class used during construction * @return the wrapped line number, or null if not available * @throws IllegalArgumentException if the member does not belong to the class used during - * construction + * construction */ public Integer getLineNumber(Member member) { - Preconditions.checkArgument(type == member.getDeclaringClass(), - "Member %s belongs to %s, not %s", member, member.getDeclaringClass(), type); + Preconditions.checkArgument( + type == member.getDeclaringClass(), + "Member %s belongs to %s, not %s", + member, + member.getDeclaringClass(), + type); return lines.get(memberKey(member)); } @@ -108,7 +117,7 @@ final class LineNumbers { } else if (member instanceof Constructor) { StringBuilder sb = new StringBuilder().append("<init>("); for (Class param : ((Constructor) member).getParameterTypes()) { - sb.append(org.objectweb.asm.Type.getDescriptor(param)); + sb.append(org.objectweb.asm.Type.getDescriptor(param)); } return sb.append(")V").toString(); @@ -120,7 +129,7 @@ final class LineNumbers { /*if[NO_AOP] return "<NO_MEMBER_KEY>"; end[NO_AOP]*/ - } + } private class LineNumberReader extends ClassVisitor { @@ -129,16 +138,23 @@ final class LineNumbers { private String name; LineNumberReader() { - super(Opcodes.ASM5); + super(Opcodes.ASM6); } - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { + @Override + public void visit( + int version, + int access, + String name, + String signature, + String superName, + String[] interfaces) { this.name = name; } - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { + @Override + public MethodVisitor visitMethod( + int access, String name, String desc, String signature, String[] exceptions) { if ((access & Opcodes.ACC_PRIVATE) != 0) { return null; } @@ -147,6 +163,7 @@ final class LineNumbers { return new LineNumberMethodVisitor(); } + @Override public void visitSource(String source, String debug) { LineNumbers.this.source = source; } @@ -163,41 +180,47 @@ final class LineNumbers { } } - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { + @Override + public FieldVisitor visitField( + int access, String name, String desc, String signature, Object value) { return null; } + @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return new LineNumberAnnotationVisitor(); } - public AnnotationVisitor visitParameterAnnotation(int parameter, - String desc, boolean visible) { + public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { return new LineNumberAnnotationVisitor(); } class LineNumberMethodVisitor extends MethodVisitor { LineNumberMethodVisitor() { - super(Opcodes.ASM5); + super(Opcodes.ASM6); } + @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { return new LineNumberAnnotationVisitor(); } + @Override public AnnotationVisitor visitAnnotationDefault() { return new LineNumberAnnotationVisitor(); } - public void visitFieldInsn(int opcode, String owner, String name, - String desc) { - if (opcode == Opcodes.PUTFIELD && LineNumberReader.this.name.equals(owner) - && !lines.containsKey(name) && line != -1) { + @Override + public void visitFieldInsn(int opcode, String owner, String name, String desc) { + if (opcode == Opcodes.PUTFIELD + && LineNumberReader.this.name.equals(owner) + && !lines.containsKey(name) + && line != -1) { lines.put(name, line); } } + @Override public void visitLineNumber(int line, Label start) { LineNumberReader.this.visitLineNumber(line, start); } @@ -205,19 +228,21 @@ final class LineNumbers { class LineNumberAnnotationVisitor extends AnnotationVisitor { LineNumberAnnotationVisitor() { - super(Opcodes.ASM5); + super(Opcodes.ASM6); } + + @Override public AnnotationVisitor visitAnnotation(String name, String desc) { return this; } + + @Override public AnnotationVisitor visitArray(String name) { return this; } - public void visitLocalVariable(String name, String desc, String signature, - Label start, Label end, int index) { - } + public void visitLocalVariable( + String name, String desc, String signature, Label start, Label end, int index) {} } - } } diff --git a/core/src/com/google/inject/internal/util/SourceProvider.java b/core/src/com/google/inject/internal/util/SourceProvider.java index 9d4b9f9a..bcb84de5 100644 --- a/core/src/com/google/inject/internal/util/SourceProvider.java +++ b/core/src/com/google/inject/internal/util/SourceProvider.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +19,11 @@ package com.google.inject.internal.util; import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; - import java.util.List; /** * Provides access to the calling line of code. - * + * * @author crazybob@google.com (Bob Lee) */ public final class SourceProvider { @@ -34,9 +33,9 @@ public final class SourceProvider { private final SourceProvider parent; private final ImmutableSet<String> classNamesToSkip; - - public static final SourceProvider DEFAULT_INSTANCE - = new SourceProvider(ImmutableSet.of(SourceProvider.class.getName())); + + public static final SourceProvider DEFAULT_INSTANCE = + new SourceProvider(ImmutableSet.of(SourceProvider.class.getName())); private SourceProvider(Iterable<String> classesToSkip) { this(null, classesToSkip); @@ -44,7 +43,7 @@ public final class SourceProvider { private SourceProvider(SourceProvider parent, Iterable<String> classesToSkip) { this.parent = parent; - + ImmutableSet.Builder<String> classNamesToSkipBuilder = ImmutableSet.builder(); for (String classToSkip : classesToSkip) { if (parent == null || !parent.shouldBeSkipped(classToSkip)) { @@ -64,7 +63,7 @@ public final class SourceProvider { return (parent != null && parent.shouldBeSkipped(className)) || classNamesToSkip.contains(className); } - + /** Returns the class names as Strings */ private static List<String> asStrings(Class... classes) { List<String> strings = Lists.newArrayList(); @@ -82,7 +81,7 @@ public final class SourceProvider { Preconditions.checkNotNull(stackTraceElements, "The stack trace elements cannot be null."); for (final StackTraceElement element : stackTraceElements) { String className = element.getClassName(); - + if (!shouldBeSkipped(className)) { return element; } @@ -90,9 +89,7 @@ public final class SourceProvider { throw new AssertionError(); } - /** - * Returns the non-skipped module class name. - */ + /** Returns the non-skipped module class name. */ public Object getFromClassNames(List<String> moduleClassNames) { Preconditions.checkNotNull(moduleClassNames, "The list of module class names cannot be null."); for (final String moduleClassName : moduleClassNames) { diff --git a/core/src/com/google/inject/internal/util/StackTraceElements.java b/core/src/com/google/inject/internal/util/StackTraceElements.java index 69f930f1..486855b9 100644 --- a/core/src/com/google/inject/internal/util/StackTraceElements.java +++ b/core/src/com/google/inject/internal/util/StackTraceElements.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,12 +19,11 @@ package com.google.inject.internal.util; import com.google.common.cache.CacheBuilder; import com.google.common.cache.CacheLoader; import com.google.common.cache.LoadingCache; -import com.google.common.collect.MapMaker; - import java.io.IOException; import java.lang.reflect.Constructor; import java.lang.reflect.Member; -import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; /** * Creates stack trace elements for members. @@ -34,25 +33,31 @@ import java.util.Map; public class StackTraceElements { private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0]; - private static final InMemoryStackTraceElement[] EMPTY_INMEMORY_STACK_TRACE = + private static final InMemoryStackTraceElement[] EMPTY_INMEMORY_STACK_TRACE = new InMemoryStackTraceElement[0]; /*if[AOP]*/ static final LoadingCache<Class<?>, LineNumbers> lineNumbersCache = - CacheBuilder.newBuilder().weakKeys().softValues().build( - new CacheLoader<Class<?>, LineNumbers>() { - public LineNumbers load(Class<?> key) { - try { - return new LineNumbers(key); - } - catch (IOException e) { - throw new RuntimeException(e); - } - } - }); + CacheBuilder.newBuilder() + .weakKeys() + .softValues() + .build( + new CacheLoader<Class<?>, LineNumbers>() { + @Override + public LineNumbers load(Class<?> key) { + try { + return new LineNumbers(key); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + }); /*end[AOP]*/ - private static Map<Object, Object> cache = new MapMaker().makeMap(); + private static final ConcurrentMap<InMemoryStackTraceElement, InMemoryStackTraceElement> + elementCache = new ConcurrentHashMap<>(); + private static final ConcurrentMap<String, String> stringCache = new ConcurrentHashMap<>(); + private static final String UNKNOWN_SOURCE = "Unknown Source"; public static Object forMember(Member member) { @@ -91,31 +96,28 @@ public class StackTraceElements { return new StackTraceElement(implementation.getName(), "class", fileName, lineNumber); } - - /** - * Clears the internal cache for {@link StackTraceElement StackTraceElements}. - */ + + /** Clears the internal cache for {@link StackTraceElement StackTraceElements}. */ public static void clearCache() { - cache.clear(); + elementCache.clear(); + stringCache.clear(); } - - /** - * Returns encoded in-memory version of {@link StackTraceElement StackTraceElements}. - */ + + /** Returns encoded in-memory version of {@link StackTraceElement StackTraceElements}. */ public static InMemoryStackTraceElement[] convertToInMemoryStackTraceElement( StackTraceElement[] stackTraceElements) { if (stackTraceElements.length == 0) { return EMPTY_INMEMORY_STACK_TRACE; } - InMemoryStackTraceElement[] inMemoryStackTraceElements = + InMemoryStackTraceElement[] inMemoryStackTraceElements = new InMemoryStackTraceElement[stackTraceElements.length]; for (int i = 0; i < stackTraceElements.length; i++) { - inMemoryStackTraceElements[i] = + inMemoryStackTraceElements[i] = weakIntern(new InMemoryStackTraceElement(stackTraceElements[i])); } return inMemoryStackTraceElements; } - + /** * Decodes in-memory stack trace elements to regular {@link StackTraceElement StackTraceElements}. */ @@ -124,45 +126,43 @@ public class StackTraceElements { if (inMemoryStackTraceElements.length == 0) { return EMPTY_STACK_TRACE; } - StackTraceElement[] stackTraceElements = + StackTraceElement[] stackTraceElements = new StackTraceElement[inMemoryStackTraceElements.length]; for (int i = 0; i < inMemoryStackTraceElements.length; i++) { String declaringClass = inMemoryStackTraceElements[i].getClassName(); String methodName = inMemoryStackTraceElements[i].getMethodName(); int lineNumber = inMemoryStackTraceElements[i].getLineNumber(); - stackTraceElements[i] = + stackTraceElements[i] = new StackTraceElement(declaringClass, methodName, UNKNOWN_SOURCE, lineNumber); } return stackTraceElements; } - + private static InMemoryStackTraceElement weakIntern( InMemoryStackTraceElement inMemoryStackTraceElement) { - InMemoryStackTraceElement cached = - (InMemoryStackTraceElement) cache.get(inMemoryStackTraceElement); + InMemoryStackTraceElement cached = elementCache.get(inMemoryStackTraceElement); if (cached != null) { return cached; } - inMemoryStackTraceElement = new InMemoryStackTraceElement( - weakIntern(inMemoryStackTraceElement.getClassName()), - weakIntern(inMemoryStackTraceElement.getMethodName()), - inMemoryStackTraceElement.getLineNumber()); - cache.put(inMemoryStackTraceElement, inMemoryStackTraceElement); + inMemoryStackTraceElement = + new InMemoryStackTraceElement( + weakIntern(inMemoryStackTraceElement.getClassName()), + weakIntern(inMemoryStackTraceElement.getMethodName()), + inMemoryStackTraceElement.getLineNumber()); + elementCache.put(inMemoryStackTraceElement, inMemoryStackTraceElement); return inMemoryStackTraceElement; } - + private static String weakIntern(String s) { - String cached = (String) cache.get(s); + String cached = stringCache.get(s); if (cached != null) { return cached; } - cache.put(s, s); - return s; + stringCache.put(s, s); + return s; } - - /** - * In-Memory version of {@link StackTraceElement} that does not store the file name. - */ + + /** In-Memory version of {@link StackTraceElement} that does not store the file name. */ public static class InMemoryStackTraceElement { private String declaringClass; private String methodName; @@ -181,11 +181,11 @@ public class StackTraceElements { String getClassName() { return declaringClass; } - + String getMethodName() { return methodName; } - + int getLineNumber() { return lineNumber; } @@ -199,8 +199,9 @@ public class StackTraceElements { return false; } InMemoryStackTraceElement e = (InMemoryStackTraceElement) obj; - return e.declaringClass.equals(declaringClass) && e.lineNumber == lineNumber && - methodName.equals(e.methodName); + return e.declaringClass.equals(declaringClass) + && e.lineNumber == lineNumber + && methodName.equals(e.methodName); } @Override @@ -209,7 +210,7 @@ public class StackTraceElements { result = 31 * result + lineNumber; return result; } - + @Override public String toString() { return declaringClass + "." + methodName + "(" + lineNumber + ")"; diff --git a/core/src/com/google/inject/internal/util/Stopwatch.java b/core/src/com/google/inject/internal/util/Stopwatch.java index 92c73fba..04953d44 100644 --- a/core/src/com/google/inject/internal/util/Stopwatch.java +++ b/core/src/com/google/inject/internal/util/Stopwatch.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,9 +28,7 @@ public final class Stopwatch { private long start = System.currentTimeMillis(); - /** - * Resets and returns elapsed time in milliseconds. - */ + /** Resets and returns elapsed time in milliseconds. */ public long reset() { long now = System.currentTimeMillis(); try { @@ -40,9 +38,7 @@ public final class Stopwatch { } } - /** - * Resets and logs elapsed time in milliseconds. - */ + /** Resets and logs elapsed time in milliseconds. */ public void resetAndLog(String label) { logger.fine(label + ": " + reset() + "ms"); } diff --git a/core/src/com/google/inject/matcher/AbstractMatcher.java b/core/src/com/google/inject/matcher/AbstractMatcher.java index 91ea2e67..08209fc3 100644 --- a/core/src/com/google/inject/matcher/AbstractMatcher.java +++ b/core/src/com/google/inject/matcher/AbstractMatcher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,10 +25,12 @@ import java.io.Serializable; */ public abstract class AbstractMatcher<T> implements Matcher<T> { + @Override public Matcher<T> and(final Matcher<? super T> other) { return new AndMatcher<T>(this, other); } + @Override public Matcher<T> or(Matcher<? super T> other) { return new OrMatcher<T>(this, other); } @@ -41,21 +43,25 @@ public abstract class AbstractMatcher<T> implements Matcher<T> { this.b = b; } + @Override public boolean matches(T t) { return a.matches(t) && b.matches(t); } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof AndMatcher && ((AndMatcher) other).a.equals(a) && ((AndMatcher) other).b.equals(b); } - @Override public int hashCode() { + @Override + public int hashCode() { return 41 * (a.hashCode() ^ b.hashCode()); } - @Override public String toString() { + @Override + public String toString() { return "and(" + a + ", " + b + ")"; } @@ -70,21 +76,25 @@ public abstract class AbstractMatcher<T> implements Matcher<T> { this.b = b; } + @Override public boolean matches(T t) { return a.matches(t) || b.matches(t); } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof OrMatcher && ((OrMatcher) other).a.equals(a) && ((OrMatcher) other).b.equals(b); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * (a.hashCode() ^ b.hashCode()); } - @Override public String toString() { + @Override + public String toString() { return "or(" + a + ", " + b + ")"; } diff --git a/core/src/com/google/inject/matcher/Matcher.java b/core/src/com/google/inject/matcher/Matcher.java index 681f1256..6eb81e88 100644 --- a/core/src/com/google/inject/matcher/Matcher.java +++ b/core/src/com/google/inject/matcher/Matcher.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,20 +23,18 @@ package com.google.inject.matcher; */ public interface Matcher<T> { - /** - * Returns {@code true} if this matches {@code t}, {@code false} otherwise. - */ + /** Returns {@code true} if this matches {@code t}, {@code false} otherwise. */ boolean matches(T t); /** - * Returns a new matcher which returns {@code true} if both this and the - * given matcher return {@code true}. + * Returns a new matcher which returns {@code true} if both this and the given matcher return + * {@code true}. */ Matcher<T> and(Matcher<? super T> other); /** - * Returns a new matcher which returns {@code true} if either this or the - * given matcher return {@code true}. + * Returns a new matcher which returns {@code true} if either this or the given matcher return + * {@code true}. */ Matcher<T> or(Matcher<? super T> other); } diff --git a/core/src/com/google/inject/matcher/Matchers.java b/core/src/com/google/inject/matcher/Matchers.java index 1bebcdb1..7aaf750e 100644 --- a/core/src/com/google/inject/matcher/Matchers.java +++ b/core/src/com/google/inject/matcher/Matchers.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,9 +34,7 @@ import java.lang.reflect.Method; public class Matchers { private Matchers() {} - /** - * Returns a matcher which matches any input. - */ + /** Returns a matcher which matches any input. */ public static Matcher<Object> any() { return ANY; } @@ -44,11 +42,13 @@ public class Matchers { private static final Matcher<Object> ANY = new Any(); private static class Any extends AbstractMatcher<Object> implements Serializable { + @Override public boolean matches(Object o) { return true; } - @Override public String toString() { + @Override + public String toString() { return "any()"; } @@ -59,9 +59,7 @@ public class Matchers { private static final long serialVersionUID = 0; } - /** - * Inverts the given matcher. - */ + /** Inverts the given matcher. */ public static <T> Matcher<T> not(final Matcher<? super T> p) { return new Not<T>(p); } @@ -73,37 +71,38 @@ public class Matchers { this.delegate = checkNotNull(delegate, "delegate"); } + @Override public boolean matches(T t) { return !delegate.matches(t); } - @Override public boolean equals(Object other) { - return other instanceof Not - && ((Not) other).delegate.equals(delegate); + @Override + public boolean equals(Object other) { + return other instanceof Not && ((Not) other).delegate.equals(delegate); } - @Override public int hashCode() { + @Override + public int hashCode() { return -delegate.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "not(" + delegate + ")"; } private static final long serialVersionUID = 0; } - private static void checkForRuntimeRetention( - Class<? extends Annotation> annotationType) { + private static void checkForRuntimeRetention(Class<? extends Annotation> annotationType) { Retention retention = annotationType.getAnnotation(Retention.class); - checkArgument(retention != null && retention.value() == RetentionPolicy.RUNTIME, - "Annotation %s is missing RUNTIME retention", annotationType.getSimpleName()); + checkArgument( + retention != null && retention.value() == RetentionPolicy.RUNTIME, + "Annotation %s is missing RUNTIME retention", + annotationType.getSimpleName()); } - /** - * Returns a matcher which matches elements (methods, classes, etc.) - * with a given annotation. - */ + /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */ public static Matcher<AnnotatedElement> annotatedWith( final Class<? extends Annotation> annotationType) { return new AnnotatedWithType(annotationType); @@ -118,32 +117,32 @@ public class Matchers { checkForRuntimeRetention(annotationType); } + @Override public boolean matches(AnnotatedElement element) { return element.isAnnotationPresent(annotationType); } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof AnnotatedWithType && ((AnnotatedWithType) other).annotationType.equals(annotationType); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * annotationType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "annotatedWith(" + annotationType.getSimpleName() + ".class)"; } private static final long serialVersionUID = 0; } - /** - * Returns a matcher which matches elements (methods, classes, etc.) - * with a given annotation. - */ - public static Matcher<AnnotatedElement> annotatedWith( - final Annotation annotation) { + /** Returns a matcher which matches elements (methods, classes, etc.) with a given annotation. */ + public static Matcher<AnnotatedElement> annotatedWith(final Annotation annotation) { return new AnnotatedWith(annotation); } @@ -156,127 +155,130 @@ public class Matchers { checkForRuntimeRetention(annotation.annotationType()); } + @Override public boolean matches(AnnotatedElement element) { Annotation fromElement = element.getAnnotation(annotation.annotationType()); return fromElement != null && annotation.equals(fromElement); } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof AnnotatedWith && ((AnnotatedWith) other).annotation.equals(annotation); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * annotation.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "annotatedWith(" + annotation + ")"; } private static final long serialVersionUID = 0; } - /** - * Returns a matcher which matches subclasses of the given type (as well as - * the given type). - */ + /** Returns a matcher which matches subclasses of the given type (as well as the given type). */ public static Matcher<Class> subclassesOf(final Class<?> superclass) { return new SubclassesOf(superclass); } - private static class SubclassesOf extends AbstractMatcher<Class> - implements Serializable { + private static class SubclassesOf extends AbstractMatcher<Class> implements Serializable { private final Class<?> superclass; public SubclassesOf(Class<?> superclass) { this.superclass = checkNotNull(superclass, "superclass"); } + @Override public boolean matches(Class subclass) { return superclass.isAssignableFrom(subclass); } - @Override public boolean equals(Object other) { - return other instanceof SubclassesOf - && ((SubclassesOf) other).superclass.equals(superclass); + @Override + public boolean equals(Object other) { + return other instanceof SubclassesOf && ((SubclassesOf) other).superclass.equals(superclass); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * superclass.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "subclassesOf(" + superclass.getSimpleName() + ".class)"; } private static final long serialVersionUID = 0; } - /** - * Returns a matcher which matches objects equal to the given object. - */ + /** Returns a matcher which matches objects equal to the given object. */ public static Matcher<Object> only(Object value) { return new Only(value); } - private static class Only extends AbstractMatcher<Object> - implements Serializable { + private static class Only extends AbstractMatcher<Object> implements Serializable { private final Object value; public Only(Object value) { this.value = checkNotNull(value, "value"); } + @Override public boolean matches(Object other) { return value.equals(other); } - @Override public boolean equals(Object other) { - return other instanceof Only - && ((Only) other).value.equals(value); + @Override + public boolean equals(Object other) { + return other instanceof Only && ((Only) other).value.equals(value); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * value.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "only(" + value + ")"; } private static final long serialVersionUID = 0; } - /** - * Returns a matcher which matches only the given object. - */ + /** Returns a matcher which matches only the given object. */ public static Matcher<Object> identicalTo(final Object value) { return new IdenticalTo(value); } - private static class IdenticalTo extends AbstractMatcher<Object> - implements Serializable { + private static class IdenticalTo extends AbstractMatcher<Object> implements Serializable { private final Object value; public IdenticalTo(Object value) { this.value = checkNotNull(value, "value"); } + @Override public boolean matches(Object other) { return value == other; } - @Override public boolean equals(Object other) { - return other instanceof IdenticalTo - && ((IdenticalTo) other).value == value; + @Override + public boolean equals(Object other) { + return other instanceof IdenticalTo && ((IdenticalTo) other).value == value; } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * System.identityHashCode(value); } - @Override public String toString() { + @Override + public String toString() { return "identicalTo(" + value + ")"; } @@ -300,20 +302,23 @@ public class Matchers { this.packageName = targetPackage.getName(); } + @Override public boolean matches(Class c) { return c.getPackage().equals(targetPackage); } - @Override public boolean equals(Object other) { - return other instanceof InPackage - && ((InPackage) other).targetPackage.equals(targetPackage); + @Override + public boolean equals(Object other) { + return other instanceof InPackage && ((InPackage) other).targetPackage.equals(targetPackage); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * targetPackage.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "inPackage(" + targetPackage.getName() + ")"; } @@ -325,9 +330,9 @@ public class Matchers { } /** - * Returns a matcher which matches classes in the given package and its subpackages. Unlike - * {@link #inPackage(Package) inPackage()}, this matches classes from any classloader. - * + * Returns a matcher which matches classes in the given package and its subpackages. Unlike {@link + * #inPackage(Package) inPackage()}, this matches classes from any classloader. + * * @since 2.0 */ public static Matcher<Class> inSubpackage(final String targetPackageName) { @@ -341,33 +346,34 @@ public class Matchers { this.targetPackageName = targetPackageName; } + @Override public boolean matches(Class c) { String classPackageName = c.getPackage().getName(); return classPackageName.equals(targetPackageName) || classPackageName.startsWith(targetPackageName + "."); } - @Override public boolean equals(Object other) { + @Override + public boolean equals(Object other) { return other instanceof InSubpackage && ((InSubpackage) other).targetPackageName.equals(targetPackageName); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * targetPackageName.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "inSubpackage(" + targetPackageName + ")"; } private static final long serialVersionUID = 0; } - /** - * Returns a matcher which matches methods with matching return types. - */ - public static Matcher<Method> returns( - final Matcher<? super Class<?>> returnType) { + /** Returns a matcher which matches methods with matching return types. */ + public static Matcher<Method> returns(final Matcher<? super Class<?>> returnType) { return new Returns(returnType); } @@ -378,20 +384,23 @@ public class Matchers { this.returnType = checkNotNull(returnType, "return type matcher"); } + @Override public boolean matches(Method m) { return returnType.matches(m.getReturnType()); } - @Override public boolean equals(Object other) { - return other instanceof Returns - && ((Returns) other).returnType.equals(returnType); + @Override + public boolean equals(Object other) { + return other instanceof Returns && ((Returns) other).returnType.equals(returnType); } - @Override public int hashCode() { + @Override + public int hashCode() { return 37 * returnType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return "returns(" + returnType + ")"; } diff --git a/core/src/com/google/inject/matcher/package-info.java b/core/src/com/google/inject/matcher/package-info.java index ced3238c..d37eed29 100644 --- a/core/src/com/google/inject/matcher/package-info.java +++ b/core/src/com/google/inject/matcher/package-info.java @@ -14,8 +14,5 @@ * limitations under the License. */ -/** - * Used for matching things. Primarily used to pick out methods to which to - * apply interceptors. - */ -package com.google.inject.matcher;
\ No newline at end of file +/** Used for matching things. Primarily used to pick out methods to which to apply interceptors. */ +package com.google.inject.matcher; diff --git a/core/src/com/google/inject/multibindings/ClassMapKey.java b/core/src/com/google/inject/multibindings/ClassMapKey.java new file mode 100644 index 00000000..19527c79 --- /dev/null +++ b/core/src/com/google/inject/multibindings/ClassMapKey.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Allows {@literal @}{@link ProvidesIntoMap} to specify a class map key. + * + * @since 4.0 + */ +@MapKey(unwrapValue = true) +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface ClassMapKey { + Class<?> value(); +} diff --git a/core/src/com/google/inject/multibindings/MapBinder.java b/core/src/com/google/inject/multibindings/MapBinder.java new file mode 100644 index 00000000..fbc506c7 --- /dev/null +++ b/core/src/com/google/inject/multibindings/MapBinder.java @@ -0,0 +1,214 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static com.google.inject.internal.RealMapBinder.newMapRealBinder; +import static com.google.inject.internal.RealMapBinder.newRealMapBinder; + +import com.google.inject.Binder; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.RealMapBinder; +import java.lang.annotation.Annotation; +import java.util.Map; + +/** + * An API to bind multiple map entries separately, only to later inject them as a complete map. + * MapBinder is intended for use in your application's module: + * + * <pre><code> + * public class SnacksModule extends AbstractModule { + * protected void configure() { + * MapBinder<String, Snack> mapbinder + * = MapBinder.newMapBinder(binder(), String.class, Snack.class); + * mapbinder.addBinding("twix").toInstance(new Twix()); + * mapbinder.addBinding("snickers").toProvider(SnickersProvider.class); + * mapbinder.addBinding("skittles").to(Skittles.class); + * } + * }</code></pre> + * + * <p>With this binding, a {@link Map}{@code <String, Snack>} can now be injected: + * + * <pre><code> + * class SnackMachine { + * {@literal @}Inject + * public SnackMachine(Map<String, Snack> snacks) { ... } + * }</code></pre> + * + * <p>In addition to binding {@code Map<K, V>}, a mapbinder will also bind {@code Map<K, + * Provider<V>>} for lazy value provision: + * + * <pre><code> + * class SnackMachine { + * {@literal @}Inject + * public SnackMachine(Map<String, Provider<Snack>> snackProviders) { ... } + * }</code></pre> + * + * <p>Contributing mapbindings from different modules is supported. For example, it is okay to have + * both {@code CandyModule} and {@code ChipsModule} both create their own {@code MapBinder<String, + * Snack>}, and to each contribute bindings to the snacks map. When that map is injected, it will + * contain entries from both modules. + * + * <p>The map's iteration order is consistent with the binding order. This is convenient when + * multiple elements are contributed by the same module because that module can order its bindings + * appropriately. Avoid relying on the iteration order of elements contributed by different modules, + * since there is no equivalent mechanism to order modules. + * + * <p>The map is unmodifiable. Elements can only be added to the map by configuring the MapBinder. + * Elements can never be removed from the map. + * + * <p>Values are resolved at map injection time. If a value is bound to a provider, that provider's + * get method will be called each time the map is injected (unless the binding is also scoped, or a + * map of providers is injected). + * + * <p>Annotations are used to create different maps of the same key/value type. Each distinct + * annotation gets its own independent map. + * + * <p><strong>Keys must be distinct.</strong> If the same key is bound more than once, map injection + * will fail. However, use {@link #permitDuplicates()} in order to allow duplicate keys; extra + * bindings to {@code Map<K, Set<V>>} and {@code Map<K, Set<Provider<V>>} will be added. + * + * <p><strong>Keys must be non-null.</strong> {@code addBinding(null)} will throw an unchecked + * exception. + * + * <p><strong>Values must be non-null to use map injection.</strong> If any value is null, map + * injection will fail (although injecting a map of providers will not). + * + * @author dpb@google.com (David P. Baker) + */ +public class MapBinder<K, V> { + // This class is non-final due to users mocking this in tests :( + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with no binding annotation. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType) { + return new MapBinder<K, V>( + newMapRealBinder(binder.skipSources(MapBinder.class), keyType, valueType)); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with no binding annotation. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, Class<K> keyType, Class<V> valueType) { + return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType)); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotation}. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, TypeLiteral<K> keyType, TypeLiteral<V> valueType, Annotation annotation) { + return new MapBinder<K, V>( + newRealMapBinder(binder.skipSources(MapBinder.class), keyType, valueType, annotation)); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotation}. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, Class<K> keyType, Class<V> valueType, Annotation annotation) { + return newMapBinder(binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotation); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotationType}. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, + TypeLiteral<K> keyType, + TypeLiteral<V> valueType, + Class<? extends Annotation> annotationType) { + return new MapBinder<K, V>( + newRealMapBinder(binder.skipSources(MapBinder.class), keyType, valueType, annotationType)); + } + + /** + * Returns a new mapbinder that collects entries of {@code keyType}/{@code valueType} in a {@link + * Map} that is itself bound with {@code annotationType}. + */ + public static <K, V> MapBinder<K, V> newMapBinder( + Binder binder, + Class<K> keyType, + Class<V> valueType, + Class<? extends Annotation> annotationType) { + return newMapBinder( + binder, TypeLiteral.get(keyType), TypeLiteral.get(valueType), annotationType); + } + + private final RealMapBinder<K, V> delegate; + + private MapBinder(RealMapBinder<K, V> delegate) { + this.delegate = delegate; + } + + /** + * Configures the {@code MapBinder} to handle duplicate entries. + * + * <p>When multiple equal keys are bound, the value that gets included in the map is arbitrary. + * + * <p>In addition to the {@code Map<K, V>} and {@code Map<K, Provider<V>>} maps that are normally + * bound, a {@code Map<K, Set<V>>} and {@code Map<K, Set<Provider<V>>>} are <em>also</em> bound, + * which contain all values bound to each key. + * + * <p>When multiple modules contribute elements to the map, this configuration option impacts all + * of them. + * + * @return this map binder + * @since 3.0 + */ + public MapBinder<K, V> permitDuplicates() { + delegate.permitDuplicates(); + return this; + } + + /** + * Returns a binding builder used to add a new entry in the map. Each key must be distinct (and + * non-null). Bound providers will be evaluated each time the map is injected. + * + * <p>It is an error to call this method without also calling one of the {@code to} methods on the + * returned binding builder. + * + * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding + * scope. + */ + public LinkedBindingBuilder<V> addBinding(K key) { + return delegate.addBinding(key); + } + + // Some tests rely on MapBinder implementing equals/hashCode + + @Override + public boolean equals(Object obj) { + if (obj instanceof MapBinder) { + return delegate.equals(((MapBinder<?, ?>) obj).delegate); + } + return false; + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } +} diff --git a/core/src/com/google/inject/multibindings/MapBinderBinding.java b/core/src/com/google/inject/multibindings/MapBinderBinding.java new file mode 100644 index 00000000..b45806f5 --- /dev/null +++ b/core/src/com/google/inject/multibindings/MapBinderBinding.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import com.google.inject.Binding; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.spi.Element; +import com.google.inject.spi.Elements; +import java.util.List; +import java.util.Map; + +/** + * A binding for a MapBinder. + * + * <p>Although MapBinders may be injected through a variety of generic types (Map<K, V>, Map + * <K, Provider<V>>, Map<K, Set<V>>, Map<K, Set< Provider<V>>, and even + * Set<Map.Entry<K, Provider<V>>), a MapBinderBinding exists only on the Binding associated + * with the Map<K, V> key. Other bindings can be validated to be derived from this + * MapBinderBinding using {@link #containsElement(Element)}. + * + * @param <T> The fully qualified type of the map, including Map. For example: <code> + * MapBinderBinding<Map<String, Snack>></code> + * @since 3.0 + * @author sameb@google.com (Sam Berlin) + */ +public interface MapBinderBinding<T> { + + /** Returns the {@link Key} for the map. */ + Key<T> getMapKey(); + + /** + * Returns the TypeLiteral describing the keys of the map. + * + * <p>The TypeLiteral will always match the type Map's generic type. For example, if getMapKey + * returns a key of <code>Map<String, Snack></code>, then this will always return a <code> + * TypeLiteral<String></code>. + */ + TypeLiteral<?> getKeyTypeLiteral(); + + /** + * Returns the TypeLiteral describing the values of the map. + * + * <p>The TypeLiteral will always match the type Map's generic type. For example, if getMapKey + * returns a key of <code>Map<String, Snack></code>, then this will always return a <code> + * TypeLiteral<Snack></code>. + */ + TypeLiteral<?> getValueTypeLiteral(); + + /** + * Returns all entries in the Map. The returned list of Map.Entries contains the key and a binding + * to the value. Duplicate keys or values will exist as separate Map.Entries in the returned list. + * This is only supported on bindings returned from an injector. This will throw {@link + * UnsupportedOperationException} if it is called on an element retrieved from {@link + * Elements#getElements}. + * + * <p>The elements will always match the type Map's generic type. For example, if getMapKey + * returns a key of <code>Map<String, Snack></code>, then this will always return a list of + * type <code>List<Map.Entry<String, Binding<Snack>>></code>. + */ + List<Map.Entry<?, Binding<?>>> getEntries(); + + /** + * Similar to {@link #getEntries()}, but can be used on a MapBinderBinding retrieved from {@link + * Elements#getElements}. + * + * <p>One way to use this is to pass in the results of {@link Elements#getElements} as the {@code + * elements} parameter. + * + * <p>This differs from {@link #getEntries()} in that it will return duplicates if they are + * present in the {@code elements} passed in. This does not run the normal Guice de-duplication + * that {@link #getEntries()} does. + * + * @throws IllegalArgumentException if the provided elements contain partial map entries. If the + * elements come from {@link Elements#getElements} on a module with a MapBinder, there will be + * a 1:1 relationship and no exception will be thrown. + * @since 4.2 + */ + List<Map.Entry<?, Binding<?>>> getEntries(Iterable<? extends Element> elements); + + /** + * Returns true if the MapBinder permits duplicates. This is only supported on bindings returned + * from an injector. This will throw {@link UnsupportedOperationException} if it is called on a + * MapBinderBinding retrieved from {@link Elements#getElements}. + */ + boolean permitsDuplicates(); + + /** + * Returns true if this MapBinder contains the given Element in order to build the map or uses the + * given Element in order to support building and injecting the map. This will work for + * MapBinderBindings retrieved from an injector and {@link Elements#getElements}. Usually this is + * only necessary if you are working with elements retrieved from modules (without an Injector), + * otherwise {@link #getEntries} and {@link #permitsDuplicates} are better options. + * + * <p>If you need to introspect the details of the map, such as the keys, values or if it permits + * duplicates, it is necessary to pass the elements through an Injector and use {@link + * #getEntries()} and {@link #permitsDuplicates()}. + */ + boolean containsElement(Element element); +} diff --git a/core/src/com/google/inject/multibindings/MapKey.java b/core/src/com/google/inject/multibindings/MapKey.java new file mode 100644 index 00000000..3f8af89d --- /dev/null +++ b/core/src/com/google/inject/multibindings/MapKey.java @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.ANNOTATION_TYPE; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Allows users define customized key type annotations for map bindings by annotating an annotation + * of a {@code Map}'s key type. The custom key annotation can be applied to methods also annotated + * with {@literal @}{@link ProvidesIntoMap}. + * + * <p>A {@link StringMapKey} and {@link ClassMapKey} are provided for convenience with maps whose + * keys are strings or classes. For maps with enums or primitive types as keys, you must provide + * your own MapKey annotation, such as this one for an enum: + * + * <pre> + * {@literal @}MapKey(unwrapValue = true) + * {@literal @}Retention(RUNTIME) + * public {@literal @}interface MyCustomEnumKey { + * MyCustomEnum value(); + * } + * </pre> + * + * You can also use the whole annotation as the key, if {@code unwrapValue=false}. When unwrapValue + * is false, the annotation type will be the key type for the injected map and the annotation + * instances will be the key values. If {@code unwrapValue=true}, the value() type will be the key + * type for injected map and the value() instances will be the keys values. + * + * @since 4.0 + */ +@Documented +@Target(ANNOTATION_TYPE) +@Retention(RUNTIME) +public @interface MapKey { + /** + * if {@code unwrapValue} is false, then the whole annotation will be the type and annotation + * instances will be the keys. If {@code unwrapValue} is true, the value() type of key type + * annotation will be the key type for injected map and the value instances will be the keys. + */ + boolean unwrapValue() default true; +} diff --git a/core/src/com/google/inject/multibindings/Multibinder.java b/core/src/com/google/inject/multibindings/Multibinder.java new file mode 100644 index 00000000..058fffe9 --- /dev/null +++ b/core/src/com/google/inject/multibindings/Multibinder.java @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2008 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static com.google.inject.internal.RealMultibinder.newRealSetBinder; + +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.RealMultibinder; +import java.lang.annotation.Annotation; +import java.util.Collection; +import java.util.Set; + +/** + * An API to bind multiple values separately, only to later inject them as a complete collection. + * Multibinder is intended for use in your application's module: + * + * <pre><code> + * public class SnacksModule extends AbstractModule { + * protected void configure() { + * Multibinder<Snack> multibinder + * = Multibinder.newSetBinder(binder(), Snack.class); + * multibinder.addBinding().toInstance(new Twix()); + * multibinder.addBinding().toProvider(SnickersProvider.class); + * multibinder.addBinding().to(Skittles.class); + * } + * }</code></pre> + * + * <p>With this binding, a {@link Set}{@code <Snack>} can now be injected: + * + * <pre><code> + * class SnackMachine { + * {@literal @}Inject + * public SnackMachine(Set<Snack> snacks) { ... } + * }</code></pre> + * + * If desired, {@link Collection}{@code <Provider<Snack>>} can also be injected. + * + * <p>Contributing multibindings from different modules is supported. For example, it is okay for + * both {@code CandyModule} and {@code ChipsModule} to create their own {@code Multibinder<Snack>}, + * and to each contribute bindings to the set of snacks. When that set is injected, it will contain + * elements from both modules. + * + * <p>The set's iteration order is consistent with the binding order. This is convenient when + * multiple elements are contributed by the same module because that module can order its bindings + * appropriately. Avoid relying on the iteration order of elements contributed by different modules, + * since there is no equivalent mechanism to order modules. + * + * <p>The set is unmodifiable. Elements can only be added to the set by configuring the multibinder. + * Elements can never be removed from the set. + * + * <p>Elements are resolved at set injection time. If an element is bound to a provider, that + * provider's get method will be called each time the set is injected (unless the binding is also + * scoped). + * + * <p>Annotations are be used to create different sets of the same element type. Each distinct + * annotation gets its own independent collection of elements. + * + * <p><strong>Elements must be distinct.</strong> If multiple bound elements have the same value, + * set injection will fail. + * + * <p><strong>Elements must be non-null.</strong> If any set element is null, set injection will + * fail. + * + * @author jessewilson@google.com (Jesse Wilson) + */ +public class Multibinder<T> { + // This class is non-final due to users mocking this in tests :( + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with no binding annotation. + */ + public static <T> Multibinder<T> newSetBinder(Binder binder, TypeLiteral<T> type) { + return newSetBinder(binder, Key.get(type)); + } + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with no binding annotation. + */ + public static <T> Multibinder<T> newSetBinder(Binder binder, Class<T> type) { + return newSetBinder(binder, Key.get(type)); + } + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with {@code annotation}. + */ + public static <T> Multibinder<T> newSetBinder( + Binder binder, TypeLiteral<T> type, Annotation annotation) { + return newSetBinder(binder, Key.get(type, annotation)); + } + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with {@code annotation}. + */ + public static <T> Multibinder<T> newSetBinder( + Binder binder, Class<T> type, Annotation annotation) { + return newSetBinder(binder, Key.get(type, annotation)); + } + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with {@code annotationType}. + */ + public static <T> Multibinder<T> newSetBinder( + Binder binder, TypeLiteral<T> type, Class<? extends Annotation> annotationType) { + return newSetBinder(binder, Key.get(type, annotationType)); + } + + /** + * Returns a new multibinder that collects instances of the key's type in a {@link Set} that is + * itself bound with the annotation (if any) of the key. + * + * @since 4.0 + */ + public static <T> Multibinder<T> newSetBinder(Binder binder, Key<T> key) { + return new Multibinder<T>(newRealSetBinder(binder.skipSources(Multibinder.class), key)); + } + + /** + * Returns a new multibinder that collects instances of {@code type} in a {@link Set} that is + * itself bound with {@code annotationType}. + */ + public static <T> Multibinder<T> newSetBinder( + Binder binder, Class<T> type, Class<? extends Annotation> annotationType) { + return newSetBinder(binder, Key.get(type, annotationType)); + } + + private final RealMultibinder<T> delegate; + + private Multibinder(RealMultibinder<T> delegate) { + this.delegate = delegate; + } + + /** + * Configures the bound set to silently discard duplicate elements. When multiple equal values are + * bound, the one that gets included is arbitrary. When multiple modules contribute elements to + * the set, this configuration option impacts all of them. + * + * @return this multibinder + * @since 3.0 + */ + public Multibinder<T> permitDuplicates() { + delegate.permitDuplicates(); + return this; + } + + /** + * Returns a binding builder used to add a new element in the set. Each bound element must have a + * distinct value. Bound providers will be evaluated each time the set is injected. + * + * <p>It is an error to call this method without also calling one of the {@code to} methods on the + * returned binding builder. + * + * <p>Scoping elements independently is supported. Use the {@code in} method to specify a binding + * scope. + */ + public LinkedBindingBuilder<T> addBinding() { + return delegate.addBinding(); + } + + // Some tests rely on Multibinder implementing equals/hashCode + + @Override + public boolean equals(Object obj) { + if (obj instanceof Multibinder) { + return delegate.equals(((Multibinder<?>) obj).delegate); + } + return false; + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } +} diff --git a/core/src/com/google/inject/multibindings/MultibinderBinding.java b/core/src/com/google/inject/multibindings/MultibinderBinding.java new file mode 100644 index 00000000..43db6a23 --- /dev/null +++ b/core/src/com/google/inject/multibindings/MultibinderBinding.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import com.google.inject.Binding; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.spi.Element; +import com.google.inject.spi.Elements; +import java.util.List; + +/** + * A binding for a Multibinder. + * + * @param <T> The fully qualified type of the set, including Set. For example: <code> + * MultibinderBinding<Set<Boolean>></code> + * @since 3.0 + * @author sameb@google.com (Sam Berlin) + */ +public interface MultibinderBinding<T> { + + /** Returns the key for the set. */ + Key<T> getSetKey(); + + /** + * Returns the TypeLiteral that describes the type of elements in the set. + * + * <p>The elements will always match the type Set's generic type. For example, if getSetKey + * returns a key of <code>Set<String></code>, then this will always return a <code> + * TypeLiteral<String></code>. + */ + TypeLiteral<?> getElementTypeLiteral(); + + /** + * Returns all bindings that make up the set. This is only supported on bindings returned from an + * injector. This will throw {@link UnsupportedOperationException} if it is called on an element + * retrieved from {@link Elements#getElements}. + * + * <p>The elements will always match the type Set's generic type. For example, if getSetKey + * returns a key of <code>Set<String></code>, then this will always return a list of type + * <code>List<Binding<String>></code>. + */ + List<Binding<?>> getElements(); + + /** + * Returns true if the multibinder permits duplicates. This is only supported on bindings returned + * from an injector. This will throw {@link UnsupportedOperationException} if it is called on a + * MultibinderBinding retrieved from {@link Elements#getElements}. + */ + boolean permitsDuplicates(); + + /** + * Returns true if this Multibinder uses the given Element. This will be true for bindings that + * derive the elements of the set and other bindings that Multibinder uses internally. This will + * work for MultibinderBindings retrieved from an injector and {@link Elements#getElements}. + * Usually this is only necessary if you are working with elements retrieved from modules (without + * an Injector), otherwise {@link #getElements} and {@link #permitsDuplicates} are better options. + * + * <p>If you need to introspect the details of the set, such as the values or if it permits + * duplicates, it is necessary to pass the elements through an Injector and use {@link + * #getElements()} and {@link #permitsDuplicates()}. + */ + boolean containsElement(Element element); +} diff --git a/core/src/com/google/inject/multibindings/MultibindingsScanner.java b/core/src/com/google/inject/multibindings/MultibindingsScanner.java new file mode 100644 index 00000000..3ede7c5e --- /dev/null +++ b/core/src/com/google/inject/multibindings/MultibindingsScanner.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import com.google.common.collect.ImmutableSet; +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.Module; +import com.google.inject.spi.InjectionPoint; +import com.google.inject.spi.ModuleAnnotatedMethodScanner; +import com.google.inject.util.Modules; +import java.lang.annotation.Annotation; +import java.util.Set; + +/** + * Scans a module for annotations that signal multibindings, mapbindings, and optional bindings. + * + * @since 4.0 + * @deprecated This functionality is installed by default. All references to this can be safely + * removed. This class will be removed in Guice 4.4 + */ +@Deprecated +public class MultibindingsScanner { + private MultibindingsScanner() {} + + /** + * Returns a module that, when installed, will scan all modules for methods with the annotations + * {@literal @}{@link ProvidesIntoMap}, {@literal @}{@link ProvidesIntoSet}, and + * {@literal @}{@link ProvidesIntoOptional}. + * + * <p>This is a convenience method, equivalent to doing {@code + * binder().scanModulesForAnnotatedMethods(MultibindingsScanner.scanner())}. + * + * @deprecated This functionality is now installed by default. All references/installations can be + * eliminated. + */ + @Deprecated + public static Module asModule() { + return Modules.EMPTY_MODULE; + } + + /** + * @deprecated This method returns an empty scanner since the preexisting functionality is + * installed by default. + */ + @Deprecated + public static ModuleAnnotatedMethodScanner scanner() { + return new ModuleAnnotatedMethodScanner() { + @Override + public Set<? extends Class<? extends Annotation>> annotationClasses() { + return ImmutableSet.of(); + } + + @Override + public <T> Key<T> prepareMethod( + Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) { + throw new IllegalStateException("Unexpected annotation: " + annotation); + } + }; + } +} diff --git a/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java b/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java new file mode 100644 index 00000000..b6a2eb31 --- /dev/null +++ b/core/src/com/google/inject/multibindings/MultibindingsTargetVisitor.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2010 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import com.google.inject.spi.BindingTargetVisitor; + +/** + * A visitor for the multibinder extension. + * + * <p>If your {@link BindingTargetVisitor} implements this interface, bindings created by using + * {@link Multibinder}, {@link MapBinder} or {@link OptionalBinderBinding} will be visited through + * this interface. + * + * @since 3.0 + * @author sameb@google.com (Sam Berlin) + */ +public interface MultibindingsTargetVisitor<T, V> extends BindingTargetVisitor<T, V> { + + /** Visits a binding created through {@link Multibinder}. */ + V visit(MultibinderBinding<? extends T> multibinding); + + /** Visits a binding created through {@link MapBinder}. */ + V visit(MapBinderBinding<? extends T> mapbinding); + + /** + * Visits a binding created through {@link OptionalBinder}. + * + * @since 4.0 + */ + V visit(OptionalBinderBinding<? extends T> optionalbinding); +} diff --git a/core/src/com/google/inject/multibindings/OptionalBinder.java b/core/src/com/google/inject/multibindings/OptionalBinder.java new file mode 100644 index 00000000..0e015c5d --- /dev/null +++ b/core/src/com/google/inject/multibindings/OptionalBinder.java @@ -0,0 +1,199 @@ +/* + * Copyright (C) 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static com.google.inject.internal.RealOptionalBinder.newRealOptionalBinder; + +import com.google.common.base.Optional; +import com.google.inject.Binder; +import com.google.inject.Key; +import com.google.inject.TypeLiteral; +import com.google.inject.binder.LinkedBindingBuilder; +import com.google.inject.internal.RealOptionalBinder; + +/** + * An API to bind optional values, optionally with a default value. OptionalBinder fulfills two + * roles: + * + * <ol> + * <li>It allows a framework to define an injection point that may or may not be bound by users. + * <li>It allows a framework to supply a default value that can be changed by users. + * </ol> + * + * <p>When an OptionalBinder is added, it will always supply the bindings: {@code Optional<T>} and + * {@code Optional<Provider<T>>}. If {@link #setBinding} or {@link #setDefault} are called, it will + * also bind {@code T}. + * + * <p>{@code setDefault} is intended for use by frameworks that need a default value. User code can + * call {@code setBinding} to override the default. <b>Warning: Even if setBinding is called, the + * default binding will still exist in the object graph. If it is a singleton, it will be + * instantiated in {@code Stage.PRODUCTION}.</b> + * + * <p>If setDefault or setBinding are linked to Providers, the Provider may return {@code null}. If + * it does, the Optional bindings will be absent. Binding setBinding to a Provider that returns null + * will not cause OptionalBinder to fall back to the setDefault binding. + * + * <p>If neither setDefault nor setBinding are called, it will try to link to a user-supplied + * binding of the same type. If no binding exists, the optionals will be absent. Otherwise, if a + * user-supplied binding of that type exists, or if setBinding or setDefault are called, the + * optionals will return present if they are bound to a non-null value. + * + * <p>Values are resolved at injection time. If a value is bound to a provider, that provider's get + * method will be called each time the optional is injected (unless the binding is also scoped, or + * an optional of provider is injected). + * + * <p>Annotations are used to create different optionals of the same key/value type. Each distinct + * annotation gets its own independent binding. + * + * <pre><code> + * public class FrameworkModule extends AbstractModule { + * protected void configure() { + * OptionalBinder.newOptionalBinder(binder(), Renamer.class); + * } + * }</code></pre> + * + * <p>With this module, an {@link Optional}{@code <Renamer>} can now be injected. With no other + * bindings, the optional will be absent. Users can specify bindings in one of two ways: + * + * <p>Option 1: + * + * <pre><code> + * public class UserRenamerModule extends AbstractModule { + * protected void configure() { + * bind(Renamer.class).to(ReplacingRenamer.class); + * } + * }</code></pre> + * + * <p>or Option 2: + * + * <pre><code> + * public class UserRenamerModule extends AbstractModule { + * protected void configure() { + * OptionalBinder.newOptionalBinder(binder(), Renamer.class) + * .setBinding().to(ReplacingRenamer.class); + * } + * }</code></pre> + * + * With both options, the {@code Optional<Renamer>} will be present and supply the ReplacingRenamer. + * + * <p>Default values can be supplied using: + * + * <pre><code> + * public class FrameworkModule extends AbstractModule { + * protected void configure() { + * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class)) + * .setDefault().toInstance(DEFAULT_LOOKUP_URL); + * } + * }</code></pre> + * + * With the above module, code can inject an {@code @LookupUrl String} and it will supply the + * DEFAULT_LOOKUP_URL. A user can change this value by binding + * + * <pre><code> + * public class UserLookupModule extends AbstractModule { + * protected void configure() { + * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class)) + * .setBinding().toInstance(CUSTOM_LOOKUP_URL); + * } + * }</code></pre> + * + * ... which will override the default value. + * + * <p>If one module uses setDefault the only way to override the default is to use setBinding. It is + * an error for a user to specify the binding without using OptionalBinder if setDefault or + * setBinding are called. For example, + * + * <pre><code> + * public class FrameworkModule extends AbstractModule { + * protected void configure() { + * OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, LookupUrl.class)) + * .setDefault().toInstance(DEFAULT_LOOKUP_URL); + * } + * } + * public class UserLookupModule extends AbstractModule { + * protected void configure() { + * bind(Key.get(String.class, LookupUrl.class)).toInstance(CUSTOM_LOOKUP_URL); + * } + * }</code></pre> + * + * ... would generate an error, because both the framework and the user are trying to bind + * {@code @LookupUrl String}. + * + * @author sameb@google.com (Sam Berlin) + * @since 4.0 + */ +public class OptionalBinder<T> { + // This class is non-final due to users mocking this in tests :( + + public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Class<T> type) { + return new OptionalBinder<T>( + newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type))); + } + + public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, TypeLiteral<T> type) { + return new OptionalBinder<T>( + newRealOptionalBinder(binder.skipSources(OptionalBinder.class), Key.get(type))); + } + + public static <T> OptionalBinder<T> newOptionalBinder(Binder binder, Key<T> type) { + return new OptionalBinder<T>( + newRealOptionalBinder(binder.skipSources(OptionalBinder.class), type)); + } + + private final RealOptionalBinder<T> delegate; + + private OptionalBinder(RealOptionalBinder<T> delegate) { + this.delegate = delegate; + } + + /** + * Returns a binding builder used to set the default value that will be injected. The binding set + * by this method will be ignored if {@link #setBinding} is called. + * + * <p>It is an error to call this method without also calling one of the {@code to} methods on the + * returned binding builder. + */ + public LinkedBindingBuilder<T> setDefault() { + return delegate.setDefault(); + } + + /** + * Returns a binding builder used to set the actual value that will be injected. This overrides + * any binding set by {@link #setDefault}. + * + * <p>It is an error to call this method without also calling one of the {@code to} methods on the + * returned binding builder. + */ + public LinkedBindingBuilder<T> setBinding() { + return delegate.setBinding(); + } + + // Some tests depend on equals/hashCode behavior of OptionalBinder + + @Override + public boolean equals(Object obj) { + if (obj instanceof OptionalBinder) { + return delegate.equals(((OptionalBinder<?>) obj).delegate); + } + return false; + } + + @Override + public int hashCode() { + return delegate.hashCode(); + } +} diff --git a/core/src/com/google/inject/multibindings/OptionalBinderBinding.java b/core/src/com/google/inject/multibindings/OptionalBinderBinding.java new file mode 100644 index 00000000..5fedc4b5 --- /dev/null +++ b/core/src/com/google/inject/multibindings/OptionalBinderBinding.java @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2014 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import com.google.inject.Binding; +import com.google.inject.Key; +import com.google.inject.spi.Element; +import com.google.inject.spi.Elements; + +/** + * A binding for a OptionalBinder. + * + * <p>Although OptionalBinders may be injected through a variety of types {@code T}, {@code + * Optional<T>}, {@code Optional<Provider<T>>}, etc..), an OptionalBinderBinding exists only on the + * Binding associated with the {@code Optional<T>} key. Other bindings can be validated to be + * derived from this OptionalBinderBinding using {@link #containsElement}. + * + * @param <T> The fully qualified type of the optional binding, including Optional. For example: + * {@code Optional<String>}. + * @since 4.0 + * @author sameb@google.com (Sam Berlin) + */ +public interface OptionalBinderBinding<T> { + + /** Returns the {@link Key} for this binding. */ + Key<T> getKey(); + + /** + * Returns the default binding (set by {@link OptionalBinder#setDefault}) if one exists or null if + * no default binding is set. This will throw {@link UnsupportedOperationException} if it is + * called on an element retrieved from {@link Elements#getElements}. + * + * <p>The Binding's type will always match the type Optional's generic type. For example, if + * getKey returns a key of <code>Optional<String></code>, then this will always return a <code> + * Binding<String></code>. + */ + Binding<?> getDefaultBinding(); + + /** + * Returns the actual binding (set by {@link OptionalBinder#setBinding}) or null if not set. This + * will throw {@link UnsupportedOperationException} if it is called on an element retrieved from + * {@link Elements#getElements}. + * + * <p>The Binding's type will always match the type Optional's generic type. For example, if + * getKey returns a key of <code>Optional<String></code>, then this will always return a <code> + * Binding<String></code>. + */ + Binding<?> getActualBinding(); + + /** + * Returns true if this OptionalBinder contains the given Element in order to build the optional + * binding or uses the given Element in order to support building and injecting its data. This + * will work for OptionalBinderBinding retrieved from an injector and {@link + * Elements#getElements}. Usually this is only necessary if you are working with elements + * retrieved from modules (without an Injector), otherwise {@link #getDefaultBinding} and {@link + * #getActualBinding} are better options. + */ + boolean containsElement(Element element); +} diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoMap.java b/core/src/com/google/inject/multibindings/ProvidesIntoMap.java new file mode 100644 index 00000000..9ab0dd93 --- /dev/null +++ b/core/src/com/google/inject/multibindings/ProvidesIntoMap.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.Module; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Annotates methods of a {@link Module} to add items to a {@link MapBinder}. The method's return + * type, binding annotation and additional key annotation determines what Map this will contribute + * to. For example, + * + * <pre> + * {@literal @}ProvidesIntoMap + * {@literal @}StringMapKey("Foo") + * {@literal @}Named("urls") + * Plugin provideFooUrl(FooManager fm) { return fm.getPlugin(); } + * + * {@literal @}ProvidesIntoMap + * {@literal @}StringMapKey("Bar") + * {@literal @}Named("urls") + * Plugin provideBarUrl(BarManager bm) { return bm.getPlugin(); } + * </pre> + * + * will add two items to the {@code @Named("urls") Map<String, Plugin>} map. The key 'Foo' will map + * to the provideFooUrl method, and the key 'Bar' will map to the provideBarUrl method. The values + * are bound as providers and will be evaluated at injection time. + * + * <p>Because the key is specified as an annotation, only Strings, Classes, enums, primitive types + * and annotation instances are supported as keys. + * + * @author sameb@google.com (Sam Berlin) + * @since 4.0 + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface ProvidesIntoMap {} diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java b/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java new file mode 100644 index 00000000..19799c80 --- /dev/null +++ b/core/src/com/google/inject/multibindings/ProvidesIntoOptional.java @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.Module; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Annotates methods of a {@link Module} to add items to a {@link Multibinder}. The method's return + * type and binding annotation determines what Optional this will contribute to. For example, + * + * <pre> + * {@literal @}ProvidesIntoOptional(DEFAULT) + * {@literal @}Named("url") + * String provideFooUrl(FooManager fm) { returm fm.getUrl(); } + * + * {@literal @}ProvidesIntoOptional(ACTUAL) + * {@literal @}Named("url") + * String provideBarUrl(BarManager bm) { return bm.getUrl(); } + * </pre> + * + * will set the default value of {@code @Named("url") Optional<String>} to foo's URL, and then + * override it to bar's URL. + * + * @author sameb@google.com (Sam Berlin) + * @since 4.0 + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface ProvidesIntoOptional { + /** @since 4.0 */ + enum Type { + /** Corresponds to {@link OptionalBinder#setBinding}. */ + ACTUAL, + + /** Corresponds to {@link OptionalBinder#setDefault}. */ + DEFAULT + } + + /** Specifies if the binding is for the actual or default value. */ + Type value(); +} diff --git a/core/src/com/google/inject/multibindings/ProvidesIntoSet.java b/core/src/com/google/inject/multibindings/ProvidesIntoSet.java new file mode 100644 index 00000000..a7618b6f --- /dev/null +++ b/core/src/com/google/inject/multibindings/ProvidesIntoSet.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import com.google.inject.Module; +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Annotates methods of a {@link Module} to add items to a {@link Multibinder}. The method's return + * type and binding annotation determines what Set this will contribute to. For example, + * + * <pre> + * {@literal @}ProvidesIntoSet + * {@literal @}Named("urls") + * String provideFooUrl(FooManager fm) { returm fm.getUrl(); } + * + * {@literal @}ProvidesIntoSet + * {@literal @}Named("urls") + * String provideBarUrl(BarManager bm) { return bm.getUrl(); } + * </pre> + * + * will add two items to the {@code @Named("urls") Set<String>} set. The items are bound as + * providers and will be evaluated at injection time. + * + * @author sameb@google.com (Sam Berlin) + * @since 4.0 + */ +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface ProvidesIntoSet {} diff --git a/core/src/com/google/inject/multibindings/StringMapKey.java b/core/src/com/google/inject/multibindings/StringMapKey.java new file mode 100644 index 00000000..7c6e041f --- /dev/null +++ b/core/src/com/google/inject/multibindings/StringMapKey.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2015 Google Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.google.inject.multibindings; + +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +/** + * Allows {@literal @}{@link ProvidesIntoMap} to specify a string map key. + * + * @since 4.0 + */ +@MapKey(unwrapValue = true) +@Documented +@Target(METHOD) +@Retention(RUNTIME) +public @interface StringMapKey { + String value(); +} diff --git a/core/src/com/google/inject/internal/ContextualCallable.java b/core/src/com/google/inject/multibindings/package-info.java index 56c0630c..71517791 100644 --- a/core/src/com/google/inject/internal/ContextualCallable.java +++ b/core/src/com/google/inject/multibindings/package-info.java @@ -1,5 +1,5 @@ -/** - * Copyright (C) 2006 Google Inc. +/* + * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,11 +14,8 @@ * limitations under the License. */ -package com.google.inject.internal; - /** - * @author crazybob@google.com (Bob Lee) + * Extension for binding multiple instances in a collection; this extension requires {@code + * guice-multibindings.jar}. */ -interface ContextualCallable<T> { - T call(InternalContext context) throws ErrorsException; -} +package com.google.inject.multibindings; diff --git a/core/src/com/google/inject/name/Named.java b/core/src/com/google/inject/name/Named.java index 23b3d5dc..b1d9a4e8 100644 --- a/core/src/com/google/inject/name/Named.java +++ b/core/src/com/google/inject/name/Named.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,7 +19,6 @@ package com.google.inject.name; import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.google.inject.BindingAnnotation; - import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -30,7 +29,7 @@ import java.lang.annotation.Target; * @author crazybob@google.com (Bob Lee) */ @Retention(RUNTIME) -@Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD }) +@Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD}) @BindingAnnotation public @interface Named { String value(); diff --git a/core/src/com/google/inject/name/NamedImpl.java b/core/src/com/google/inject/name/NamedImpl.java index 2fe01071..9c4d10e4 100644 --- a/core/src/com/google/inject/name/NamedImpl.java +++ b/core/src/com/google/inject/name/NamedImpl.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,6 +18,7 @@ package com.google.inject.name; import static com.google.common.base.Preconditions.checkNotNull; +import com.google.inject.internal.Annotations; import java.io.Serializable; import java.lang.annotation.Annotation; @@ -29,15 +30,18 @@ class NamedImpl implements Named, Serializable { this.value = checkNotNull(value, "name"); } + @Override public String value() { return this.value; } + @Override public int hashCode() { // This is specified in java.lang.Annotation. return (127 * "value".hashCode()) ^ value.hashCode(); } + @Override public boolean equals(Object o) { if (!(o instanceof Named)) { return false; @@ -47,10 +51,12 @@ class NamedImpl implements Named, Serializable { return value.equals(other.value()); } + @Override public String toString() { - return "@" + Named.class.getName() + "(value=" + value + ")"; + return "@" + Named.class.getName() + "(value=" + Annotations.memberValueString(value) + ")"; } + @Override public Class<? extends Annotation> annotationType() { return Named.class; } diff --git a/core/src/com/google/inject/name/Names.java b/core/src/com/google/inject/name/Names.java index f7ec971a..619de81e 100644 --- a/core/src/com/google/inject/name/Names.java +++ b/core/src/com/google/inject/name/Names.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.name; import com.google.inject.Binder; import com.google.inject.Key; - import java.util.Enumeration; import java.util.Map; import java.util.Properties; @@ -32,17 +31,12 @@ public class Names { private Names() {} - /** - * Creates a {@link Named} annotation with {@code name} as the value. - */ + /** Creates a {@link Named} annotation with {@code name} as the value. */ public static Named named(String name) { return new NamedImpl(name); } - /** - * Creates a constant binding to {@code @Named(key)} for each entry in - * {@code properties}. - */ + /** Creates a constant binding to {@code @Named(key)} for each entry in {@code properties}. */ public static void bindProperties(Binder binder, Map<String, String> properties) { binder = binder.skipSources(Names.class); for (Map.Entry<String, String> entry : properties.entrySet()) { @@ -53,9 +47,8 @@ public class Names { } /** - * Creates a constant binding to {@code @Named(key)} for each property. This - * method binds all properties including those inherited from - * {@link Properties#defaults defaults}. + * Creates a constant binding to {@code @Named(key)} for each property. This method binds all + * properties including those inherited from {@link Properties#defaults defaults}. */ public static void bindProperties(Binder binder, Properties properties) { binder = binder.skipSources(Names.class); diff --git a/core/src/com/google/inject/name/package-info.java b/core/src/com/google/inject/name/package-info.java index d6bf05da..8d4482d1 100644 --- a/core/src/com/google/inject/name/package-info.java +++ b/core/src/com/google/inject/name/package-info.java @@ -14,7 +14,5 @@ * limitations under the License. */ -/** - * Support for binding to string-based names. - */ -package com.google.inject.name;
\ No newline at end of file +/** Support for binding to string-based names. */ +package com.google.inject.name; diff --git a/core/src/com/google/inject/package-info.java b/core/src/com/google/inject/package-info.java index 626bde2b..12b3b1eb 100644 --- a/core/src/com/google/inject/package-info.java +++ b/core/src/com/google/inject/package-info.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,33 +15,25 @@ */ /** - * <i>Google Guice</i> (pronounced "juice") is an ultra-lightweight dependency - * injection framework. Please refer to the Guice - * <a href="http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8">User's Guide</a> - * for a gentle introduction. + * <i>Google Guice</i> (pronounced "juice") is an ultra-lightweight dependency injection framework. + * Please refer to the Guice <a href="http://docs.google.com/Doc?id=dd2fhx4z_5df5hw8">User's + * Guide</a> for a gentle introduction. * * <p>The principal public APIs in this package are: * * <dl> * <dt>{@link com.google.inject.Inject} - * <dd>The annotation you will use in your implementation classes to tell Guice - * where and how it should send in ("inject") the objects you depend on - * (your "dependencies"). - * + * <dd>The annotation you will use in your implementation classes to tell Guice where and how it + * should send in ("inject") the objects you depend on (your "dependencies"). * <dt>{@link com.google.inject.Module} - * <dd>The interface you will implement in order to specify "bindings" -- - * instructions for how Guice should handle injection -- for a particular - * set of interfaces. - * + * <dd>The interface you will implement in order to specify "bindings" -- instructions for how Guice + * should handle injection -- for a particular set of interfaces. * <dt>{@link com.google.inject.Binder} - * <dd>The object that Guice passes into your {@link com.google.inject.Module} - * to collect these bindings. - * + * <dd>The object that Guice passes into your {@link com.google.inject.Module} to collect these + * bindings. * <dt>{@link com.google.inject.Provider} - * <dd>The interface you will implement when you need to customize exactly how - * Guice creates instances for a particular binding. - * + * <dd>The interface you will implement when you need to customize exactly how Guice creates + * instances for a particular binding. * </dl> - * */ -package com.google.inject;
\ No newline at end of file +package com.google.inject; diff --git a/core/src/com/google/inject/spi/BindingScopingVisitor.java b/core/src/com/google/inject/spi/BindingScopingVisitor.java index 2abfc9eb..41bd0699 100644 --- a/core/src/com/google/inject/spi/BindingScopingVisitor.java +++ b/core/src/com/google/inject/spi/BindingScopingVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,14 +17,13 @@ package com.google.inject.spi; import com.google.inject.Scope; - import java.lang.annotation.Annotation; /** * Visits each of the strategies used to scope an injection. * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @since 2.0 */ public interface BindingScopingVisitor<V> { @@ -35,9 +34,7 @@ public interface BindingScopingVisitor<V> { */ V visitEagerSingleton(); - /** - * Visit a scope instance. This scope strategy is found on both module and injector bindings. - */ + /** Visit a scope instance. This scope strategy is found on both module and injector bindings. */ V visitScope(Scope scope); /** @@ -49,9 +46,9 @@ public interface BindingScopingVisitor<V> { /** * Visit an unspecified or unscoped strategy. On a module, this strategy indicates that the - * injector should use scoping annotations to find a scope. On an injector, it indicates that - * no scope is applied to the binding. An unscoped binding will behave like a scoped one when it - * is linked to a scoped binding. + * injector should use scoping annotations to find a scope. On an injector, it indicates that no + * scope is applied to the binding. An unscoped binding will behave like a scoped one when it is + * linked to a scoped binding. */ V visitNoScoping(); } diff --git a/core/src/com/google/inject/spi/BindingTargetVisitor.java b/core/src/com/google/inject/spi/BindingTargetVisitor.java index 7137d743..890aebac 100644 --- a/core/src/com/google/inject/spi/BindingTargetVisitor.java +++ b/core/src/com/google/inject/spi/BindingTargetVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,8 +19,8 @@ package com.google.inject.spi; /** * Visits each of the strategies used to find an instance to satisfy an injection. * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @since 2.0 */ public interface BindingTargetVisitor<T, V> { @@ -45,8 +45,8 @@ public interface BindingTargetVisitor<T, V> { V visit(ProviderKeyBinding<? extends T> binding); /** - * Visit a linked key binding. The other key's binding is used to resolve injections. This - * target is found in both module and injector bindings. + * Visit a linked key binding. The other key's binding is used to resolve injections. This target + * is found in both module and injector bindings. */ V visit(LinkedKeyBinding<? extends T> binding); @@ -57,8 +57,8 @@ public interface BindingTargetVisitor<T, V> { V visit(ExposedBinding<? extends T> binding); /** - * Visit an untargetted binding. This target is found only on module bindings. It indicates - * that the injector should use its implicit binding strategies to resolve injections. + * Visit an untargetted binding. This target is found only on module bindings. It indicates that + * the injector should use its implicit binding strategies to resolve injections. */ V visit(UntargettedBinding<? extends T> binding); @@ -69,8 +69,8 @@ public interface BindingTargetVisitor<T, V> { V visit(ConstructorBinding<? extends T> binding); /** - * Visit a binding created from converting a bound instance to a new type. The source binding - * has the same binding annotation but a different type. This target is found only on injector + * Visit a binding created from converting a bound instance to a new type. The source binding has + * the same binding annotation but a different type. This target is found only on injector * bindings. */ V visit(ConvertedConstantBinding<? extends T> binding); diff --git a/core/src/com/google/inject/spi/ConstructorBinding.java b/core/src/com/google/inject/spi/ConstructorBinding.java index 6799941d..4e6e5f59 100644 --- a/core/src/com/google/inject/spi/ConstructorBinding.java +++ b/core/src/com/google/inject/spi/ConstructorBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,6 @@ package com.google.inject.spi; import com.google.inject.Binding; - import java.lang.reflect.Method; import java.util.List; import java.util.Map; @@ -32,17 +31,15 @@ import java.util.Set; */ public interface ConstructorBinding<T> extends Binding<T>, HasDependencies { - /** - * Gets the constructor this binding injects. - */ + /** Gets the constructor this binding injects. */ InjectionPoint getConstructor(); /** * Returns all instance method and field injection points on {@code type}. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. */ Set<InjectionPoint> getInjectableMembers(); @@ -54,4 +51,4 @@ public interface ConstructorBinding<T> extends Binding<T>, HasDependencies { */ Map<Method, List<org.aopalliance.intercept.MethodInterceptor>> getMethodInterceptors(); /*end[AOP]*/ -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/ConvertedConstantBinding.java b/core/src/com/google/inject/spi/ConvertedConstantBinding.java index 5582fb6a..ebafdf60 100644 --- a/core/src/com/google/inject/spi/ConvertedConstantBinding.java +++ b/core/src/com/google/inject/spi/ConvertedConstantBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.spi; import com.google.inject.Binding; import com.google.inject.Key; - import java.util.Set; /** @@ -30,14 +29,12 @@ import java.util.Set; */ public interface ConvertedConstantBinding<T> extends Binding<T>, HasDependencies { - /** - * Returns the converted value. - */ + /** Returns the converted value. */ T getValue(); /** * Returns the type converter binding used to convert the constant. - * + * * @since 3.0 */ TypeConverterBinding getTypeConverterBinding(); @@ -48,8 +45,7 @@ public interface ConvertedConstantBinding<T> extends Binding<T>, HasDependencies */ Key<String> getSourceKey(); - /** - * Returns a singleton set containing only the converted key. - */ + /** Returns a singleton set containing only the converted key. */ + @Override Set<Dependency<?>> getDependencies(); } diff --git a/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java b/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java index b5172720..edaa6603 100644 --- a/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java +++ b/core/src/com/google/inject/spi/DefaultBindingScopingVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,40 +17,40 @@ package com.google.inject.spi; import com.google.inject.Scope; - import java.lang.annotation.Annotation; /** - * No-op visitor for subclassing. All interface methods simply delegate to - * {@link #visitOther()}, returning its result. + * No-op visitor for subclassing. All interface methods simply delegate to {@link #visitOther()}, + * returning its result. * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. - * + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 */ public class DefaultBindingScopingVisitor<V> implements BindingScopingVisitor<V> { - /** - * Default visit implementation. Returns {@code null}. - */ + /** Default visit implementation. Returns {@code null}. */ protected V visitOther() { return null; } + @Override public V visitEagerSingleton() { return visitOther(); } + @Override public V visitScope(Scope scope) { return visitOther(); } + @Override public V visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) { return visitOther(); } + @Override public V visitNoScoping() { return visitOther(); } diff --git a/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java b/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java index 3deb9dd9..5bd10661 100644 --- a/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java +++ b/core/src/com/google/inject/spi/DefaultBindingTargetVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -22,53 +22,59 @@ import com.google.inject.Binding; * No-op visitor for subclassing. All interface methods simply delegate to {@link * #visitOther(Binding)}, returning its result. * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. - * + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 */ public abstract class DefaultBindingTargetVisitor<T, V> implements BindingTargetVisitor<T, V> { - /** - * Default visit implementation. Returns {@code null}. - */ + /** Default visit implementation. Returns {@code null}. */ protected V visitOther(Binding<? extends T> binding) { return null; } + @Override public V visit(InstanceBinding<? extends T> instanceBinding) { return visitOther(instanceBinding); } + @Override public V visit(ProviderInstanceBinding<? extends T> providerInstanceBinding) { return visitOther(providerInstanceBinding); } + @Override public V visit(ProviderKeyBinding<? extends T> providerKeyBinding) { return visitOther(providerKeyBinding); } + @Override public V visit(LinkedKeyBinding<? extends T> linkedKeyBinding) { return visitOther(linkedKeyBinding); } + @Override public V visit(ExposedBinding<? extends T> exposedBinding) { return visitOther(exposedBinding); } + @Override public V visit(UntargettedBinding<? extends T> untargettedBinding) { return visitOther(untargettedBinding); } + @Override public V visit(ConstructorBinding<? extends T> constructorBinding) { return visitOther(constructorBinding); } + @Override public V visit(ConvertedConstantBinding<? extends T> convertedConstantBinding) { return visitOther(convertedConstantBinding); } + @Override @SuppressWarnings("unchecked") public V visit(ProviderBinding<? extends T> providerBinding) { // TODO(cushon): remove raw (Binding) cast when we don't care about javac 6 anymore diff --git a/core/src/com/google/inject/spi/DefaultElementVisitor.java b/core/src/com/google/inject/spi/DefaultElementVisitor.java index 1bbea0d2..1f1aacee 100644 --- a/core/src/com/google/inject/spi/DefaultElementVisitor.java +++ b/core/src/com/google/inject/spi/DefaultElementVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,90 +19,104 @@ package com.google.inject.spi; import com.google.inject.Binding; /** - * No-op visitor for subclassing. All interface methods simply delegate to - * {@link #visitOther(Element)}, returning its result. - * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. + * No-op visitor for subclassing. All interface methods simply delegate to {@link + * #visitOther(Element)}, returning its result. * + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @author sberlin@gmail.com (Sam Berlin) * @since 2.0 */ public abstract class DefaultElementVisitor<V> implements ElementVisitor<V> { - /** - * Default visit implementation. Returns {@code null}. - */ + /** Default visit implementation. Returns {@code null}. */ protected V visitOther(Element element) { return null; } + @Override public V visit(Message message) { return visitOther(message); } + @Override public <T> V visit(Binding<T> binding) { return visitOther(binding); } /*if[AOP]*/ + @Override public V visit(InterceptorBinding interceptorBinding) { return visitOther(interceptorBinding); } /*end[AOP]*/ + @Override public V visit(ScopeBinding scopeBinding) { return visitOther(scopeBinding); } + @Override public V visit(TypeConverterBinding typeConverterBinding) { return visitOther(typeConverterBinding); } + @Override public <T> V visit(ProviderLookup<T> providerLookup) { return visitOther(providerLookup); } + @Override public V visit(InjectionRequest<?> injectionRequest) { return visitOther(injectionRequest); } + @Override public V visit(StaticInjectionRequest staticInjectionRequest) { return visitOther(staticInjectionRequest); } + @Override public V visit(PrivateElements privateElements) { return visitOther(privateElements); } + @Override public <T> V visit(MembersInjectorLookup<T> lookup) { return visitOther(lookup); } + @Override public V visit(TypeListenerBinding binding) { return visitOther(binding); } - + + @Override public V visit(ProvisionListenerBinding binding) { return visitOther(binding); } - + + @Override public V visit(DisableCircularProxiesOption option) { return visitOther(option); } - + + @Override public V visit(RequireExplicitBindingsOption option) { return visitOther(option); } - + + @Override public V visit(RequireAtInjectOnConstructorsOption option) { return visitOther(option); } + @Override public V visit(RequireExactBindingAnnotationsOption option) { return visitOther(option); } + @Override public V visit(ModuleAnnotatedMethodScannerBinding binding) { return visitOther(binding); } diff --git a/core/src/com/google/inject/spi/Dependency.java b/core/src/com/google/inject/spi/Dependency.java index f86e2559..5a084c6a 100644 --- a/core/src/com/google/inject/spi/Dependency.java +++ b/core/src/com/google/inject/spi/Dependency.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; import com.google.inject.Key; import com.google.inject.internal.MoreTypes; - import java.util.List; import java.util.Set; @@ -58,9 +57,7 @@ public final class Dependency<T> { return new Dependency<T>(null, MoreTypes.canonicalizeKey(key), true, -1); } - /** - * Returns the dependencies from the given injection points. - */ + /** Returns the dependencies from the given injection points. */ public static Set<Dependency<?>> forInjectionPoints(Set<InjectionPoint> injectionPoints) { List<Dependency<?>> dependencies = Lists.newArrayList(); for (InjectionPoint injectionPoint : injectionPoints) { @@ -69,16 +66,12 @@ public final class Dependency<T> { return ImmutableSet.copyOf(dependencies); } - /** - * Returns the key to the binding that satisfies this dependency. - */ + /** Returns the key to the binding that satisfies this dependency. */ public Key<T> getKey() { return this.key; } - /** - * Returns true if null is a legal value for this dependency. - */ + /** Returns true if null is a legal value for this dependency. */ public boolean isNullable() { return nullable; } @@ -100,11 +93,13 @@ public final class Dependency<T> { return parameterIndex; } - @Override public int hashCode() { + @Override + public int hashCode() { return Objects.hashCode(injectionPoint, parameterIndex, key); } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (o instanceof Dependency) { Dependency dependency = (Dependency) o; return Objects.equal(injectionPoint, dependency.injectionPoint) @@ -115,7 +110,8 @@ public final class Dependency<T> { } } - @Override public String toString() { + @Override + public String toString() { StringBuilder builder = new StringBuilder(); builder.append(key); if (injectionPoint != null) { diff --git a/core/src/com/google/inject/spi/DependencyAndSource.java b/core/src/com/google/inject/spi/DependencyAndSource.java index ce52aaed..321e9495 100644 --- a/core/src/com/google/inject/spi/DependencyAndSource.java +++ b/core/src/com/google/inject/spi/DependencyAndSource.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2011 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -20,16 +20,19 @@ import com.google.inject.Binder; import com.google.inject.Binding; import com.google.inject.Injector; import com.google.inject.internal.util.StackTraceElements; - import java.lang.reflect.Member; /** - * A combination of a {@link Dependency} and the {@link Binding#getSource() - * source} where the dependency was bound. - * + * A combination of a {@link Dependency} and the {@link Binding#getSource() source} where the + * dependency was bound. + * * @author sameb@google.com (Sam Berlin) * @since 4.0 + * @deprecated The only use of this object is for {@link + * ProvisionListener.ProvisionInvocation#getDependencyChain()} which is also deprecated. This + * object will also be removed in Guice 4.4. */ +@Deprecated public final class DependencyAndSource { private final Dependency<?> dependency; private final Object source; @@ -40,21 +43,19 @@ public final class DependencyAndSource { } /** - * Returns the Dependency, if one exists. For anything that can be referenced - * by {@link Injector#getBinding}, a dependency exists. A dependency will not - * exist (and this will return null) for types initialized with - * {@link Binder#requestInjection} or {@link Injector#injectMembers(Object)}, - * nor will it exist for objects injected into Providers bound with - * LinkedBindingBuilder#toProvider(Provider). + * Returns the Dependency, if one exists. For anything that can be referenced by {@link + * Injector#getBinding}, a dependency exists. A dependency will not exist (and this will return + * null) for types initialized with {@link Binder#requestInjection} or {@link + * Injector#injectMembers(Object)}, nor will it exist for objects injected into Providers bound + * with LinkedBindingBuilder#toProvider(Provider). */ public Dependency<?> getDependency() { return dependency; } /** - * Returns a string describing where this dependency was bound. If the binding - * was just-in-time, there is no valid binding source, so this describes the - * class in question. + * Returns a string describing where this dependency was bound. If the binding was just-in-time, + * there is no valid binding source, so this describes the class in question. */ public String getBindingSource() { if (source instanceof Class) { @@ -76,4 +77,4 @@ public final class DependencyAndSource { return "Source: " + source; } } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/DisableCircularProxiesOption.java b/core/src/com/google/inject/spi/DisableCircularProxiesOption.java index 4193e0ab..ad6812c0 100644 --- a/core/src/com/google/inject/spi/DisableCircularProxiesOption.java +++ b/core/src/com/google/inject/spi/DisableCircularProxiesOption.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,14 +33,17 @@ public final class DisableCircularProxiesOption implements Element { this.source = checkNotNull(source, "source"); } + @Override public Object getSource() { return source; } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).disableCircularProxies(); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } diff --git a/core/src/com/google/inject/spi/Element.java b/core/src/com/google/inject/spi/Element.java index 814ccef8..9b42b7ee 100644 --- a/core/src/com/google/inject/spi/Element.java +++ b/core/src/com/google/inject/spi/Element.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -60,5 +60,4 @@ public interface Element { * element. */ void applyTo(Binder binder); - } diff --git a/core/src/com/google/inject/spi/ElementSource.java b/core/src/com/google/inject/spi/ElementSource.java index 52783c99..5a0d6cc3 100644 --- a/core/src/com/google/inject/spi/ElementSource.java +++ b/core/src/com/google/inject/spi/ElementSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,79 +20,76 @@ import com.google.common.base.Preconditions; import com.google.common.collect.ImmutableList; import com.google.inject.internal.util.StackTraceElements; import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement; - import java.util.List; /** - * Contains information about where and how an {@link Element element} was - * bound. - * <p> - * The {@link #getDeclaringSource() declaring source} refers to a location in - * source code that defines the Guice {@link Element element}. For example, if - * the element is created from a method annotated by {@literal @Provides}, the - * declaring source of element would be the method itself. - * <p> - * The {@link #getStackTrace()} refers to the sequence of calls ends at one of - * {@link com.google.inject.Binder} {@code bindXXX()} methods and eventually - * defines the element. Note that {@link #getStackTrace()} lists - * {@link StackTraceElement StackTraceElements} in reverse chronological order. - * The first element (index zero) is the last method call and the last element - * is the first method invocation. By default, the stack trace is not collected. - * The default behavior can be changed by setting the - * {@code guice_include_stack_traces} flag value. The value can be either - * {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that - * collecting stack traces for every binding can cause a performance hit when - * the injector is created. - * <p> - * The sequence of class names of {@link com.google.inject.Module modules} - * involved in the element creation can be retrieved by - * {@link #getModuleClassNames()}. Similar to {@link #getStackTrace()}, the - * order is reverse chronological. The first module (index 0) is the module that - * installs the {@link Element element}. The last module is the root module. - * <p> - * In order to support the cases where a Guice {@link Element element} is - * created from another Guice {@link Element element} (original) (e.g., by - * {@link Element#applyTo}), it also provides a reference to the original - * element source ({@link #getOriginalElementSource()}). + * Contains information about where and how an {@link Element element} was bound. + * + * <p>The {@link #getDeclaringSource() declaring source} refers to a location in source code that + * defines the Guice {@link Element element}. For example, if the element is created from a method + * annotated by {@literal @Provides}, the declaring source of element would be the method itself. + * + * <p>The {@link #getStackTrace()} refers to the sequence of calls ends at one of {@link + * com.google.inject.Binder} {@code bindXXX()} methods and eventually defines the element. Note that + * {@link #getStackTrace()} lists {@link StackTraceElement StackTraceElements} in reverse + * chronological order. The first element (index zero) is the last method call and the last element + * is the first method invocation. By default, the stack trace is not collected. The default + * behavior can be changed by setting the {@code guice_include_stack_traces} flag value. The value + * can be either {@code OFF}, {@code ONLY_FOR_DECLARING_SOURCE} or {@code COMPLETE}. Note that + * collecting stack traces for every binding can cause a performance hit when the injector is + * created. + * + * <p>The sequence of class names of {@link com.google.inject.Module modules} involved in the + * element creation can be retrieved by {@link #getModuleClassNames()}. Similar to {@link + * #getStackTrace()}, the order is reverse chronological. The first module (index 0) is the module + * that installs the {@link Element element}. The last module is the root module. + * + * <p>In order to support the cases where a Guice {@link Element element} is created from another + * Guice {@link Element element} (original) (e.g., by {@link Element#applyTo}), it also provides a + * reference to the original element source ({@link #getOriginalElementSource()}). * * @since 4.0 */ public final class ElementSource { - /** + /** * The {@link ElementSource source} of element that this element created from (if there is any), * otherwise {@code null}. */ final ElementSource originalElementSource; - + /** The {@link ModuleSource source} of module creates the element. */ final ModuleSource moduleSource; - - /** + + /** * The partial call stack that starts at the last module {@link Module#Configure(Binder) * configure(Binder)} call. The value is empty if stack trace collection is off. */ final InMemoryStackTraceElement[] partialCallStack; - - /** - * Refers to a single location in source code that causes the element creation. It can be any - * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement}, - * etc. For example, if the element is created from a method annotated by {@literal @Provides}, + + /** + * Refers to a single location in source code that causes the element creation. It can be any + * object such as {@link Constructor}, {@link Method}, {@link Field}, {@link StackTraceElement}, + * etc. For example, if the element is created from a method annotated by {@literal @Provides}, * the declaring source of element would be the method itself. */ final Object declaringSource; /** - * Creates a new {@ElementSource} from the given parameters. + * Creates a new {@ElementSource} from the given parameters. + * * @param originalElementSource The source of element that this element created from (if there is - * any), otherwise {@code null}. + * any), otherwise {@code null}. * @param declaringSource the source (in)directly declared the element. * @param moduleSource the moduleSource when the element is bound - * @param partialCallStack the partial call stack from the top module to where the element is - * bound + * @param partialCallStack the partial call stack from the top module to where the element is + * bound */ - ElementSource(/* @Nullable */ ElementSource originalSource, Object declaringSource, - ModuleSource moduleSource, StackTraceElement[] partialCallStack) { + ElementSource( + /* @Nullable */ ElementSource originalSource, + Object declaringSource, + ModuleSource moduleSource, + StackTraceElement[] partialCallStack) { Preconditions.checkNotNull(declaringSource, "declaringSource cannot be null."); Preconditions.checkNotNull(moduleSource, "moduleSource cannot be null."); Preconditions.checkNotNull(partialCallStack, "partialCallStack cannot be null."); @@ -101,7 +98,7 @@ public final class ElementSource { this.moduleSource = moduleSource; this.partialCallStack = StackTraceElements.convertToInMemoryStackTraceElement(partialCallStack); } - + /** * Returns the {@link ElementSource} of the element this was created or copied from. If this was * not created or copied from another element, returns {@code null}. @@ -109,22 +106,22 @@ public final class ElementSource { public ElementSource getOriginalElementSource() { return originalElementSource; } - + /** - * Returns a single location in source code that defines the element. It can be any object - * such as {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method}, - * {@link java.lang.reflect.Field}, {@link StackTraceElement}, etc. For - * example, if the element is created from a method annotated by {@literal @Provides}, the - * declaring source of element would be the method itself. + * Returns a single location in source code that defines the element. It can be any object such as + * {@link java.lang.reflect.Constructor}, {@link java.lang.reflect.Method}, {@link + * java.lang.reflect.Field}, {@link StackTraceElement}, etc. For example, if the element is + * created from a method annotated by {@literal @Provides}, the declaring source of element would + * be the method itself. */ public Object getDeclaringSource() { return declaringSource; } - + /** - * Returns the class names of modules involved in creating this {@link Element}. The first - * element (index 0) is the class name of module that defined the element, and the last element - * is the class name of root module. + * Returns the class names of modules involved in creating this {@link Element}. The first element + * (index 0) is the class name of module that defined the element, and the last element is the + * class name of root module. */ public List<String> getModuleClassNames() { return moduleSource.getModuleClassNames(); @@ -134,18 +131,18 @@ public final class ElementSource { * Returns the position of {@link com.google.inject.Module#configure configure(Binder)} method * call in the {@link #getStackTrace stack trace} for modules that their classes returned by * {@link #getModuleClassNames}. For example, if the stack trace looks like the following: - * <p> - * {@code - * 0 - Binder.bind(), - * 1 - ModuleTwo.configure(), - * 2 - Binder.install(), - * 3 - ModuleOne.configure(), - * 4 - theRest(). - * } - * <p> - * 1 and 3 are returned. - * <p> - * In the cases where stack trace is not available (i.e., the stack trace was not collected), + * + * <ol> + * <li>{@code Binder.bind()} + * <li>{@code ModuleTwo.configure()} + * <li>{@code Binder.install()} + * <li>{@code ModuleOne.configure()} + * <li>{@code theRest(). + * </ol> + * + * <p>1 and 3 are returned. + * + * <p>In the cases where stack trace is not available (i.e., the stack trace was not collected), * it returns -1 for all module positions. */ public List<Integer> getModuleConfigurePositionsInStackTrace() { @@ -164,11 +161,11 @@ public final class ElementSource { /** * Returns the sequence of method calls that ends at one of {@link com.google.inject.Binder} - * {@code bindXXX()} methods and eventually defines the element. Note that - * {@link #getStackTrace} lists {@link StackTraceElement StackTraceElements} in reverse - * chronological order. The first element (index zero) is the last method call and the last - * element is the first method invocation. In the cases where stack trace is not available - * (i.e.,the stack trace was not collected), it returns an empty array. + * {@code bindXXX()} methods and eventually defines the element. Note that {@link #getStackTrace} + * lists {@link StackTraceElement StackTraceElements} in reverse chronological order. The first + * element (index zero) is the last method call and the last element is the first method + * invocation. In the cases where stack trace is not available (i.e.,the stack trace was not + * collected), it returns an empty array. */ public StackTraceElement[] getStackTrace() { int modulesCallStackSize = moduleSource.getStackTraceSize(); @@ -176,15 +173,16 @@ public final class ElementSource { int size = moduleSource.getStackTraceSize() + chunkSize; StackTraceElement[] callStack = new StackTraceElement[size]; System.arraycopy( - StackTraceElements.convertToStackTraceElement(partialCallStack), 0, callStack, 0, + StackTraceElements.convertToStackTraceElement(partialCallStack), + 0, + callStack, + 0, chunkSize); System.arraycopy(moduleSource.getStackTrace(), 0, callStack, chunkSize, modulesCallStackSize); return callStack; } - /** - * Returns {@code getDeclaringSource().toString()} value. - */ + /** Returns {@code getDeclaringSource().toString()} value. */ @Override public String toString() { return getDeclaringSource().toString(); diff --git a/core/src/com/google/inject/spi/ElementVisitor.java b/core/src/com/google/inject/spi/ElementVisitor.java index bc0d9106..b99f884a 100644 --- a/core/src/com/google/inject/spi/ElementVisitor.java +++ b/core/src/com/google/inject/spi/ElementVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,59 +23,42 @@ import com.google.inject.Inject; /** * Visit elements. * - * @param <V> any type to be returned by the visit method. Use {@link Void} with - * {@code return null} if no return type is needed. - * + * @param <V> any type to be returned by the visit method. Use {@link Void} with {@code return null} + * if no return type is needed. * @since 2.0 */ public interface ElementVisitor<V> { /** - * Visit a mapping from a key (type and optional annotation) to the strategy for getting - * instances of the type. + * Visit a mapping from a key (type and optional annotation) to the strategy for getting instances + * of the type. */ <T> V visit(Binding<T> binding); /*if[AOP]*/ - /** - * Visit a registration of interceptors for matching methods of matching classes. - */ + /** Visit a registration of interceptors for matching methods of matching classes. */ V visit(InterceptorBinding binding); /*end[AOP]*/ - /** - * Visit a registration of a scope annotation with the scope that implements it. - */ + /** Visit a registration of a scope annotation with the scope that implements it. */ V visit(ScopeBinding binding); - /** - * Visit a registration of type converters for matching target types. - */ + /** Visit a registration of type converters for matching target types. */ V visit(TypeConverterBinding binding); - /** - * Visit a request to inject the instance fields and methods of an instance. - */ + /** Visit a request to inject the instance fields and methods of an instance. */ V visit(InjectionRequest<?> request); - /** - * Visit a request to inject the static fields and methods of type. - */ + /** Visit a request to inject the static fields and methods of type. */ V visit(StaticInjectionRequest request); - /** - * Visit a lookup of the provider for a type. - */ + /** Visit a lookup of the provider for a type. */ <T> V visit(ProviderLookup<T> lookup); - /** - * Visit a lookup of the members injector. - */ + /** Visit a lookup of the members injector. */ <T> V visit(MembersInjectorLookup<T> lookup); - /** - * Visit an error message and the context in which it occured. - */ + /** Visit an error message and the context in which it occured. */ V visit(Message message); /** @@ -84,35 +67,33 @@ public interface ElementVisitor<V> { */ V visit(PrivateElements elements); - /** - * Visit an injectable type listener binding. - */ + /** Visit an injectable type listener binding. */ V visit(TypeListenerBinding binding); - + /** * Visit a provision listener binding. * * @since 4.0 */ V visit(ProvisionListenerBinding binding); - + /** * Visit a require explicit bindings command. - * + * * @since 3.0 */ V visit(RequireExplicitBindingsOption option); - + /** * Visit a disable circular proxies command. - * + * * @since 3.0 */ V visit(DisableCircularProxiesOption option); - + /** * Visit a require explicit {@literal @}{@link Inject} command. - * + * * @since 4.0 */ V visit(RequireAtInjectOnConstructorsOption option); diff --git a/core/src/com/google/inject/spi/Elements.java b/core/src/com/google/inject/spi/Elements.java index 9348276b..724fa1ca 100644 --- a/core/src/com/google/inject/spi/Elements.java +++ b/core/src/com/google/inject/spi/Elements.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,7 +50,6 @@ import com.google.inject.internal.ProviderMethodsModule; import com.google.inject.internal.util.SourceProvider; import com.google.inject.internal.util.StackTraceElements; import com.google.inject.matcher.Matcher; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; import java.util.Arrays; @@ -69,41 +68,35 @@ import java.util.Set; */ public final class Elements { - private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR - = new DefaultBindingTargetVisitor<Object, Object>() { - @Override public Object visit(InstanceBinding<?> binding) { - return binding.getInstance(); - } + private static final BindingTargetVisitor<Object, Object> GET_INSTANCE_VISITOR = + new DefaultBindingTargetVisitor<Object, Object>() { + @Override + public Object visit(InstanceBinding<?> binding) { + return binding.getInstance(); + } - @Override protected Object visitOther(Binding<?> binding) { - throw new IllegalArgumentException(); - } - }; + @Override + protected Object visitOther(Binding<?> binding) { + throw new IllegalArgumentException(); + } + }; - /** - * Records the elements executed by {@code modules}. - */ + /** Records the elements executed by {@code modules}. */ public static List<Element> getElements(Module... modules) { return getElements(Stage.DEVELOPMENT, Arrays.asList(modules)); } - /** - * Records the elements executed by {@code modules}. - */ + /** Records the elements executed by {@code modules}. */ public static List<Element> getElements(Stage stage, Module... modules) { return getElements(stage, Arrays.asList(modules)); } - /** - * Records the elements executed by {@code modules}. - */ + /** Records the elements executed by {@code modules}. */ public static List<Element> getElements(Iterable<? extends Module> modules) { return getElements(Stage.DEVELOPMENT, modules); } - /** - * Records the elements executed by {@code modules}. - */ + /** Records the elements executed by {@code modules}. */ public static List<Element> getElements(Stage stage, Iterable<? extends Module> modules) { RecordingBinder binder = new RecordingBinder(stage); for (Module module : modules) { @@ -133,9 +126,7 @@ public final class Elements { } } - /** - * Returns the module composed of {@code elements}. - */ + /** Returns the module composed of {@code elements}. */ public static Module getModule(final Iterable<? extends Element> elements) { return new ElementsAsModule(elements); } @@ -164,11 +155,13 @@ public final class Elements { private final Object source; /** The current modules stack */ private ModuleSource moduleSource = null; + private final SourceProvider sourceProvider; private final Set<ModuleAnnotatedMethodScanner> scanners; /** The binder where exposed bindings will be created */ private final RecordingBinder parent; + private final PrivateElementsImpl privateElements; /** All children private binders, so we can scan through them. */ @@ -180,9 +173,14 @@ public final class Elements { this.scanners = Sets.newLinkedHashSet(); this.elements = Lists.newArrayList(); this.source = null; - this.sourceProvider = SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses( - Elements.class, RecordingBinder.class, AbstractModule.class, - ConstantBindingBuilderImpl.class, AbstractBindingBuilder.class, BindingBuilder.class); + this.sourceProvider = + SourceProvider.DEFAULT_INSTANCE.plusSkippedClasses( + Elements.class, + RecordingBinder.class, + AbstractModule.class, + ConstantBindingBuilderImpl.class, + AbstractBindingBuilder.class, + BindingBuilder.class); this.parent = null; this.privateElements = null; this.privateBinders = Lists.newArrayList(); @@ -225,8 +223,8 @@ public final class Elements { Matcher<? super Class<?>> classMatcher, Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors) { - elements.add(new InterceptorBinding( - getElementSource(), classMatcher, methodMatcher, interceptors)); + elements.add( + new InterceptorBinding(getElementSource(), classMatcher, methodMatcher, interceptors)); } /*end[AOP]*/ @@ -243,31 +241,37 @@ public final class Elements { @Override public <T> void requestInjection(TypeLiteral<T> type, T instance) { - elements.add(new InjectionRequest<T>(getElementSource(), MoreTypes.canonicalizeForKey(type), - instance)); + elements.add( + new InjectionRequest<T>( + getElementSource(), MoreTypes.canonicalizeForKey(type), instance)); } @Override public <T> MembersInjector<T> getMembersInjector(final TypeLiteral<T> typeLiteral) { - final MembersInjectorLookup<T> element = new MembersInjectorLookup<T>(getElementSource(), - MoreTypes.canonicalizeForKey(typeLiteral)); + final MembersInjectorLookup<T> element = + new MembersInjectorLookup<T>( + getElementSource(), MoreTypes.canonicalizeForKey(typeLiteral)); elements.add(element); return element.getMembersInjector(); } + @Override public <T> MembersInjector<T> getMembersInjector(Class<T> type) { return getMembersInjector(TypeLiteral.get(type)); } + @Override public void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher, TypeListener listener) { elements.add(new TypeListenerBinding(getElementSource(), listener, typeMatcher)); } - - public void bindListener(Matcher<? super Binding<?>> bindingMatcher, - ProvisionListener... listeners) { + + @Override + public void bindListener( + Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners) { elements.add(new ProvisionListenerBinding(getElementSource(), bindingMatcher, listeners)); } + @Override public void requestStaticInjection(Class<?>... types) { for (Class<?> type : types) { elements.add(new StaticInjectionRequest(getElementSource(), type)); @@ -275,10 +279,9 @@ public final class Elements { } /** - * Applies all scanners to the modules we've installed. We skip certain - * PrivateModules because store them in more than one Modules map and only - * want to process them through one of the maps. (They're stored in both - * maps to prevent a module from being installed more than once.) + * Applies all scanners to the modules we've installed. We skip certain PrivateModules because + * store them in more than one Modules map and only want to process them through one of the + * maps. (They're stored in both maps to prevent a module from being installed more than once.) */ void scanForAnnotatedMethods() { for (ModuleAnnotatedMethodScanner scanner : scanners) { @@ -293,7 +296,7 @@ public final class Elements { moduleSource = entry.getValue().moduleSource; try { info.binder.install(ProviderMethodsModule.forModule(module, scanner)); - } catch(RuntimeException e) { + } catch (RuntimeException e) { Collection<Message> messages = Errors.getMessagesFromThrowable(e); if (!messages.isEmpty()) { elements.addAll(messages); @@ -306,6 +309,7 @@ public final class Elements { moduleSource = null; } + @Override public void install(Module module) { if (!modules.containsKey(module)) { RecordingBinder binder = this; @@ -354,64 +358,78 @@ public final class Elements { } } + @Override public Stage currentStage() { return stage; } + @Override public void addError(String message, Object... arguments) { elements.add(new Message(getElementSource(), Errors.format(message, arguments))); } + @Override public void addError(Throwable t) { String message = "An exception was caught and reported. Message: " + t.getMessage(); elements.add(new Message(ImmutableList.of((Object) getElementSource()), message, t)); } + @Override public void addError(Message message) { elements.add(message); } + @Override public <T> AnnotatedBindingBuilder<T> bind(Key<T> key) { BindingBuilder<T> builder = new BindingBuilder<T>(this, elements, getElementSource(), MoreTypes.canonicalizeKey(key)); return builder; } + @Override public <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) { return bind(Key.get(typeLiteral)); } + @Override public <T> AnnotatedBindingBuilder<T> bind(Class<T> type) { return bind(Key.get(type)); } + @Override public AnnotatedConstantBindingBuilder bindConstant() { return new ConstantBindingBuilderImpl<Void>(this, elements, getElementSource()); } + @Override public <T> Provider<T> getProvider(final Key<T> key) { return getProvider(Dependency.get(key)); } + @Override public <T> Provider<T> getProvider(final Dependency<T> dependency) { - final ProviderLookup<T> element = new ProviderLookup<T>(getElementSource(), dependency); + final ProviderLookup<T> element = new ProviderLookup<>(getElementSource(), dependency); elements.add(element); return element.getProvider(); } + @Override public <T> Provider<T> getProvider(Class<T> type) { return getProvider(Key.get(type)); } - public void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter converter) { + @Override + public void convertToTypes( + Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter converter) { elements.add(new TypeConverterBinding(getElementSource(), typeMatcher, converter)); } - public RecordingBinder withSource(final Object source) { + @Override + public RecordingBinder withSource(final Object source) { return source == this.source ? this : new RecordingBinder(this, source, null); } + @Override public RecordingBinder skipSources(Class... classesToSkip) { // if a source is specified explicitly, we don't need to skip sources if (source != null) { @@ -457,6 +475,7 @@ public final class Elements { elements.add(new ModuleAnnotatedMethodScannerBinding(getElementSource(), scanner)); } + @Override public void expose(Key<?> key) { exposeInternal(key); } @@ -473,11 +492,14 @@ public final class Elements { private <T> AnnotatedElementBuilder exposeInternal(Key<T> key) { if (privateElements == null) { - addError("Cannot expose %s on a standard binder. " - + "Exposed bindings are only applicable to private binders.", key); + addError( + "Cannot expose %s on a standard binder. " + + "Exposed bindings are only applicable to private binders.", + key); return new AnnotatedElementBuilder() { @Override public void annotatedWith(Class<? extends Annotation> annotationType) {} + @Override public void annotatedWith(Annotation annotation) {} }; @@ -516,9 +538,9 @@ public final class Elements { declaringSource = originalSource.getDeclaringSource(); } IncludeStackTraceOption stackTraceOption = getIncludeStackTraceOption(); - if (stackTraceOption == IncludeStackTraceOption.COMPLETE || - (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE - && declaringSource == null)) { + if (stackTraceOption == IncludeStackTraceOption.COMPLETE + || (stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE + && declaringSource == null)) { callStack = new Throwable().getStackTrace(); } if (stackTraceOption == IncludeStackTraceOption.COMPLETE) { @@ -526,8 +548,8 @@ public final class Elements { } if (declaringSource == null) { // So 'source' and 'originalSource' are null otherwise declaringSource has some value - if (stackTraceOption == IncludeStackTraceOption.COMPLETE || - stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) { + if (stackTraceOption == IncludeStackTraceOption.COMPLETE + || stackTraceOption == IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE) { // With the above conditions and assignments 'callStack' is non-null declaringSource = sourceProvider.get(callStack); } else { // or if (stackTraceOption == IncludeStackTraceOptions.OFF) @@ -536,14 +558,13 @@ public final class Elements { } } // Build the binding call stack - return new ElementSource( - originalSource, declaringSource, moduleSource, partialCallStack); + return new ElementSource(originalSource, declaringSource, moduleSource, partialCallStack); } /** * Removes the {@link #moduleSource} call stack from the beginning of current call stack. It - * also removes the last two elements in order to make {@link #install(Module)} the last call - * in the call stack. + * also removes the last two elements in order to make {@link #install(Module)} the last call in + * the call stack. */ private StackTraceElement[] getPartialCallStack(StackTraceElement[] callStack) { int toSkip = 0; @@ -558,7 +579,8 @@ public final class Elements { return partialCallStack; } - @Override public String toString() { + @Override + public String toString() { return "Binder"; } } diff --git a/core/src/com/google/inject/spi/ExposedBinding.java b/core/src/com/google/inject/spi/ExposedBinding.java index 16a569eb..501d8845 100644 --- a/core/src/com/google/inject/spi/ExposedBinding.java +++ b/core/src/com/google/inject/spi/ExposedBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,13 +27,10 @@ import com.google.inject.Binding; */ public interface ExposedBinding<T> extends Binding<T>, HasDependencies { - /** - * Returns the enclosed environment that holds the original binding. - */ + /** Returns the enclosed environment that holds the original binding. */ PrivateElements getPrivateElements(); - /** - * Unsupported. Always throws {@link UnsupportedOperationException}. - */ + /** Unsupported. Always throws {@link UnsupportedOperationException}. */ + @Override void applyTo(Binder binder); -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/HasDependencies.java b/core/src/com/google/inject/spi/HasDependencies.java index 77a55231..f28f1a3e 100644 --- a/core/src/com/google/inject/spi/HasDependencies.java +++ b/core/src/com/google/inject/spi/HasDependencies.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -31,7 +31,7 @@ public interface HasDependencies { * Returns the known dependencies for this type. If this has dependencies whose values are not * known statically, a dependency for the {@link com.google.inject.Injector Injector} will be * included in the returned set. - * + * * @return a possibly empty set */ Set<Dependency<?>> getDependencies(); diff --git a/core/src/com/google/inject/spi/InjectionPoint.java b/core/src/com/google/inject/spi/InjectionPoint.java index 267e0abb..2a302a4f 100644 --- a/core/src/com/google/inject/spi/InjectionPoint.java +++ b/core/src/com/google/inject/spi/InjectionPoint.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,11 @@ package com.google.inject.spi; import static com.google.inject.internal.MoreTypes.getRawType; +import com.google.common.collect.ComparisonChain; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import com.google.common.collect.Ordering; import com.google.inject.ConfigurationException; import com.google.inject.Inject; import com.google.inject.Key; @@ -30,7 +32,6 @@ import com.google.inject.internal.Errors; import com.google.inject.internal.ErrorsException; import com.google.inject.internal.Nullability; import com.google.inject.internal.util.Classes; - import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; @@ -58,7 +59,7 @@ import java.util.logging.Logger; * @since 2.0 */ public final class InjectionPoint { - + private static final Logger logger = Logger.getLogger(InjectionPoint.class.getName()); private final boolean optional; @@ -77,8 +78,8 @@ public final class InjectionPoint { this.member = constructor; this.declaringType = declaringType; this.optional = false; - this.dependencies = forMember( - constructor, declaringType, constructor.getParameterAnnotations()); + this.dependencies = + forMember(constructor, declaringType, constructor.getParameterAnnotations()); } InjectionPoint(TypeLiteral<?> declaringType, Field field, boolean optional) { @@ -99,21 +100,21 @@ public final class InjectionPoint { } errors.throwConfigurationExceptionIfErrorsExist(); - this.dependencies = ImmutableList.<Dependency<?>>of( - newDependency(key, Nullability.allowsNull(annotations), -1)); + this.dependencies = + ImmutableList.<Dependency<?>>of( + newDependency(key, Nullability.allowsNull(annotations), -1)); } - private ImmutableList<Dependency<?>> forMember(Member member, TypeLiteral<?> type, - Annotation[][] paramterAnnotations) { + private ImmutableList<Dependency<?>> forMember( + Member member, TypeLiteral<?> type, Annotation[][] paramterAnnotations) { Errors errors = new Errors(member); - Iterator<Annotation[]> annotationsIterator = Arrays.asList(paramterAnnotations).iterator(); List<Dependency<?>> dependencies = Lists.newArrayList(); int index = 0; for (TypeLiteral<?> parameterType : type.getParameterTypes(member)) { try { - Annotation[] parameterAnnotations = annotationsIterator.next(); + Annotation[] parameterAnnotations = paramterAnnotations[index]; Key<?> key = Annotations.getKey(parameterType, member, parameterAnnotations, errors); dependencies.add(newDependency(key, Nullability.allowsNull(parameterAnnotations), index)); index++; @@ -133,9 +134,7 @@ public final class InjectionPoint { return new Dependency<T>(this, key, allowsNull, parameterIndex); } - /** - * Returns the injected constructor, field, or method. - */ + /** Returns the injected constructor, field, or method. */ public Member getMember() { // TODO: Don't expose the original member (which probably has setAccessible(true)). return member; @@ -161,38 +160,41 @@ public final class InjectionPoint { public boolean isOptional() { return optional; } - + /** * Returns true if the element is annotated with {@literal @}{@link Toolable}. - * + * * @since 3.0 */ public boolean isToolable() { - return ((AnnotatedElement)member).isAnnotationPresent(Toolable.class); + return ((AnnotatedElement) member).isAnnotationPresent(Toolable.class); } /** * Returns the generic type that defines this injection point. If the member exists on a * parameterized type, the result will include more type information than the member's {@link * Member#getDeclaringClass() raw declaring class}. - * + * * @since 3.0 */ public TypeLiteral<?> getDeclaringType() { return declaringType; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { return o instanceof InjectionPoint && member.equals(((InjectionPoint) o).member) && declaringType.equals(((InjectionPoint) o).declaringType); } - @Override public int hashCode() { + @Override + public int hashCode() { return member.hashCode() ^ declaringType.hashCode(); } - @Override public String toString() { + @Override + public String toString() { return Classes.toString(member); } @@ -202,7 +204,6 @@ public final class InjectionPoint { * type literal. * * @param constructor any single constructor present on {@code type}. - * * @since 3.0 */ public static <T> InjectionPoint forConstructor(Constructor<T> constructor) { @@ -214,7 +215,6 @@ public final class InjectionPoint { * * @param constructor any single constructor present on {@code type}. * @param type the concrete type that defines {@code constructor}. - * * @since 3.0 */ public static <T> InjectionPoint forConstructor( @@ -307,13 +307,11 @@ public final class InjectionPoint { } /** - * Returns a new injection point for the specified method of {@code type}. - * This is useful for extensions that need to build dependency graphs from - * arbitrary methods. + * Returns a new injection point for the specified method of {@code type}. This is useful for + * extensions that need to build dependency graphs from arbitrary methods. * * @param method any single method present on {@code type}. * @param type the concrete type that defines {@code method}. - * * @since 4.0 */ public static <T> InjectionPoint forMethod(Method method, TypeLiteral<T> type) { @@ -324,25 +322,25 @@ public final class InjectionPoint { * Returns all static method and field injection points on {@code type}. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as - * a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public static Set<InjectionPoint> forStaticMethodsAndFields(TypeLiteral<?> type) { Errors errors = new Errors(); - + Set<InjectionPoint> result; - + if (type.getRawType().isInterface()) { errors.staticInjectionOnInterface(type.getRawType()); result = null; } else { result = getInjectionPoints(type, true, errors); } - + if (errors.hasErrors()) { throw new ConfigurationException(errors.getMessages()).withPartialValue(result); } @@ -353,12 +351,12 @@ public final class InjectionPoint { * Returns all static method and field injection points on {@code type}. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as - * a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public static Set<InjectionPoint> forStaticMethodsAndFields(Class<?> type) { return forStaticMethodsAndFields(TypeLiteral.get(type)); @@ -368,12 +366,12 @@ public final class InjectionPoint { * Returns all instance method and field injection points on {@code type}. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as - * a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public static Set<InjectionPoint> forInstanceMethodsAndFields(TypeLiteral<?> type) { Errors errors = new Errors(); @@ -388,23 +386,22 @@ public final class InjectionPoint { * Returns all instance method and field injection points on {@code type}. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as - * a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public static Set<InjectionPoint> forInstanceMethodsAndFields(Class<?> type) { return forInstanceMethodsAndFields(TypeLiteral.get(type)); } - /** - * Returns true if the binding annotation is in the wrong place. - */ + /** Returns true if the binding annotation is in the wrong place. */ private static boolean checkForMisplacedBindingAnnotations(Member member, Errors errors) { - Annotation misplacedBindingAnnotation = Annotations.findBindingAnnotation( - errors, member, ((AnnotatedElement) member).getAnnotations()); + Annotation misplacedBindingAnnotation = + Annotations.findBindingAnnotation( + errors, member, ((AnnotatedElement) member).getAnnotations()); if (misplacedBindingAnnotation == null) { return false; } @@ -424,10 +421,8 @@ public final class InjectionPoint { return true; } - /** - * Node in the doubly-linked list of injectable members (fields and methods). - */ - static abstract class InjectableMember { + /** Node in the doubly-linked list of injectable members (fields and methods). */ + abstract static class InjectableMember { final TypeLiteral<?> declaringType; final boolean optional; final boolean jsr330; @@ -452,8 +447,8 @@ public final class InjectionPoint { static class InjectableField extends InjectableMember { final Field field; - InjectableField(TypeLiteral<?> declaringType, Field field, - Annotation atInject) { + + InjectableField(TypeLiteral<?> declaringType, Field field, Annotation atInject) { super(declaringType, atInject); this.field = field; } @@ -467,13 +462,12 @@ public final class InjectionPoint { static class InjectableMethod extends InjectableMember { final Method method; /** - * true if this method overrode a method that was annotated - * with com.google.inject.Inject. used to allow different - * override behavior for guice inject vs javax.inject.Inject + * true if this method overrode a method that was annotated with com.google.inject.Inject. used + * to allow different override behavior for guice inject vs javax.inject.Inject */ boolean overrodeGuiceInject; - InjectableMethod(TypeLiteral<?> declaringType, Method method, - Annotation atInject) { + + InjectableMethod(TypeLiteral<?> declaringType, Method method, Annotation atInject) { super(declaringType, atInject); this.method = method; } @@ -493,9 +487,7 @@ public final class InjectionPoint { return a == null ? member.getAnnotation(Inject.class) : a; } - /** - * Linked list of injectable members. - */ + /** Linked list of injectable members. */ static class InjectableMembers { InjectableMember head; InjectableMember tail; @@ -555,23 +547,19 @@ public final class InjectionPoint { Signature lastSignature; /** - * Removes a method overridden by the given method, if present. In order to - * remain backwards compatible with prior Guice versions, this will *not* - * remove overridden methods if 'alwaysRemove' is false and the overridden - * signature was annotated with a com.google.inject.Inject. - * - * @param method - * The method used to determine what is overridden and should be - * removed. - * @param alwaysRemove - * true if overridden methods should be removed even if they were - * guice @Inject - * @param injectableMethod - * if this method overrode any guice @Inject methods, - * {@link InjectableMethod#overrodeGuiceInject} is set to true + * Removes a method overridden by the given method, if present. In order to remain backwards + * compatible with prior Guice versions, this will *not* remove overridden methods if + * 'alwaysRemove' is false and the overridden signature was annotated with a + * com.google.inject.Inject. + * + * @param method The method used to determine what is overridden and should be removed. + * @param alwaysRemove true if overridden methods should be removed even if they were + * guice @Inject + * @param injectableMethod if this method overrode any guice @Inject methods, {@link + * InjectableMethod#overrodeGuiceInject} is set to true */ - boolean removeIfOverriddenBy(Method method, boolean alwaysRemove, - InjectableMethod injectableMethod) { + boolean removeIfOverriddenBy( + Method method, boolean alwaysRemove, InjectableMethod injectableMethod) { if (position == Position.TOP) { // If we're at the top of the hierarchy, there's nothing to override. return false; @@ -580,13 +568,18 @@ public final class InjectionPoint { if (bySignature == null) { // We encountered a method in a subclass. Time to index the // methods in the parent class. - bySignature = new HashMap<Signature, List<InjectableMethod>>(); - for (InjectableMember member = injectableMembers.head; member != null; + bySignature = new HashMap<>(); + for (InjectableMember member = injectableMembers.head; + member != null; member = member.next) { - if (!(member instanceof InjectableMethod)) continue; + if (!(member instanceof InjectableMethod)) { + continue; + } InjectableMethod im = (InjectableMethod) member; - if (im.isFinal()) continue; - List<InjectableMethod> methods = new ArrayList<InjectableMethod>(); + if (im.isFinal()) { + continue; + } + List<InjectableMethod> methods = new ArrayList<>(); methods.add(im); bySignature.put(new Signature(im.method), methods); } @@ -597,19 +590,18 @@ public final class InjectionPoint { List<InjectableMethod> methods = bySignature.get(signature); boolean removed = false; if (methods != null) { - for (Iterator<InjectableMethod> iterator = methods.iterator(); - iterator.hasNext();) { + for (Iterator<InjectableMethod> iterator = methods.iterator(); iterator.hasNext(); ) { InjectableMethod possiblyOverridden = iterator.next(); if (overrides(method, possiblyOverridden.method)) { boolean wasGuiceInject = - !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject; - if(injectableMethod != null) { + !possiblyOverridden.jsr330 || possiblyOverridden.overrodeGuiceInject; + if (injectableMethod != null) { injectableMethod.overrodeGuiceInject = wasGuiceInject; } // Only actually remove the methods if we want to force // remove or if the signature never specified @com.google.inject.Inject // somewhere. - if(alwaysRemove || !wasGuiceInject) { + if (alwaysRemove || !wasGuiceInject) { removed = true; iterator.remove(); injectableMembers.remove(possiblyOverridden); @@ -621,23 +613,25 @@ public final class InjectionPoint { } /** - * Adds the given method to the list of injection points. Keeps track of it in this index - * in case it gets overridden. + * Adds the given method to the list of injection points. Keeps track of it in this index in + * case it gets overridden. */ void add(InjectableMethod injectableMethod) { injectableMembers.add(injectableMethod); - if (position == Position.BOTTOM - || injectableMethod.isFinal()) { + if (position == Position.BOTTOM || injectableMethod.isFinal()) { // This method can't be overridden, so there's no need to index it. return; } if (bySignature != null) { // Try to reuse the signature we created during removal - Signature signature = injectableMethod.method == lastMethod - ? lastSignature : new Signature(injectableMethod.method); + @SuppressWarnings("ReferenceEquality") + Signature signature = + injectableMethod.method == lastMethod + ? lastSignature + : new Signature(injectableMethod.method); List<InjectableMethod> methods = bySignature.get(signature); if (methods == null) { - methods = new ArrayList<InjectableMethod>(); + methods = new ArrayList<>(); bySignature.put(signature, methods); } methods.add(injectableMethod); @@ -648,13 +642,14 @@ public final class InjectionPoint { /** * Returns an ordered, immutable set of injection points for the given type. Members in * superclasses come before members in subclasses. Within a class, fields come before methods. - * Overridden methods are filtered out. + * Overridden methods are filtered out. The order of fields/methods within a class is consistent + * but undefined. * * @param statics true is this method should return static members, false for instance members * @param errors used to record errors */ - private static Set<InjectionPoint> getInjectionPoints(final TypeLiteral<?> type, - boolean statics, Errors errors) { + private static Set<InjectionPoint> getInjectionPoints( + final TypeLiteral<?> type, boolean statics, Errors errors) { InjectableMembers injectableMembers = new InjectableMembers(); OverrideIndex overrideIndex = null; @@ -672,7 +667,7 @@ public final class InjectionPoint { TypeLiteral<?> current = hierarchy.get(i); - for (Field field : current.getRawType().getDeclaredFields()) { + for (Field field : getDeclaredFields(current)) { if (Modifier.isStatic(field.getModifiers()) == statics) { Annotation atInject = getAtInject(field); if (atInject != null) { @@ -685,22 +680,25 @@ public final class InjectionPoint { } } - for (Method method : current.getRawType().getDeclaredMethods()) { + for (Method method : getDeclaredMethods(current)) { if (isEligibleForInjection(method, statics)) { Annotation atInject = getAtInject(method); if (atInject != null) { - InjectableMethod injectableMethod = new InjectableMethod( - current, method, atInject); + InjectableMethod injectableMethod = new InjectableMethod(current, method, atInject); if (checkForMisplacedBindingAnnotations(method, errors) || !isValidMethod(injectableMethod, errors)) { if (overrideIndex != null) { - boolean removed = overrideIndex.removeIfOverriddenBy(method, false, injectableMethod); - if(removed) { - logger.log(Level.WARNING, "Method: {0} is not a valid injectable method (" - + "because it either has misplaced binding annotations " - + "or specifies type parameters) but is overriding a method that is valid. " - + "Because it is not valid, the method will not be injected. " - + "To fix this, make the method a valid injectable method.", method); + boolean removed = + overrideIndex.removeIfOverriddenBy(method, false, injectableMethod); + if (removed) { + logger.log( + Level.WARNING, + "Method: {0} is not a valid injectable method (" + + "because it either has misplaced binding annotations " + + "or specifies type parameters) but is overriding a method that is " + + "valid. Because it is not valid, the method will not be injected. " + + "To fix this, make the method a valid injectable method.", + method); } } continue; @@ -717,20 +715,23 @@ public final class InjectionPoint { */ overrideIndex = new OverrideIndex(injectableMembers); } else { - // Forcibly remove the overriden method, otherwise we'll inject + // Forcibly remove the overridden method, otherwise we'll inject // it twice. overrideIndex.removeIfOverriddenBy(method, true, injectableMethod); } overrideIndex.add(injectableMethod); } } else { - if(overrideIndex != null) { + if (overrideIndex != null) { boolean removed = overrideIndex.removeIfOverriddenBy(method, false, null); - if(removed) { - logger.log(Level.WARNING, "Method: {0} is not annotated with @Inject but " - + "is overriding a method that is annotated with @javax.inject.Inject. Because " - + "it is not annotated with @Inject, the method will not be injected. " - + "To fix this, annotate the method with @Inject.", method); + if (removed) { + logger.log( + Level.WARNING, + "Method: {0} is not annotated with @Inject but " + + "is overriding a method that is annotated with @javax.inject.Inject." + + "Because it is not annotated with @Inject, the method will not be " + + "injected. To fix this, annotate the method with @Inject.", + method); } } } @@ -743,8 +744,7 @@ public final class InjectionPoint { } ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder(); - for (InjectableMember im = injectableMembers.head; im != null; - im = im.next) { + for (InjectableMember im = injectableMembers.head; im != null; im = im.next) { try { builder.add(im.toInjectionPoint()); } catch (ConfigurationException ignorable) { @@ -756,22 +756,86 @@ public final class InjectionPoint { return builder.build(); } - /** - * Returns true if the method is eligible to be injected. This is different than - * {@link #isValidMethod}, because ineligibility will not drop a method - * from being injected if a superclass was eligible & valid. - * Bridge & synthetic methods are excluded from eligibility for two reasons: - * - * <p>Prior to Java8, javac would generate these methods in subclasses without - * annotations, which means this would accidentally stop injecting a method - * annotated with {@link javax.inject.Inject}, since the spec says to stop - * injecting if a subclass isn't annotated with it. - * - * <p>Starting at Java8, javac copies the annotations to the generated subclass - * method, except it leaves out the generic types. If this considered it a valid - * injectable method, this would eject the parent's overridden method that had the - * proper generic types, and would use invalid injectable parameters as a result. - * + private static Field[] getDeclaredFields(TypeLiteral<?> type) { + Field[] fields = type.getRawType().getDeclaredFields(); + Arrays.sort(fields, FIELD_ORDERING); + return fields; + } + + private static Method[] getDeclaredMethods(TypeLiteral<?> type) { + Method[] methods = type.getRawType().getDeclaredMethods(); + Arrays.sort(methods, METHOD_ORDERING); + return methods; + } + + /** + * An ordering suitable for comparing two classes if they are loaded by the same classloader + * + * <p>Within a single classloader there can only be one class with a given name, so we just + * compare the names. + */ + private static final Ordering<Class<?>> CLASS_ORDERING = + new Ordering<Class<?>>() { + @Override + public int compare(Class<?> o1, Class<?> o2) { + return o1.getName().compareTo(o2.getName()); + } + }; + + /** + * An ordering suitable for comparing two fields if they are owned by the same class. + * + * <p>Within a single class it is sufficent to compare the non-generic field signature which + * consists of the field name and type. + */ + private static final Ordering<Field> FIELD_ORDERING = + new Ordering<Field>() { + @Override + public int compare(Field left, Field right) { + return ComparisonChain.start() + .compare(left.getName(), right.getName()) + .compare(left.getType(), right.getType(), CLASS_ORDERING) + .result(); + } + }; + + /** + * An ordering suitable for comparing two methods if they are owned by the same class. + * + * <p>Within a single class it is sufficient to compare the non-generic method signature which + * consists of the name, return type and parameter types. + */ + private static final Ordering<Method> METHOD_ORDERING = + new Ordering<Method>() { + @Override + public int compare(Method left, Method right) { + return ComparisonChain.start() + .compare(left.getName(), right.getName()) + .compare(left.getReturnType(), right.getReturnType(), CLASS_ORDERING) + .compare( + Arrays.asList(left.getParameterTypes()), + Arrays.asList(right.getParameterTypes()), + CLASS_ORDERING.lexicographical()) + .result(); + } + }; + + /** + * Returns true if the method is eligible to be injected. This is different than {@link + * #isValidMethod}, because ineligibility will not drop a method from being injected if a + * superclass was eligible & valid. Bridge & synthetic methods are excluded from eligibility for + * two reasons: + * + * <p>Prior to Java8, javac would generate these methods in subclasses without annotations, which + * means this would accidentally stop injecting a method annotated with {@link + * javax.inject.Inject}, since the spec says to stop injecting if a subclass isn't annotated with + * it. + * + * <p>Starting at Java8, javac copies the annotations to the generated subclass method, except it + * leaves out the generic types. If this considered it a valid injectable method, this would eject + * the parent's overridden method that had the proper generic types, and would use invalid + * injectable parameters as a result. + * * <p>The fix for both is simply to ignore these synthetic bridge methods. */ private static boolean isEligibleForInjection(Method method, boolean statics) { @@ -780,8 +844,7 @@ public final class InjectionPoint { && !method.isSynthetic(); } - private static boolean isValidMethod(InjectableMethod injectableMethod, - Errors errors) { + private static boolean isValidMethod(InjectableMethod injectableMethod, Errors errors) { boolean result = true; if (injectableMethod.jsr330) { Method method = injectableMethod.method; @@ -798,7 +861,7 @@ public final class InjectionPoint { } private static List<TypeLiteral<?>> hierarchyFor(TypeLiteral<?> type) { - List<TypeLiteral<?>> hierarchy = new ArrayList<TypeLiteral<?>>(); + List<TypeLiteral<?>> hierarchy = new ArrayList<>(); TypeLiteral<?> current = type; while (current.getRawType() != Object.class) { hierarchy.add(current); @@ -824,9 +887,7 @@ public final class InjectionPoint { return a.getDeclaringClass().getPackage().equals(b.getDeclaringClass().getPackage()); } - /** - * A method signature. Used to handle method overridding. - */ + /** A method signature. Used to handle method overridding. */ static class Signature { final String name; @@ -845,11 +906,13 @@ public final class InjectionPoint { this.hash = h; } - @Override public int hashCode() { + @Override + public int hashCode() { return this.hash; } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (!(o instanceof Signature)) { return false; } diff --git a/core/src/com/google/inject/spi/InjectionRequest.java b/core/src/com/google/inject/spi/InjectionRequest.java index f80e37a4..8fbd16df 100644 --- a/core/src/com/google/inject/spi/InjectionRequest.java +++ b/core/src/com/google/inject/spi/InjectionRequest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,13 +21,13 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Binder; import com.google.inject.ConfigurationException; import com.google.inject.TypeLiteral; - import java.util.Set; /** * A request to inject the instance fields and methods of an instance. Requests are created * explicitly in a module using {@link com.google.inject.Binder#requestInjection(Object) * requestInjection()} statements: + * * <pre> * requestInjection(serviceInstance);</pre> * @@ -46,6 +46,7 @@ public final class InjectionRequest<T> implements Element { this.instance = checkNotNull(instance, "instance"); } + @Override public Object getSource() { return source; } @@ -63,21 +64,23 @@ public final class InjectionRequest<T> implements Element { * this request. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on the class of {@code - * instance}, such as a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * instance}, such as a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException { return InjectionPoint.forInstanceMethodsAndFields(instance.getClass()); } + @Override public <R> R acceptVisitor(ElementVisitor<R> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).requestInjection(type, instance); } diff --git a/core/src/com/google/inject/spi/InstanceBinding.java b/core/src/com/google/inject/spi/InstanceBinding.java index 2e2270cf..478b0850 100644 --- a/core/src/com/google/inject/spi/InstanceBinding.java +++ b/core/src/com/google/inject/spi/InstanceBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,7 +17,6 @@ package com.google.inject.spi; import com.google.inject.Binding; - import java.util.Set; /** @@ -28,9 +27,7 @@ import java.util.Set; */ public interface InstanceBinding<T> extends Binding<T>, HasDependencies { - /** - * Returns the user-supplied instance. - */ + /** Returns the user-supplied instance. */ T getInstance(); /** @@ -40,5 +37,4 @@ public interface InstanceBinding<T> extends Binding<T>, HasDependencies { * @return a possibly empty set */ Set<InjectionPoint> getInjectionPoints(); - } diff --git a/core/src/com/google/inject/spi/InterceptorBinding.java b/core/src/com/google/inject/spi/InterceptorBinding.java index a16e701b..49e6349b 100644 --- a/core/src/com/google/inject/spi/InterceptorBinding.java +++ b/core/src/com/google/inject/spi/InterceptorBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,16 +21,15 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.common.collect.ImmutableList; import com.google.inject.Binder; import com.google.inject.matcher.Matcher; - -import org.aopalliance.intercept.MethodInterceptor; - import java.lang.reflect.Method; import java.util.List; +import org.aopalliance.intercept.MethodInterceptor; /** * Registration of interceptors for matching methods of matching classes. Instances are created - * explicitly in a module using {@link com.google.inject.Binder#bindInterceptor( - * Matcher, Matcher, MethodInterceptor[]) bindInterceptor()} statements: + * explicitly in a module using {@link com.google.inject.Binder#bindInterceptor( Matcher, Matcher, + * MethodInterceptor[]) bindInterceptor()} statements: + * * <pre> * bindInterceptor(Matchers.subclassesOf(MyAction.class), * Matchers.annotatedWith(Transactional.class), @@ -59,6 +58,7 @@ public final class InterceptorBinding implements Element { this.interceptors = ImmutableList.copyOf(interceptors); } + @Override public Object getSource() { return source; } @@ -75,12 +75,18 @@ public final class InterceptorBinding implements Element { return interceptors; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { - binder.withSource(getSource()).bindInterceptor(classMatcher, methodMatcher, - interceptors.toArray(new MethodInterceptor[interceptors.size()])); + binder + .withSource(getSource()) + .bindInterceptor( + classMatcher, + methodMatcher, + interceptors.toArray(new MethodInterceptor[interceptors.size()])); } } diff --git a/core/src/com/google/inject/spi/LinkedKeyBinding.java b/core/src/com/google/inject/spi/LinkedKeyBinding.java index 7b823a6d..2d59d8e2 100644 --- a/core/src/com/google/inject/spi/LinkedKeyBinding.java +++ b/core/src/com/google/inject/spi/LinkedKeyBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -32,5 +32,4 @@ public interface LinkedKeyBinding<T> extends Binding<T> { * injector using {@link com.google.inject.Injector#getBinding(Key) Injector.getBinding(key)}. */ Key<? extends T> getLinkedKey(); - -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/MembersInjectorLookup.java b/core/src/com/google/inject/spi/MembersInjectorLookup.java index d4da8bdd..2944de3b 100644 --- a/core/src/com/google/inject/spi/MembersInjectorLookup.java +++ b/core/src/com/google/inject/spi/MembersInjectorLookup.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,6 +26,7 @@ import com.google.inject.TypeLiteral; /** * A lookup of the members injector for a type. Lookups are created explicitly in a module using * {@link com.google.inject.Binder#getMembersInjector(Class) getMembersInjector()} statements: + * * <pre> * MembersInjector<PaymentService> membersInjector * = getMembersInjector(PaymentService.class);</pre> @@ -44,17 +45,17 @@ public final class MembersInjectorLookup<T> implements Element { this.type = checkNotNull(type, "type"); } + @Override public Object getSource() { return source; } - /** - * Gets the type containing the members to be injected. - */ + /** Gets the type containing the members to be injected. */ public TypeLiteral<T> getType() { return type; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } @@ -69,14 +70,15 @@ public final class MembersInjectorLookup<T> implements Element { this.delegate = checkNotNull(delegate, "delegate"); } + @Override public void applyTo(Binder binder) { initializeDelegate(binder.withSource(getSource()).getMembersInjector(type)); } /** - * Returns the delegate members injector, or {@code null} if it has not yet been initialized. - * The delegate will be initialized when this element is processed, or otherwise used to create - * an injector. + * Returns the delegate members injector, or {@code null} if it has not yet been initialized. The + * delegate will be initialized when this element is processed, or otherwise used to create an + * injector. */ public MembersInjector<T> getDelegate() { return delegate; @@ -89,15 +91,20 @@ public final class MembersInjectorLookup<T> implements Element { */ public MembersInjector<T> getMembersInjector() { return new MembersInjector<T>() { + @Override public void injectMembers(T instance) { - checkState(delegate != null, - "This MembersInjector cannot be used until the Injector has been created."); - delegate.injectMembers(instance); + MembersInjector<T> local = delegate; + if (local == null) { + throw new IllegalStateException( + "This MembersInjector cannot be used until the Injector has been created."); + } + local.injectMembers(instance); } - @Override public String toString() { + @Override + public String toString() { return "MembersInjector<" + type + ">"; } }; } -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/Message.java b/core/src/com/google/inject/spi/Message.java index 59c40728..282f80ce 100644 --- a/core/src/com/google/inject/spi/Message.java +++ b/core/src/com/google/inject/spi/Message.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2006 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableList; import com.google.inject.Binder; import com.google.inject.internal.Errors; import com.google.inject.internal.util.SourceProvider; - import java.io.ObjectStreamException; import java.io.Serializable; import java.util.List; @@ -32,6 +31,7 @@ import java.util.List; * An error message and the context in which it occured. Messages are usually created internally by * Guice and its extensions. Messages can be created explicitly in a module using {@link * com.google.inject.Binder#addError(Throwable) addError()} statements: + * * <pre> * try { * bindPropertiesFromFile(); @@ -46,18 +46,14 @@ public final class Message implements Serializable, Element { private final Throwable cause; private final List<Object> sources; - /** - * @since 2.0 - */ + /** @since 2.0 */ public Message(List<Object> sources, String message, Throwable cause) { this.sources = ImmutableList.copyOf(sources); this.message = checkNotNull(message, "message"); this.cause = cause; } - /** - * @since 4.0 - */ + /** @since 4.0 */ public Message(String message, Throwable cause) { this(ImmutableList.of(), message, cause); } @@ -70,6 +66,7 @@ public final class Message implements Serializable, Element { this(ImmutableList.of(), message, null); } + @Override public String getSource() { return sources.isEmpty() ? SourceProvider.UNKNOWN_SOURCE.toString() @@ -81,21 +78,20 @@ public final class Message implements Serializable, Element { return sources; } - /** - * Gets the error message text. - */ + /** Gets the error message text. */ public String getMessage() { return message; } /** @since 2.0 */ + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } /** - * Returns the throwable that caused this message, or {@code null} if this - * message was not caused by a throwable. + * Returns the throwable that caused this message, or {@code null} if this message was not caused + * by a throwable. * * @since 2.0 */ @@ -103,15 +99,18 @@ public final class Message implements Serializable, Element { return cause; } - @Override public String toString() { + @Override + public String toString() { return message; } - @Override public int hashCode() { - return message.hashCode(); + @Override + public int hashCode() { + return Objects.hashCode(message, cause, sources); } - @Override public boolean equals(Object o) { + @Override + public boolean equals(Object o) { if (!(o instanceof Message)) { return false; } @@ -120,6 +119,7 @@ public final class Message implements Serializable, Element { } /** @since 2.0 */ + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).addError(this); } diff --git a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java index 3c908257..48343cb3 100644 --- a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java +++ b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,13 +18,12 @@ package com.google.inject.spi; import com.google.inject.Binder; import com.google.inject.Key; - import java.lang.annotation.Annotation; import java.util.Set; /** - * Allows extensions to scan modules for annotated methods and bind those methods - * as providers, similar to {@code @Provides} methods. + * Allows extensions to scan modules for annotated methods and bind those methods as providers, + * similar to {@code @Provides} methods. * * @since 4.0 */ @@ -40,16 +39,15 @@ public abstract class ModuleAnnotatedMethodScanner { /** * Prepares a method for binding. This {@code key} parameter is the key discovered from looking at * the binding annotation and return value of the method. Implementations can modify the key to - * instead bind to another key. For example, Multibinder may want to change - * {@code @SetProvides String provideFoo()} to bind into a unique Key within the multibinder - * instead of binding {@code String}. + * instead bind to another key. For example, Multibinder may want to change {@code @SetProvides + * String provideFoo()} to bind into a unique Key within the multibinder instead of binding {@code + * String}. * * <p>The injection point and annotation are provided in case the implementation wants to set the * key based on the property of the annotation or if any additional preparation is needed for any * of the dependencies. The annotation is guaranteed to be an instance of one the classes returned * by {@link #annotationClasses}. */ - public abstract <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key, - InjectionPoint injectionPoint); - + public abstract <T> Key<T> prepareMethod( + Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint); } diff --git a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java index d6324206..91cbe676 100644 --- a/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java +++ b/core/src/com/google/inject/spi/ModuleAnnotatedMethodScannerBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2015 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,7 +23,7 @@ import com.google.inject.internal.Errors; /** * Represents a call to {@link Binder#scanModulesForAnnotatedMethods} in a module. - * + * * @author sameb@google.com (Sam Berlin) * @since 4.0 */ @@ -36,6 +36,7 @@ public final class ModuleAnnotatedMethodScannerBinding implements Element { this.scanner = checkNotNull(scanner, "scanner"); } + @Override public Object getSource() { return source; } @@ -43,17 +44,24 @@ public final class ModuleAnnotatedMethodScannerBinding implements Element { public ModuleAnnotatedMethodScanner getScanner() { return scanner; } - + + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).scanModulesForAnnotatedMethods(scanner); } - @Override public String toString() { - return scanner + " which scans for " + scanner.annotationClasses() - + " (bound at " + Errors.convert(source) + ")"; + @Override + public String toString() { + return scanner + + " which scans for " + + scanner.annotationClasses() + + " (bound at " + + Errors.convert(source) + + ")"; } } diff --git a/core/src/com/google/inject/spi/ModuleSource.java b/core/src/com/google/inject/spi/ModuleSource.java index 1e07de2b..cd9435a5 100644 --- a/core/src/com/google/inject/spi/ModuleSource.java +++ b/core/src/com/google/inject/spi/ModuleSource.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2013 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ import com.google.common.collect.ImmutableList; import com.google.inject.Module; import com.google.inject.internal.util.StackTraceElements; import com.google.inject.internal.util.StackTraceElements.InMemoryStackTraceElement; - import java.util.List; /** @@ -31,14 +30,10 @@ import java.util.List; */ final class ModuleSource { - /** - * The class name of module that this {@link ModuleSource} associated to. - */ + /** The class name of module that this {@link ModuleSource} associated to. */ private final String moduleClassName; - /** - * The parent {@link ModuleSource module source}. - */ + /** The parent {@link ModuleSource module source}. */ private final ModuleSource parent; /** @@ -51,22 +46,24 @@ final class ModuleSource { /** * Creates a new {@link ModuleSource} with a {@literal null} parent. + * * @param module the corresponding module * @param partialCallStack the chunk of call stack that starts from the parent module {@link - * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link - * Module#configure(Binder) configure(Binder)} method invocation + * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link + * Module#configure(Binder) configure(Binder)} method invocation */ ModuleSource(Object module, StackTraceElement[] partialCallStack) { this(null, module, partialCallStack); } - /** + /** * Creates a new {@link ModuleSource} Object. + * * @param parent the parent module {@link ModuleSource source} * @param module the corresponding module * @param partialCallStack the chunk of call stack that starts from the parent module {@link - * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link - * Module#configure(Binder) configure(Binder)} method invocation + * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link + * Module#configure(Binder) configure(Binder)} method invocation */ private ModuleSource( /* @Nullable */ ModuleSource parent, Object module, StackTraceElement[] partialCallStack) { @@ -96,27 +93,24 @@ final class ModuleSource { return StackTraceElements.convertToStackTraceElement(partialCallStack); } - /** - * Returns the size of partial call stack if stack trace collection is on otherwise zero. - */ + /** Returns the size of partial call stack if stack trace collection is on otherwise zero. */ int getPartialCallStackSize() { return partialCallStack.length; } /** * Creates and returns a child {@link ModuleSource} corresponding to the {@link Module module}. + * * @param module the corresponding module * @param partialCallStack the chunk of call stack that starts from the parent module {@link - * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link - * Module#configure(Binder) configure(Binder)} method invocation + * Module#configure(Binder) configure(Binder)} call and ends just before the module {@link + * Module#configure(Binder) configure(Binder)} method invocation */ ModuleSource createChild(Object module, StackTraceElement[] partialCallStack) { return new ModuleSource(this, module, partialCallStack); } - /** - * Returns the parent module {@link ModuleSource source}. - */ + /** Returns the parent module {@link ModuleSource source}. */ ModuleSource getParent() { return parent; } diff --git a/core/src/com/google/inject/spi/PrivateElements.java b/core/src/com/google/inject/spi/PrivateElements.java index fc36305e..f3bc0e6a 100644 --- a/core/src/com/google/inject/spi/PrivateElements.java +++ b/core/src/com/google/inject/spi/PrivateElements.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.spi; import com.google.inject.Injector; import com.google.inject.Key; - import java.util.List; import java.util.Set; @@ -31,9 +30,7 @@ import java.util.Set; */ public interface PrivateElements extends Element { - /** - * Returns the configuration information in this private environment. - */ + /** Returns the configuration information in this private environment. */ List<Element> getElements(); /** @@ -42,9 +39,7 @@ public interface PrivateElements extends Element { */ Injector getInjector(); - /** - * Returns the unique exposed keys for these private elements. - */ + /** Returns the unique exposed keys for these private elements. */ Set<Key<?>> getExposedKeys(); /** diff --git a/core/src/com/google/inject/spi/ProviderBinding.java b/core/src/com/google/inject/spi/ProviderBinding.java index caec274b..092f645c 100644 --- a/core/src/com/google/inject/spi/ProviderBinding.java +++ b/core/src/com/google/inject/spi/ProviderBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -35,4 +35,4 @@ public interface ProviderBinding<T extends Provider<?>> extends Binding<T> { * Injector.getBinding(providedKey)} */ Key<?> getProvidedKey(); -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/ProviderInstanceBinding.java b/core/src/com/google/inject/spi/ProviderInstanceBinding.java index 99cd9db9..73f3b2e1 100644 --- a/core/src/com/google/inject/spi/ProviderInstanceBinding.java +++ b/core/src/com/google/inject/spi/ProviderInstanceBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,7 +18,6 @@ package com.google.inject.spi; import com.google.inject.Binding; import com.google.inject.Provider; - import java.util.Set; /** @@ -33,14 +32,15 @@ public interface ProviderInstanceBinding<T> extends Binding<T>, HasDependencies /** * If the user supplied a JSR330 binding, then this will wrap that one. To always return the * user-supplied provider, use {@link #getUserSuppliedProvider}. - * + * * @deprecated Use {@link #getUserSuppliedProvider} instead. */ @Deprecated Provider<? extends T> getProviderInstance(); - + /** * Returns the user-supplied, unscoped provider. + * * @since 4.0 */ javax.inject.Provider<? extends T> getUserSuppliedProvider(); @@ -52,5 +52,4 @@ public interface ProviderInstanceBinding<T> extends Binding<T>, HasDependencies * @return a possibly empty set */ Set<InjectionPoint> getInjectionPoints(); - -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/ProviderKeyBinding.java b/core/src/com/google/inject/spi/ProviderKeyBinding.java index 4a6cfdc0..9f28967f 100644 --- a/core/src/com/google/inject/spi/ProviderKeyBinding.java +++ b/core/src/com/google/inject/spi/ProviderKeyBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,5 +34,4 @@ public interface ProviderKeyBinding<T> extends Binding<T> { * Injector.getBinding(providerKey)} */ Key<? extends javax.inject.Provider<? extends T>> getProviderKey(); - -}
\ No newline at end of file +} diff --git a/core/src/com/google/inject/spi/ProviderLookup.java b/core/src/com/google/inject/spi/ProviderLookup.java index 3cc2d050..a3b51631 100644 --- a/core/src/com/google/inject/spi/ProviderLookup.java +++ b/core/src/com/google/inject/spi/ProviderLookup.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,12 +24,12 @@ import com.google.inject.Binder; import com.google.inject.Key; import com.google.inject.Provider; import com.google.inject.util.Types; - import java.util.Set; /** - * A lookup of the provider for a type. Lookups are created explicitly in a module using - * {@link com.google.inject.Binder#getProvider(Class) getProvider()} statements: + * A lookup of the provider for a type. Lookups are created explicitly in a module using {@link + * com.google.inject.Binder#getProvider(Class) getProvider()} statements: + * * <pre> * Provider<PaymentService> paymentServiceProvider * = getProvider(PaymentService.class);</pre> @@ -52,6 +52,7 @@ public final class ProviderLookup<T> implements Element { this.dependency = checkNotNull(dependency, "dependency"); } + @Override public Object getSource() { return source; } @@ -65,6 +66,7 @@ public final class ProviderLookup<T> implements Element { return dependency; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } @@ -79,6 +81,7 @@ public final class ProviderLookup<T> implements Element { this.delegate = checkNotNull(delegate, "delegate"); } + @Override public void applyTo(Binder binder) { initializeDelegate(binder.withSource(getSource()).getProvider(dependency)); } @@ -98,12 +101,17 @@ public final class ProviderLookup<T> implements Element { */ public Provider<T> getProvider() { return new ProviderWithDependencies<T>() { + @Override public T get() { - checkState(delegate != null, - "This Provider cannot be used until the Injector has been created."); - return delegate.get(); + Provider<T> local = delegate; + if (local == null) { + throw new IllegalStateException( + "This Provider cannot be used until the Injector has been created."); + } + return local.get(); } + @Override public Set<Dependency<?>> getDependencies() { // We depend on Provider<T>, not T directly. This is an important distinction // for dependency analysis tools that short-circuit on providers. @@ -111,7 +119,8 @@ public final class ProviderLookup<T> implements Element { return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey)); } - @Override public String toString() { + @Override + public String toString() { return "Provider<" + getKey().getTypeLiteral() + ">"; } }; diff --git a/core/src/com/google/inject/spi/ProviderWithDependencies.java b/core/src/com/google/inject/spi/ProviderWithDependencies.java index be87379f..a47a051e 100644 --- a/core/src/com/google/inject/spi/ProviderWithDependencies.java +++ b/core/src/com/google/inject/spi/ProviderWithDependencies.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java b/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java index b835b715..2d3f3bee 100644 --- a/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java +++ b/core/src/com/google/inject/spi/ProviderWithExtensionVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,26 +20,25 @@ import com.google.inject.Binding; import com.google.inject.Provider; /** - * A Provider that is part of an extension which supports a custom - * BindingTargetVisitor. - * <p> - * When an extension binds a provider instance, the provider can implement this - * interface to allow users using the - * {@link Binding#acceptTargetVisitor(BindingTargetVisitor)} method to visit a - * custom visitor designed for that extension. A typical implementation within - * the extension would look like - * <pre> + * A Provider that is part of an extension which supports a custom BindingTargetVisitor. + * + * <p>When an extension binds a provider instance, the provider can implement this interface to + * allow users using the {@link Binding#acceptTargetVisitor(BindingTargetVisitor)} method to visit a + * custom visitor designed for that extension. A typical implementation within the extension would + * look like + * + * <pre> * <V, B> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding) { * if(visitor instanceof MyCustomExtensionVisitor) { * return ((MyCustomExtensionVisitor<B, V>)visitor).visitCustomExtension(customProperties, binding); * } else { * return visitor.visit(binding); * } - * }</pre> - * 'MyCustomExtensionVisitor' in the example above would be an interface the - * extension provides that users can implement in order to be notified of custom - * extension information. These visitor interfaces must extend from - * BindingTargetVisitor. + * }</pre> + * + * 'MyCustomExtensionVisitor' in the example above would be an interface the extension provides that + * users can implement in order to be notified of custom extension information. These visitor + * interfaces must extend from BindingTargetVisitor. * * @since 3.0 * @author sameb@google.com (Sam Berlin) @@ -47,15 +46,13 @@ import com.google.inject.Provider; public interface ProviderWithExtensionVisitor<T> extends Provider<T> { /** - * Instructs the extension determine if the visitor is an instance of a custom - * extension visitor, and if so, visit it using that method. If the visitor is - * not an instance of the custom extension visitor, this method <b>MUST</b> - * call visitor.visit(binding). - * <p> - * Due to issues with generics, the type parameters of this method do not - * relate to the type of the provider. In practice, the 'B' type will always - * be a supertype of 'T'. + * Instructs the extension determine if the visitor is an instance of a custom extension visitor, + * and if so, visit it using that method. If the visitor is not an instance of the custom + * extension visitor, this method <b>MUST</b> call visitor.visit(binding). + * + * <p>Due to issues with generics, the type parameters of this method do not relate to the type of + * the provider. In practice, the 'B' type will always be a supertype of 'T'. */ - <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor, - ProviderInstanceBinding<? extends B> binding); + <B, V> V acceptExtensionVisitor( + BindingTargetVisitor<B, V> visitor, ProviderInstanceBinding<? extends B> binding); } diff --git a/core/src/com/google/inject/spi/ProvidesMethodBinding.java b/core/src/com/google/inject/spi/ProvidesMethodBinding.java index a862fcc6..ec56300a 100644 --- a/core/src/com/google/inject/spi/ProvidesMethodBinding.java +++ b/core/src/com/google/inject/spi/ProvidesMethodBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,33 +18,32 @@ package com.google.inject.spi; import com.google.inject.Key; import com.google.inject.Provides; - import java.lang.annotation.Annotation; import java.lang.reflect.Method; /** - * An {@literal @}{@link Provides} binding or binding produced by a - * {@link ModuleAnnotatedMethodScanner}. + * An {@literal @}{@link Provides} binding or binding produced by a {@link + * ModuleAnnotatedMethodScanner}. * * @since 4.0 * @author sameb@google.com (Sam Berlin) */ public interface ProvidesMethodBinding<T> extends HasDependencies { - + /** Returns the method this binding uses. */ - Method getMethod(); - + Method getMethod(); + /** Returns the instance of the object the method is defined in. */ Object getEnclosingInstance(); - + /** Returns the key of the binding. */ Key<T> getKey(); /** * Returns the annotation that caused this binding to be created. For {@code @Provides} methods, - * this is an instance of the {@code @Provides} annotation. For bindings from - * {@link ModuleAnnotatedMethodScanner}, this is the annotation that caused the scanner to produce - * the binding. + * this is an instance of the {@code @Provides} annotation. For bindings from {@link + * ModuleAnnotatedMethodScanner}, this is the annotation that caused the scanner to produce the + * binding. */ Annotation getAnnotation(); } diff --git a/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java b/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java index 62c87217..1a8c0f61 100644 --- a/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java +++ b/core/src/com/google/inject/spi/ProvidesMethodTargetVisitor.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2014 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -17,19 +17,18 @@ package com.google.inject.spi; import com.google.inject.Provides; -import com.google.inject.spi.BindingTargetVisitor; /** * A visitor for the {@literal @}{@link Provides} bindings. - * <p> - * If your {@link BindingTargetVisitor} implements this interface, bindings created by using - * {@code @Provides} will be visited through this interface. + * + * <p>If your {@link com.google.inject.spi.BindingTargetVisitor} implements this interface, bindings + * created by using {@code @Provides} will be visited through this interface. * * @since 4.0 * @author sameb@google.com (Sam Berlin) */ public interface ProvidesMethodTargetVisitor<T, V> extends BindingTargetVisitor<T, V> { - + /** * Visits an {@link ProvidesMethodBinding} created with an {@literal @}{@link Provides} method. */ diff --git a/core/src/com/google/inject/spi/ProvisionListener.java b/core/src/com/google/inject/spi/ProvisionListener.java index 274b8c39..3977224d 100644 --- a/core/src/com/google/inject/spi/ProvisionListener.java +++ b/core/src/com/google/inject/spi/ProvisionListener.java @@ -1,12 +1,12 @@ /* * Copyright (C) 2011 Google Inc. - * + * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the @@ -20,32 +20,28 @@ import com.google.inject.Binding; import com.google.inject.Provider; import com.google.inject.Scope; -import java.util.List; - /** - * Listens for provisioning of objects. Useful for gathering timing information - * about provisioning, post-provision initialization, and more. - * + * Listens for provisioning of objects. Useful for gathering timing information about provisioning, + * post-provision initialization, and more. + * * @author sameb@google.com (Sam Berlin) * @since 4.0 */ public interface ProvisionListener { /** - * Invoked by Guice when an object requires provisioning. Provisioning occurs - * when Guice locates and injects the dependencies for a binding. For types - * bound to a Provider, provisioning encapsulates the {@link Provider#get} - * method. For toInstance or constant bindings, provisioning encapsulates - * the injecting of {@literal @}{@code Inject}ed fields or methods. - * For other types, provisioning encapsulates the construction of the - * object. If a type is bound within a {@link Scope}, provisioning depends on - * the scope. Types bound in Singleton scope will only be provisioned once. - * Types bound in no scope will be provisioned every time they are injected. + * Invoked by Guice when an object requires provisioning. Provisioning occurs when Guice locates + * and injects the dependencies for a binding. For types bound to a Provider, provisioning + * encapsulates the {@link Provider#get} method. For toInstance or constant bindings, provisioning + * encapsulates the injecting of {@literal @}{@code Inject}ed fields or methods. For other types, + * provisioning encapsulates the construction of the object. If a type is bound within a {@link + * Scope}, provisioning depends on the scope. Types bound in Singleton scope will only be + * provisioned once. Types bound in no scope will be provisioned every time they are injected. * Other scopes define their own behavior for provisioning. - * <p> - * To perform the provision, call {@link ProvisionInvocation#provision()}. - * If you do not explicitly call provision, it will be automatically done after - * this method returns. It is an error to call provision more than once. + * + * <p>To perform the provision, call {@link ProvisionInvocation#provision()}. If you do not + * explicitly call provision, it will be automatically done after this method returns. It is an + * error to call provision more than once. */ <T> void onProvision(ProvisionInvocation<T> provision); @@ -53,22 +49,57 @@ public interface ProvisionListener { * Encapsulates a single act of provisioning. * * @since 4.0 - */ + */ public abstract static class ProvisionInvocation<T> { /** * Returns the Binding this is provisioning. - * <p> - * You must not call {@link Provider#get()} on the provider returned by - * {@link Binding#getProvider}, otherwise you will get confusing error messages. + * + * <p>You must not call {@link Provider#get()} on the provider returned by {@link + * Binding#getProvider}, otherwise you will get confusing error messages. */ public abstract Binding<T> getBinding(); /** Performs the provision, returning the object provisioned. */ public abstract T provision(); - - /** Returns the dependency chain that led to this object being provisioned. */ - public abstract List<DependencyAndSource> getDependencyChain(); - + + /** + * Returns the dependency chain that led to this object being provisioned. + * + * @deprecated This method is planned for removal in Guice 4.4. Some use cases can be replaced + * by inferring the current chain via ThreadLocals in the listener, other use cases can use + * the static dependency graph. For example, + * <pre>{@code + * bindListener(Matchers.any(), new MyListener()); + * ... + * + * private static final class MyListener implements ProvisionListener { + * private final ThreadLocal<ArrayDeque<Binding<?>>> bindingStack = + * new ThreadLocal<ArrayDeque<Binding<?>>>() { + * {@literal @}Override protected ArrayDeque<Binding<?>> initialValue() { + * return new ArrayDeque<>(); + * } + * }; + * {@literal @}Override public <T> void onProvision(ProvisionInvocation<T> invocation) { + * bindingStack.get().push(invocation.getBinding()); + * try { + * invocation.provision(); + * } finally { + * bindingStack.get().pop(); + * } + * // Inspect the binding stack... + * } + * } + * + * }<pre> + * + * In this example the bindingStack thread local will contain a data structure that is very + * similar to the data returned by this list. The main differences are that linked keys are + * not in the stack, but such edges do exist in the static dependency graph (inspectable via + * {@link HasDependencies#getDependencies()}), so you could infer some of the missing edges.. + */ + @Deprecated + public abstract java.util.List<DependencyAndSource> getDependencyChain(); + } } diff --git a/core/src/com/google/inject/spi/ProvisionListenerBinding.java b/core/src/com/google/inject/spi/ProvisionListenerBinding.java index 4f349d49..d94d1830 100644 --- a/core/src/com/google/inject/spi/ProvisionListenerBinding.java +++ b/core/src/com/google/inject/spi/ProvisionListenerBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2011 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,7 +20,6 @@ import com.google.common.collect.ImmutableList; import com.google.inject.Binder; import com.google.inject.Binding; import com.google.inject.matcher.Matcher; - import java.util.List; /** @@ -36,9 +35,8 @@ public final class ProvisionListenerBinding implements Element { private final Matcher<? super Binding<?>> bindingMatcher; private final List<ProvisionListener> listeners; - ProvisionListenerBinding(Object source, - Matcher<? super Binding<?>> bindingMatcher, - ProvisionListener[] listeners) { + ProvisionListenerBinding( + Object source, Matcher<? super Binding<?>> bindingMatcher, ProvisionListener[] listeners) { this.source = source; this.bindingMatcher = bindingMatcher; this.listeners = ImmutableList.copyOf(listeners); @@ -51,21 +49,25 @@ public final class ProvisionListenerBinding implements Element { /** * Returns the binding matcher which chooses which bindings the listener should be notified of. - */ + */ public Matcher<? super Binding<?>> getBindingMatcher() { return bindingMatcher; } + @Override public Object getSource() { return source; } + @Override public <R> R acceptVisitor(ElementVisitor<R> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { - binder.withSource(getSource()).bindListener(bindingMatcher, - listeners.toArray(new ProvisionListener[listeners.size()])); + binder + .withSource(getSource()) + .bindListener(bindingMatcher, listeners.toArray(new ProvisionListener[listeners.size()])); } } diff --git a/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java b/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java index 03d8c345..667df449 100644 --- a/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java +++ b/core/src/com/google/inject/spi/RequireAtInjectOnConstructorsOption.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2012 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -34,14 +34,17 @@ public final class RequireAtInjectOnConstructorsOption implements Element { this.source = checkNotNull(source, "source"); } + @Override public Object getSource() { return source; } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).requireAtInjectOnConstructors(); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } diff --git a/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java b/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java index ee52cfc6..2cc91ffd 100644 --- a/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java +++ b/core/src/com/google/inject/spi/RequireExactBindingAnnotationsOption.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,14 +33,17 @@ public final class RequireExactBindingAnnotationsOption implements Element { this.source = checkNotNull(source, "source"); } + @Override public Object getSource() { return source; } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).requireExactBindingAnnotations(); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } diff --git a/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java b/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java index 5962eb79..ee6f2109 100644 --- a/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java +++ b/core/src/com/google/inject/spi/RequireExplicitBindingsOption.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -33,14 +33,17 @@ public final class RequireExplicitBindingsOption implements Element { this.source = checkNotNull(source, "source"); } + @Override public Object getSource() { return source; } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).requireExplicitBindings(); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } diff --git a/core/src/com/google/inject/spi/ScopeBinding.java b/core/src/com/google/inject/spi/ScopeBinding.java index 86ed685c..563f5f56 100644 --- a/core/src/com/google/inject/spi/ScopeBinding.java +++ b/core/src/com/google/inject/spi/ScopeBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,13 +20,13 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Binder; import com.google.inject.Scope; - import java.lang.annotation.Annotation; /** * Registration of a scope annotation with the scope that implements it. Instances are created * explicitly in a module using {@link com.google.inject.Binder#bindScope(Class, Scope) bindScope()} * statements: + * * <pre> * Scope recordScope = new RecordScope(); * bindScope(RecordScoped.class, new RecordScope());</pre> @@ -45,6 +45,7 @@ public final class ScopeBinding implements Element { this.scope = checkNotNull(scope, "scope"); } + @Override public Object getSource() { return source; } @@ -57,10 +58,12 @@ public final class ScopeBinding implements Element { return scope; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).bindScope(annotationType, scope); } diff --git a/core/src/com/google/inject/spi/StaticInjectionRequest.java b/core/src/com/google/inject/spi/StaticInjectionRequest.java index 87e53763..fddba94f 100644 --- a/core/src/com/google/inject/spi/StaticInjectionRequest.java +++ b/core/src/com/google/inject/spi/StaticInjectionRequest.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,13 +20,13 @@ import static com.google.common.base.Preconditions.checkNotNull; import com.google.inject.Binder; import com.google.inject.ConfigurationException; - import java.util.Set; /** - * A request to inject the static fields and methods of a type. Requests are created - * explicitly in a module using {@link com.google.inject.Binder#requestStaticInjection(Class[]) + * A request to inject the static fields and methods of a type. Requests are created explicitly in a + * module using {@link com.google.inject.Binder#requestStaticInjection(Class[]) * requestStaticInjection()} statements: + * * <pre> * requestStaticInjection(MyLegacyService.class);</pre> * @@ -42,6 +42,7 @@ public final class StaticInjectionRequest implements Element { this.type = checkNotNull(type, "type"); } + @Override public Object getSource() { return source; } @@ -55,21 +56,23 @@ public final class StaticInjectionRequest implements Element { * request. * * @return a possibly empty set of injection points. The set has a specified iteration order. All - * fields are returned and then all methods. Within the fields, supertype fields are returned - * before subtype fields. Similarly, supertype methods are returned before subtype methods. + * fields are returned and then all methods. Within the fields, supertype fields are returned + * before subtype fields. Similarly, supertype methods are returned before subtype methods. * @throws ConfigurationException if there is a malformed injection point on {@code type}, such as - * a field with multiple binding annotations. The exception's {@link - * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} - * of the valid injection points. + * a field with multiple binding annotations. The exception's {@link + * ConfigurationException#getPartialValue() partial value} is a {@code Set<InjectionPoint>} of + * the valid injection points. */ public Set<InjectionPoint> getInjectionPoints() throws ConfigurationException { return InjectionPoint.forStaticMethodsAndFields(type); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).requestStaticInjection(type); } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } diff --git a/core/src/com/google/inject/spi/Toolable.java b/core/src/com/google/inject/spi/Toolable.java index ffabd9dd..d09ab307 100644 --- a/core/src/com/google/inject/spi/Toolable.java +++ b/core/src/com/google/inject/spi/Toolable.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,7 +21,6 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; import com.google.inject.Injector; import com.google.inject.Stage; - import java.lang.annotation.Documented; import java.lang.annotation.Retention; import java.lang.annotation.Target; @@ -29,17 +28,16 @@ import java.lang.annotation.Target; /** * Instructs an {@link Injector} running in {@link Stage#TOOL} that a method should be injected. * This is typically useful for for extensions to Guice that perform additional validation in an - * injected method or field. This only applies to objects that are already constructed when - * bindings are created (ie., something bound using {@link + * injected method or field. This only applies to objects that are already constructed when bindings + * are created (ie., something bound using {@link * com.google.inject.binder.LinkedBindingBuilder#toProvider toProvider}, {@link * com.google.inject.binder.LinkedBindingBuilder#toInstance toInstance}, or {@link * com.google.inject.Binder#requestInjection requestInjection}. - * + * * @author sberlin@gmail.com (Sam Berlin) * @since 3.0 */ -@Target({ METHOD }) +@Target({METHOD}) @Retention(RUNTIME) @Documented -public @interface Toolable { -} +public @interface Toolable {} diff --git a/core/src/com/google/inject/spi/TypeConverter.java b/core/src/com/google/inject/spi/TypeConverter.java index 6dd07a39..473c0ad4 100644 --- a/core/src/com/google/inject/spi/TypeConverter.java +++ b/core/src/com/google/inject/spi/TypeConverter.java @@ -26,8 +26,6 @@ import com.google.inject.TypeLiteral; */ public interface TypeConverter { - /** - * Converts a string value. Throws an exception if a conversion error occurs. - */ + /** Converts a string value. Throws an exception if a conversion error occurs. */ Object convert(String value, TypeLiteral<?> toType); } diff --git a/core/src/com/google/inject/spi/TypeConverterBinding.java b/core/src/com/google/inject/spi/TypeConverterBinding.java index 44786273..d54ad05e 100644 --- a/core/src/com/google/inject/spi/TypeConverterBinding.java +++ b/core/src/com/google/inject/spi/TypeConverterBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,11 +24,13 @@ import com.google.inject.internal.Errors; import com.google.inject.matcher.Matcher; /** - * Registration of type converters for matching target types. Instances are created - * explicitly in a module using {@link com.google.inject.Binder#convertToTypes(Matcher, - * TypeConverter) convertToTypes()} statements: + * Registration of type converters for matching target types. Instances are created explicitly in a + * module using {@link com.google.inject.Binder#convertToTypes(Matcher, TypeConverter) + * convertToTypes()} statements: + * * <pre> - * convertToTypes(Matchers.only(TypeLiteral.get(DateTime.class)), new DateTimeConverter());</pre> + * convertToTypes(Matchers.only(TypeLiteral.get(DateTime.class)), new DateTimeConverter()); + * </pre> * * @author jessewilson@google.com (Jesse Wilson) * @since 2.0 @@ -39,13 +41,14 @@ public final class TypeConverterBinding implements Element { private final TypeConverter typeConverter; /** @since 3.0 */ - public TypeConverterBinding(Object source, Matcher<? super TypeLiteral<?>> typeMatcher, - TypeConverter typeConverter) { + public TypeConverterBinding( + Object source, Matcher<? super TypeLiteral<?>> typeMatcher, TypeConverter typeConverter) { this.source = checkNotNull(source, "source"); this.typeMatcher = checkNotNull(typeMatcher, "typeMatcher"); this.typeConverter = checkNotNull(typeConverter, "typeConverter"); } + @Override public Object getSource() { return source; } @@ -58,16 +61,23 @@ public final class TypeConverterBinding implements Element { return typeConverter; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).convertToTypes(typeMatcher, typeConverter); } - @Override public String toString() { - return typeConverter + " which matches " + typeMatcher - + " (bound at " + Errors.convert(source) + ")"; + @Override + public String toString() { + return typeConverter + + " which matches " + + typeMatcher + + " (bound at " + + Errors.convert(source) + + ")"; } } diff --git a/core/src/com/google/inject/spi/TypeEncounter.java b/core/src/com/google/inject/spi/TypeEncounter.java index 2ed0ee70..159d7671 100644 --- a/core/src/com/google/inject/spi/TypeEncounter.java +++ b/core/src/com/google/inject/spi/TypeEncounter.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,13 +21,12 @@ import com.google.inject.MembersInjector; import com.google.inject.Provider; import com.google.inject.TypeLiteral; import com.google.inject.matcher.Matcher; - import java.lang.reflect.Method; /** * Context of an injectable type encounter. Enables reporting errors, registering injection - * listeners and binding method interceptors for injectable type {@code I}. It is an error to use - * an encounter after the {@link TypeListener#hear(TypeLiteral, TypeEncounter) hear()} method has + * listeners and binding method interceptors for injectable type {@code I}. It is an error to use an + * encounter after the {@link TypeListener#hear(TypeLiteral, TypeEncounter) hear()} method has * returned. * * @param <I> the injectable type encountered @@ -38,8 +37,8 @@ public interface TypeEncounter<I> { /** * Records an error message for type {@code I} which will be presented to the user at a later * time. Unlike throwing an exception, this enable us to continue configuring the Injector and - * discover more errors. Uses {@link String#format(String, Object[])} to insert the arguments - * into the message. + * discover more errors. Uses {@link String#format(String, Object[])} to insert the arguments into + * the message. */ void addError(String message, Object... arguments); @@ -50,9 +49,7 @@ public interface TypeEncounter<I> { */ void addError(Throwable t); - /** - * Records an error message to be presented to the user at a later time. - */ + /** Records an error message to be presented to the user at a later time. */ void addError(Message message); /** @@ -72,8 +69,8 @@ public interface TypeEncounter<I> { /** * Returns the members injector used to inject dependencies into methods and fields on instances * of the given type {@code T}. The returned members injector will not be valid until the main - * injector has been created. The members injector will throw an {@code IllegalStateException} - * if you try to use it beforehand. + * injector has been created. The members injector will throw an {@code IllegalStateException} if + * you try to use it beforehand. * * @param typeLiteral type to get members injector for */ @@ -82,8 +79,8 @@ public interface TypeEncounter<I> { /** * Returns the members injector used to inject dependencies into methods and fields on instances * of the given type {@code T}. The returned members injector will not be valid until the main - * injector has been created. The members injector will throw an {@code IllegalStateException} - * if you try to use it beforehand. + * injector has been created. The members injector will throw an {@code IllegalStateException} if + * you try to use it beforehand. * * @param type type to get members injector for */ @@ -103,20 +100,21 @@ public interface TypeEncounter<I> { /*if[AOP]*/ /** - * Binds method interceptor[s] to methods matched in type {@code I} and its supertypes. A - * method is eligible for interception if: + * Binds method interceptor[s] to methods matched in type {@code I} and its supertypes. A method + * is eligible for interception if: * * <ul> - * <li>Guice created the instance the method is on</li> - * <li>Neither the enclosing type nor the method is final</li> - * <li>And the method is package-private or more accessible</li> + * <li>Guice created the instance the method is on + * <li>Neither the enclosing type nor the method is final + * <li>And the method is package-private or more accessible * </ul> * - * @param methodMatcher matches methods the interceptor should apply to. For - * example: {@code annotatedWith(Transactional.class)}. + * @param methodMatcher matches methods the interceptor should apply to. For example: {@code + * annotatedWith(Transactional.class)}. * @param interceptors to bind */ - void bindInterceptor(Matcher<? super Method> methodMatcher, + void bindInterceptor( + Matcher<? super Method> methodMatcher, org.aopalliance.intercept.MethodInterceptor... interceptors); /*end[AOP]*/ } diff --git a/core/src/com/google/inject/spi/TypeListener.java b/core/src/com/google/inject/spi/TypeListener.java index ed9d8d32..b0195ab8 100644 --- a/core/src/com/google/inject/spi/TypeListener.java +++ b/core/src/com/google/inject/spi/TypeListener.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -25,24 +25,22 @@ import com.google.inject.TypeLiteral; * * <p>Useful for extra type checking, {@linkplain TypeEncounter#register(InjectionListener) * registering injection listeners}, and {@linkplain TypeEncounter#bindInterceptor( - * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) - * binding method interceptors}. - * + * com.google.inject.matcher.Matcher, org.aopalliance.intercept.MethodInterceptor[]) binding method + * interceptors}. + * * @since 2.0 */ public interface TypeListener { /** - * Invoked when Guice encounters a new type eligible for constructor or members injection. - * Called during injector creation (or afterwords if Guice encounters a type at run time and - * creates a JIT binding). + * Invoked when Guice encounters a new type eligible for constructor or members injection. Called + * during injector creation (or afterwards if Guice encounters a type at run time and creates a + * JIT binding). * * @param type encountered by Guice * @param encounter context of this encounter, enables reporting errors, registering injection * listeners and binding method interceptors for {@code type}. - * * @param <I> the injectable type */ <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter); - } diff --git a/core/src/com/google/inject/spi/TypeListenerBinding.java b/core/src/com/google/inject/spi/TypeListenerBinding.java index 8ad46729..ec609cb2 100644 --- a/core/src/com/google/inject/spi/TypeListenerBinding.java +++ b/core/src/com/google/inject/spi/TypeListenerBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2009 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -36,8 +36,8 @@ public final class TypeListenerBinding implements Element { private final Matcher<? super TypeLiteral<?>> typeMatcher; private final TypeListener listener; - TypeListenerBinding(Object source, TypeListener listener, - Matcher<? super TypeLiteral<?>> typeMatcher) { + TypeListenerBinding( + Object source, TypeListener listener, Matcher<? super TypeLiteral<?>> typeMatcher) { this.source = source; this.listener = listener; this.typeMatcher = typeMatcher; @@ -53,14 +53,17 @@ public final class TypeListenerBinding implements Element { return typeMatcher; } + @Override public Object getSource() { return source; } + @Override public <T> T acceptVisitor(ElementVisitor<T> visitor) { return visitor.visit(this); } + @Override public void applyTo(Binder binder) { binder.withSource(getSource()).bindListener(typeMatcher, listener); } diff --git a/core/src/com/google/inject/spi/UntargettedBinding.java b/core/src/com/google/inject/spi/UntargettedBinding.java index 4f6f8233..c605c941 100644 --- a/core/src/com/google/inject/spi/UntargettedBinding.java +++ b/core/src/com/google/inject/spi/UntargettedBinding.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/core/src/com/google/inject/spi/package-info.java b/core/src/com/google/inject/spi/package-info.java index 12248376..c217d264 100644 --- a/core/src/com/google/inject/spi/package-info.java +++ b/core/src/com/google/inject/spi/package-info.java @@ -14,7 +14,5 @@ * limitations under the License. */ -/** - * Guice service provider interface - */ +/** Guice service provider interface */ package com.google.inject.spi; diff --git a/core/src/com/google/inject/util/Modules.java b/core/src/com/google/inject/util/Modules.java index 08ec92c7..5378392f 100644 --- a/core/src/com/google/inject/util/Modules.java +++ b/core/src/com/google/inject/util/Modules.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -39,7 +39,6 @@ import com.google.inject.spi.Elements; import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding; import com.google.inject.spi.PrivateElements; import com.google.inject.spi.ScopeBinding; - import java.lang.annotation.Annotation; import java.util.Arrays; import java.util.LinkedHashSet; @@ -55,19 +54,22 @@ import java.util.Set; */ public final class Modules { private Modules() {} - + public static final Module EMPTY_MODULE = new EmptyModule(); + private static class EmptyModule implements Module { + @Override public void configure(Binder binder) {} } /** - * Returns a builder that creates a module that overlays override modules over the given - * modules. If a key is bound in both sets of modules, only the binding from the override modules - * is kept. If a single {@link PrivateModule} is supplied or all elements are from - * a single {@link PrivateBinder}, then this will overwrite the private bindings. - * Otherwise, private bindings will not be overwritten unless they are exposed. - * This can be used to replace the bindings of a production module with test bindings: + * Returns a builder that creates a module that overlays override modules over the given modules. + * If a key is bound in both sets of modules, only the binding from the override modules is kept. + * If a single {@link PrivateModule} is supplied or all elements are from a single {@link + * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will + * not be overwritten unless they are exposed. This can be used to replace the bindings of a + * production module with test bindings: + * * <pre> * Module functionalTestModule * = Modules.override(new ProductionModule()).with(new TestModule()); @@ -82,12 +84,13 @@ public final class Modules { } /** - * Returns a builder that creates a module that overlays override modules over the given - * modules. If a key is bound in both sets of modules, only the binding from the override modules - * is kept. If a single {@link PrivateModule} is supplied or all elements are from - * a single {@link PrivateBinder}, then this will overwrite the private bindings. - * Otherwise, private bindings will not be overwritten unless they are exposed. - * This can be used to replace the bindings of a production module with test bindings: + * Returns a builder that creates a module that overlays override modules over the given modules. + * If a key is bound in both sets of modules, only the binding from the override modules is kept. + * If a single {@link PrivateModule} is supplied or all elements are from a single {@link + * PrivateBinder}, then this will overwrite the private bindings. Otherwise, private bindings will + * not be overwritten unless they are exposed. This can be used to replace the bindings of a + * production module with test bindings: + * * <pre> * Module functionalTestModule * = Modules.override(getProductionModules()).with(getTestModules()); @@ -101,27 +104,24 @@ public final class Modules { return new RealOverriddenModuleBuilder(modules); } - /** - * Returns a new module that installs all of {@code modules}. - */ + /** Returns a new module that installs all of {@code modules}. */ public static Module combine(Module... modules) { return combine(ImmutableSet.copyOf(modules)); } - /** - * Returns a new module that installs all of {@code modules}. - */ + /** Returns a new module that installs all of {@code modules}. */ public static Module combine(Iterable<? extends Module> modules) { return new CombinedModule(modules); } - + private static class CombinedModule implements Module { final Set<Module> modulesSet; - + CombinedModule(Iterable<? extends Module> modules) { this.modulesSet = ImmutableSet.copyOf(modules); } - + + @Override public void configure(Binder binder) { binder = binder.skipSources(getClass()); for (Module module : modulesSet) { @@ -130,19 +130,13 @@ public final class Modules { } } - /** - * See the EDSL example at {@link Modules#override(Module[]) override()}. - */ + /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ public interface OverriddenModuleBuilder { - /** - * See the EDSL example at {@link Modules#override(Module[]) override()}. - */ + /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ Module with(Module... overrides); - /** - * See the EDSL example at {@link Modules#override(Module[]) override()}. - */ + /** See the EDSL example at {@link Modules#override(Module[]) override()}. */ Module with(Iterable<? extends Module> overrides); } @@ -153,19 +147,21 @@ public final class Modules { this.baseModules = ImmutableSet.copyOf(baseModules); } + @Override public Module with(Module... overrides) { return with(Arrays.asList(overrides)); } + @Override public Module with(Iterable<? extends Module> overrides) { return new OverrideModule(overrides, baseModules); } } - + static class OverrideModule extends AbstractModule { private final ImmutableSet<Module> overrides; private final ImmutableSet<Module> baseModules; - + OverrideModule(Iterable<? extends Module> overrides, ImmutableSet<Module> baseModules) { this.overrides = ImmutableSet.copyOf(overrides); this.baseModules = baseModules; @@ -179,24 +175,27 @@ public final class Modules { // If the sole element was a PrivateElements, we want to override // the private elements within that -- so refocus our elements // and binder. - if(baseElements.size() == 1) { + if (baseElements.size() == 1) { Element element = Iterables.getOnlyElement(baseElements); - if(element instanceof PrivateElements) { - PrivateElements privateElements = (PrivateElements)element; - PrivateBinder privateBinder = baseBinder.newPrivateBinder().withSource(privateElements.getSource()); - for(Key exposed : privateElements.getExposedKeys()) { + if (element instanceof PrivateElements) { + PrivateElements privateElements = (PrivateElements) element; + PrivateBinder privateBinder = + baseBinder.newPrivateBinder().withSource(privateElements.getSource()); + for (Key exposed : privateElements.getExposedKeys()) { privateBinder.withSource(privateElements.getExposedSource(exposed)).expose(exposed); } baseBinder = privateBinder; baseElements = privateElements.getElements(); } } - + final Binder binder = baseBinder.skipSources(this.getClass()); - final LinkedHashSet<Element> elements = new LinkedHashSet<Element>(baseElements); + final LinkedHashSet<Element> elements = new LinkedHashSet<>(baseElements); final Module scannersModule = extractScanners(elements); - final List<Element> overrideElements = Elements.getElements(currentStage(), - ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build()); + final List<Element> overrideElements = + Elements.getElements( + currentStage(), + ImmutableList.<Module>builder().addAll(overrides).add(scannersModule).build()); final Set<Key<?>> overriddenKeys = Sets.newHashSet(); final Map<Class<? extends Annotation>, ScopeBinding> overridesScopeAnnotations = @@ -204,17 +203,20 @@ public final class Modules { // execute the overrides module, keeping track of which keys and scopes are bound new ModuleWriter(binder) { - @Override public <T> Void visit(Binding<T> binding) { + @Override + public <T> Void visit(Binding<T> binding) { overriddenKeys.add(binding.getKey()); return super.visit(binding); } - @Override public Void visit(ScopeBinding scopeBinding) { + @Override + public Void visit(ScopeBinding scopeBinding) { overridesScopeAnnotations.put(scopeBinding.getAnnotationType(), scopeBinding); return super.visit(scopeBinding); } - @Override public Void visit(PrivateElements privateElements) { + @Override + public Void visit(PrivateElements privateElements) { overriddenKeys.addAll(privateElements.getExposedKeys()); return super.visit(privateElements); } @@ -226,7 +228,8 @@ public final class Modules { final Map<Scope, List<Object>> scopeInstancesInUse = Maps.newHashMap(); final List<ScopeBinding> scopeBindings = Lists.newArrayList(); new ModuleWriter(binder) { - @Override public <T> Void visit(Binding<T> binding) { + @Override + public <T> Void visit(Binding<T> binding) { if (!overriddenKeys.remove(binding.getKey())) { super.visit(binding); @@ -246,8 +249,8 @@ public final class Modules { } void rewrite(Binder binder, PrivateElements privateElements, Set<Key<?>> keysToSkip) { - PrivateBinder privateBinder = binder.withSource(privateElements.getSource()) - .newPrivateBinder(); + PrivateBinder privateBinder = + binder.withSource(privateElements.getSource()).newPrivateBinder(); Set<Key<?>> skippedExposes = Sets.newHashSet(); @@ -260,8 +263,7 @@ public final class Modules { } for (Element element : privateElements.getElements()) { - if (element instanceof Binding - && skippedExposes.remove(((Binding) element).getKey())) { + if (element instanceof Binding && skippedExposes.remove(((Binding) element).getKey())) { continue; } if (element instanceof PrivateElements) { @@ -272,12 +274,14 @@ public final class Modules { } } - @Override public Void visit(PrivateElements privateElements) { + @Override + public Void visit(PrivateElements privateElements) { rewrite(binder, privateElements, overriddenKeys); return null; } - @Override public Void visit(ScopeBinding scopeBinding) { + @Override + public Void visit(ScopeBinding scopeBinding) { scopeBindings.add(scopeBinding); return null; } @@ -286,7 +290,8 @@ public final class Modules { // execute the scope bindings, skipping scopes that have been overridden. Any scope that // is overridden and in active use will prompt an error new ModuleWriter(binder) { - @Override public Void visit(ScopeBinding scopeBinding) { + @Override + public Void visit(ScopeBinding scopeBinding) { ScopeBinding overideBinding = overridesScopeAnnotations.remove(scopeBinding.getAnnotationType()); if (overideBinding == null) { @@ -294,13 +299,15 @@ public final class Modules { } else { List<Object> usedSources = scopeInstancesInUse.get(scopeBinding.getScope()); if (usedSources != null) { - StringBuilder sb = new StringBuilder( - "The scope for @%s is bound directly and cannot be overridden."); + StringBuilder sb = + new StringBuilder( + "The scope for @%s is bound directly and cannot be overridden."); sb.append("%n original binding at " + Errors.convert(scopeBinding.getSource())); for (Object usedSource : usedSources) { sb.append("%n bound directly at " + Errors.convert(usedSource) + ""); } - binder.withSource(overideBinding.getSource()) + binder + .withSource(overideBinding.getSource()) .addError(sb.toString(), scopeBinding.getAnnotationType().getSimpleName()); } } @@ -310,11 +317,13 @@ public final class Modules { } private Scope getScopeInstanceOrNull(Binding<?> binding) { - return binding.acceptScopingVisitor(new DefaultBindingScopingVisitor<Scope>() { - @Override public Scope visitScope(Scope scope) { - return scope; - } - }); + return binding.acceptScopingVisitor( + new DefaultBindingScopingVisitor<Scope>() { + @Override + public Scope visitScope(Scope scope) { + return scope; + } + }); } } @@ -325,7 +334,8 @@ public final class Modules { this.binder = binder.skipSources(this.getClass()); } - @Override protected Void visitOther(Element element) { + @Override + protected Void visitOther(Element element) { element.applyTo(binder); return null; } @@ -339,17 +349,20 @@ public final class Modules { private static Module extractScanners(Iterable<Element> elements) { final List<ModuleAnnotatedMethodScannerBinding> scanners = Lists.newArrayList(); - ElementVisitor<Void> visitor = new DefaultElementVisitor<Void>() { - @Override public Void visit(ModuleAnnotatedMethodScannerBinding binding) { - scanners.add(binding); - return null; - } - }; + ElementVisitor<Void> visitor = + new DefaultElementVisitor<Void>() { + @Override + public Void visit(ModuleAnnotatedMethodScannerBinding binding) { + scanners.add(binding); + return null; + } + }; for (Element element : elements) { element.acceptVisitor(visitor); } return new AbstractModule() { - @Override protected void configure() { + @Override + protected void configure() { for (ModuleAnnotatedMethodScannerBinding scanner : scanners) { scanner.applyTo(binder()); } diff --git a/core/src/com/google/inject/util/Providers.java b/core/src/com/google/inject/util/Providers.java index c18d3512..f8c5d219 100644 --- a/core/src/com/google/inject/util/Providers.java +++ b/core/src/com/google/inject/util/Providers.java @@ -27,12 +27,10 @@ import com.google.inject.Provider; import com.google.inject.spi.Dependency; import com.google.inject.spi.InjectionPoint; import com.google.inject.spi.ProviderWithDependencies; - import java.util.Set; /** - * Static utility methods for creating and working with instances of - * {@link Provider}. + * Static utility methods for creating and working with instances of {@link Provider}. * * @author Kevin Bourrillion (kevinb9n@gmail.com) * @since 2.0 @@ -42,13 +40,12 @@ public final class Providers { private Providers() {} /** - * Returns a provider which always provides {@code instance}. This should not - * be necessary to use in your application, but is helpful for several types - * of unit tests. + * Returns a provider which always provides {@code instance}. This should not be necessary to use + * in your application, but is helpful for several types of unit tests. * - * @param instance the instance that should always be provided. This is also - * permitted to be null, to enable aggressive testing, although in real - * life a Guice-supplied Provider will never return null. + * @param instance the instance that should always be provided. This is also permitted to be null, + * to enable aggressive testing, although in real life a Guice-supplied Provider will never + * return null. */ public static <T> Provider<T> of(final T instance) { return new ConstantProvider<T>(instance); @@ -61,46 +58,50 @@ public final class Providers { this.instance = instance; } + @Override public T get() { return instance; } - @Override public String toString() { + @Override + public String toString() { return "of(" + instance + ")"; } - @Override public boolean equals(Object obj) { + @Override + public boolean equals(Object obj) { return (obj instanceof ConstantProvider) && Objects.equal(instance, ((ConstantProvider<?>) obj).instance); } - @Override public int hashCode() { + @Override + public int hashCode() { return Objects.hashCode(instance); } } /** - * Returns a Guice-friendly {@code com.google.inject.Provider} for the given - * JSR-330 {@code javax.inject.Provider}. The converse method is unnecessary, - * since Guice providers directly implement the JSR-330 interface. - * + * Returns a Guice-friendly {@code com.google.inject.Provider} for the given JSR-330 {@code + * javax.inject.Provider}. The converse method is unnecessary, since Guice providers directly + * implement the JSR-330 interface. + * * @since 3.0 */ public static <T> Provider<T> guicify(javax.inject.Provider<T> provider) { if (provider instanceof Provider) { return (Provider<T>) provider; } - + final javax.inject.Provider<T> delegate = checkNotNull(provider, "provider"); - + // Ensure that we inject all injection points from the delegate provider. Set<InjectionPoint> injectionPoints = InjectionPoint.forInstanceMethodsAndFields(provider.getClass()); - if(injectionPoints.isEmpty()) { + if (injectionPoints.isEmpty()) { return new GuicifiedProvider<T>(delegate); } else { Set<Dependency<?>> mutableDeps = Sets.newHashSet(); - for(InjectionPoint ip : injectionPoints) { + for (InjectionPoint ip : injectionPoints) { mutableDeps.addAll(ip.getDependencies()); } final Set<Dependency<?>> dependencies = ImmutableSet.copyOf(mutableDeps); @@ -115,30 +116,34 @@ public final class Providers { this.delegate = delegate; } + @Override public T get() { return delegate.get(); } - @Override public String toString() { + @Override + public String toString() { return "guicified(" + delegate + ")"; } - @Override public boolean equals(Object obj) { + @Override + public boolean equals(Object obj) { return (obj instanceof GuicifiedProvider) && Objects.equal(delegate, ((GuicifiedProvider<?>) obj).delegate); } - @Override public int hashCode() { + @Override + public int hashCode() { return Objects.hashCode(delegate); } } - private static final class GuicifiedProviderWithDependencies<T> - extends GuicifiedProvider<T> implements ProviderWithDependencies<T> { + private static final class GuicifiedProviderWithDependencies<T> extends GuicifiedProvider<T> + implements ProviderWithDependencies<T> { private final Set<Dependency<?>> dependencies; - private GuicifiedProviderWithDependencies(Set<Dependency<?>> dependencies, - javax.inject.Provider<T> delegate) { + private GuicifiedProviderWithDependencies( + Set<Dependency<?>> dependencies, javax.inject.Provider<T> delegate) { super(delegate); this.dependencies = dependencies; } @@ -149,6 +154,7 @@ public final class Providers { injector.injectMembers(delegate); } + @Override public Set<Dependency<?>> getDependencies() { return dependencies; } diff --git a/core/src/com/google/inject/util/Types.java b/core/src/com/google/inject/util/Types.java index c3b3a2af..32714cc7 100644 --- a/core/src/com/google/inject/util/Types.java +++ b/core/src/com/google/inject/util/Types.java @@ -1,4 +1,4 @@ -/** +/* * Copyright (C) 2008 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,7 +14,6 @@ * limitations under the License. */ - package com.google.inject.util; import com.google.inject.Provider; @@ -22,11 +21,11 @@ import com.google.inject.internal.MoreTypes; import com.google.inject.internal.MoreTypes.GenericArrayTypeImpl; import com.google.inject.internal.MoreTypes.ParameterizedTypeImpl; import com.google.inject.internal.MoreTypes.WildcardTypeImpl; - import java.lang.reflect.GenericArrayType; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.lang.reflect.WildcardType; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.Set; @@ -41,8 +40,8 @@ public final class Types { private Types() {} /** - * Returns a new parameterized type, applying {@code typeArguments} to - * {@code rawType}. The returned type does not have an owner type. + * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType}. The + * returned type does not have an owner type. * * @return a {@link java.io.Serializable serializable} parameterized type. */ @@ -51,8 +50,8 @@ public final class Types { } /** - * Returns a new parameterized type, applying {@code typeArguments} to - * {@code rawType} and enclosed by {@code ownerType}. + * Returns a new parameterized type, applying {@code typeArguments} to {@code rawType} and + * enclosed by {@code ownerType}. * * @return a {@link java.io.Serializable serializable} parameterized type. */ @@ -62,8 +61,7 @@ public final class Types { } /** - * Returns an array type whose elements are all instances of - * {@code componentType}. + * Returns an array type whose elements are all instances of {@code componentType}. * * @return a {@link java.io.Serializable serializable} generic array type. */ @@ -72,27 +70,25 @@ public final class Types { } /** - * Returns a type that represents an unknown type that extends {@code bound}. - * For example, if {@code bound} is {@code CharSequence.class}, this returns - * {@code ? extends CharSequence}. If {@code bound} is {@code Object.class}, - * this returns {@code ?}, which is shorthand for {@code ? extends Object}. + * Returns a type that represents an unknown type that extends {@code bound}. For example, if + * {@code bound} is {@code CharSequence.class}, this returns {@code ? extends CharSequence}. If + * {@code bound} is {@code Object.class}, this returns {@code ?}, which is shorthand for {@code ? + * extends Object}. */ public static WildcardType subtypeOf(Type bound) { - return new WildcardTypeImpl(new Type[] { bound }, MoreTypes.EMPTY_TYPE_ARRAY); + return new WildcardTypeImpl(new Type[] {bound}, MoreTypes.EMPTY_TYPE_ARRAY); } /** - * Returns a type that represents an unknown supertype of {@code bound}. For - * example, if {@code bound} is {@code String.class}, this returns {@code ? - * super String}. + * Returns a type that represents an unknown supertype of {@code bound}. For example, if {@code + * bound} is {@code String.class}, this returns {@code ? super String}. */ public static WildcardType supertypeOf(Type bound) { - return new WildcardTypeImpl(new Type[] { Object.class }, new Type[] { bound }); + return new WildcardTypeImpl(new Type[] {Object.class}, new Type[] {bound}); } /** - * Returns a type modelling a {@link List} whose elements are of type - * {@code elementType}. + * Returns a type modelling a {@link List} whose elements are of type {@code elementType}. * * @return a {@link java.io.Serializable serializable} parameterized type. */ @@ -101,8 +97,16 @@ public final class Types { } /** - * Returns a type modelling a {@link Set} whose elements are of type - * {@code elementType}. + * Returns a type modelling a {@link Collection} whose elements are of type {@code elementType}. + * + * @return a {@link java.io.Serializable serializable} parameterized type. + */ + public static ParameterizedType collectionOf(Type elementType) { + return newParameterizedType(Collection.class, elementType); + } + + /** + * Returns a type modelling a {@link Set} whose elements are of type {@code elementType}. * * @return a {@link java.io.Serializable serializable} parameterized type. */ @@ -111,8 +115,8 @@ public final class Types { } /** - * Returns a type modelling a {@link Map} whose keys are of type - * {@code keyType} and whose values are of type {@code valueType}. + * Returns a type modelling a {@link Map} whose keys are of type {@code keyType} and whose values + * are of type {@code valueType}. * * @return a {@link java.io.Serializable serializable} parameterized type. */ @@ -123,12 +127,21 @@ public final class Types { // for other custom collections types, use newParameterizedType() /** - * Returns a type modelling a {@link Provider} that provides elements of type - * {@code elementType}. + * Returns a type modelling a {@link Provider} that provides elements of type {@code elementType}. * * @return a {@link java.io.Serializable serializable} parameterized type. */ public static ParameterizedType providerOf(Type providedType) { return newParameterizedType(Provider.class, providedType); } -}
\ No newline at end of file + + /** + * Returns a type modelling a {@link javax.inject.Provider} that provides elements of type {@code + * elementType}. + * + * @return a {@link java.io.Serializable serializable} parameterized type. + */ + public static Type javaxProviderOf(Type type) { + return Types.newParameterizedType(javax.inject.Provider.class, type); + } +} diff --git a/core/src/com/google/inject/util/package-info.java b/core/src/com/google/inject/util/package-info.java index 89c5de22..3ebb87cb 100644 --- a/core/src/com/google/inject/util/package-info.java +++ b/core/src/com/google/inject/util/package-info.java @@ -14,7 +14,5 @@ * limitations under the License. */ -/** - * Helper methods for working with Guice. - */ -package com.google.inject.util;
\ No newline at end of file +/** Helper methods for working with Guice. */ +package com.google.inject.util; |