Skip to content

Commit

Permalink
Add a moduleInstance parameter to the ModuleAnnotatedMethodScanner. T…
Browse files Browse the repository at this point in the history
…his is useful in some cases where the scanner bindings need more information from the module currently being scanned.

PiperOrigin-RevId: 615788414
  • Loading branch information
jessevb authored and Guice Team committed Mar 14, 2024
1 parent d46b395 commit a0b4d16
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,8 @@ private <T> ProviderMethod<T> createProviderMethod(
Key<T> key = getKey(errors, returnType, method, method.getAnnotations());
boolean prepareMethodError = false;
try {
key = scanner.prepareMethod(binder, annotation, key, point);
key =
scanner.prepareMethod(binder, annotation, key, point, isStaticModule() ? null : delegate);
} catch (Throwable t) {
prepareMethodError = true;
binder.addError(t);
Expand Down
2 changes: 1 addition & 1 deletion core/src/com/google/inject/spi/ElementSource.java
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ public final class ElementSource {
final ElementSource originalElementSource;

/**
* Wheather the originalElementSource was set externaly (untrusted) or by Guice internals
* Whether the originalElementSource was set externally (untrusted) or by Guice internals
* (trusted).
*
* <p>External code can set the originalElementSource to an arbitrary ElementSource via
Expand Down
43 changes: 41 additions & 2 deletions core/src/com/google/inject/spi/ModuleAnnotatedMethodScanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.google.inject.Key;
import java.lang.annotation.Annotation;
import java.util.Set;
import javax.annotation.Nullable;

/**
* Allows extensions to scan modules for annotated methods and bind those methods as providers,
Expand Down Expand Up @@ -53,7 +54,45 @@ public abstract class ModuleAnnotatedMethodScanner {
* <p>If {@code injectionPoint} represents an {@code abstract} method, {@code null} must be
* returned from this method. This scanner can use {@code binder} to bind alternative bindings in
* place of the abstract method.
*
* @deprecated Prefer overriding the overload that takes `Object moduleInstance` instead. If not
* overridden, that method will invoke this one to aid in backwards compatibility.
*/
@Deprecated
public <T> Key<T> prepareMethod(
Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint) {
throw new IllegalStateException(
"'prepareMethod' not implemented, one override must be implemented.");
}

/**
* 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 @ProvidesIntoSet 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}.
*
* <p>Returning null will cause Guice to skip this method, so that it is not bound to any key.
*
* <p>If {@code injectionPoint} represents an {@code abstract} method, {@code null} must be
* returned from this method. This scanner can use {@code binder} to bind alternative bindings in
* place of the abstract method.
*
* <p>The {@code moduleInstance} parameter contains the Module instance that is currently being
* scanned, which may be null if the methods were discovered on Module class objects (as opposed
* to module instances).
*/
public abstract <T> Key<T> prepareMethod(
Binder binder, Annotation annotation, Key<T> key, InjectionPoint injectionPoint);
public <T> Key<T> prepareMethod(
Binder binder,
Annotation annotation,
Key<T> key,
InjectionPoint injectionPoint,
@Nullable Object moduleInstance) {
return prepareMethod(binder, annotation, key, injectionPoint);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1035,6 +1035,54 @@ String privateString() {
.isEqualTo(scanner);
}

static class DelegatingScanner extends ModuleAnnotatedMethodScanner {
Object delegate = null;

@Override
public Set<? extends Class<? extends Annotation>> annotationClasses() {
return ImmutableSet.of(TestProvides.class);
}

@Override
public <T> Key<T> prepareMethod(
Binder binder,
Annotation annotation,
Key<T> key,
InjectionPoint injectionPoint,
Object delegate) {
this.delegate = delegate;
return key;
}
}

@Test
public void scannerPropagatesTheDelegateObject() {
DelegatingScanner scanner = new DelegatingScanner();
AbstractModule module =
new AbstractModule() {
@TestProvides
String provideString() {
return "foo";
}
};
Guice.createInjector(scannerModule(scanner), module);
assertThat(scanner.delegate).isSameInstanceAs(module);
}

static class StaticProvider extends AbstractModule {
@TestProvides
static String provideString() {
return "foo";
}
}

@Test
public void staticScannerPropagatesNullDelegateObject() {
DelegatingScanner scanner = new DelegatingScanner();
Guice.createInjector(ProviderMethodsModule.forModule(StaticProvider.class, scanner));
assertThat(scanner.delegate).isNull();
}

ModuleAnnotatedMethodScanner getSourceScanner(Binding<?> binding) {
return ((ElementSource) binding.getSource()).scanner;
}
Expand Down

0 comments on commit a0b4d16

Please sign in to comment.