Fix ModuleAnnotatedMethodScanners so that they scan modules installed in
binders created from skipSources or withSource.
-------------
Created by MOE: http://code.google.com/p/moe-java
MOE_MIGRATED_REVID=89146131
diff --git a/core/src/com/google/inject/spi/Elements.java b/core/src/com/google/inject/spi/Elements.java
index 46072e3..f5bbe89 100644
--- a/core/src/com/google/inject/spi/Elements.java
+++ b/core/src/com/google/inject/spi/Elements.java
@@ -147,10 +147,12 @@
private static class ModuleInfo {
private final Binder binder;
private final ModuleSource moduleSource;
+ private final boolean skipScanning;
- private ModuleInfo(Binder binder, ModuleSource moduleSource) {
+ private ModuleInfo(Binder binder, ModuleSource moduleSource, boolean skipScanning) {
this.binder = binder;
this.moduleSource = moduleSource;
+ this.skipScanning = skipScanning;
}
}
@@ -270,19 +272,25 @@
}
}
+ /**
+ * 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) {
// Note: we must iterate over a copy of the modules because calling install(..)
// will mutate modules, otherwise causing a ConcurrentModificationException.
for (Map.Entry<Module, ModuleInfo> entry : Maps.newLinkedHashMap(modules).entrySet()) {
Module module = entry.getKey();
- // If this was from a child private binder, skip it... we'll process it later.
- if (entry.getValue().binder != this) {
+ ModuleInfo info = entry.getValue();
+ if (info.skipScanning) {
continue;
}
moduleSource = entry.getValue().moduleSource;
try {
- install(ProviderMethodsModule.forModule(module, scanner));
+ info.binder.install(ProviderMethodsModule.forModule(module, scanner));
} catch(RuntimeException e) {
Collection<Message> messages = Errors.getMessagesFromThrowable(e);
if (!messages.isEmpty()) {
@@ -298,7 +306,7 @@
public void install(Module module) {
if (!modules.containsKey(module)) {
- Binder binder = this;
+ RecordingBinder binder = this;
boolean unwrapModuleSource = false;
// Update the module source for the new module
if (module instanceof ProviderMethodsModule) {
@@ -316,14 +324,16 @@
moduleSource = getModuleSource(module);
unwrapModuleSource = true;
}
+ boolean skipScanning = false;
if (module instanceof PrivateModule) {
- binder = binder.newPrivateBinder();
- // Store the module in the private binder too.
- ((RecordingBinder) binder).modules.put(module, new ModuleInfo(binder, moduleSource));
+ binder = (RecordingBinder) binder.newPrivateBinder();
+ // Store the module in the private binder too so we scan for it.
+ binder.modules.put(module, new ModuleInfo(binder, moduleSource, false));
+ skipScanning = true; // don't scan this module in the parent's module set.
}
// Always store this in the parent binder (even if it was a private module)
// so that we know not to process it again, and so that scanners inherit down.
- modules.put(module, new ModuleInfo(binder, moduleSource));
+ modules.put(module, new ModuleInfo(binder, moduleSource, skipScanning));
try {
module.configure(binder);
} catch (RuntimeException e) {
diff --git a/core/test/com/google/inject/spi/ModuleAnnotatedMethodScannerTest.java b/core/test/com/google/inject/spi/ModuleAnnotatedMethodScannerTest.java
index e73a9af..6c797b1 100644
--- a/core/test/com/google/inject/spi/ModuleAnnotatedMethodScannerTest.java
+++ b/core/test/com/google/inject/spi/ModuleAnnotatedMethodScannerTest.java
@@ -75,6 +75,34 @@
foo2Binding.getProvider().toString());
}
+ public void testSkipSources() throws Exception {
+ Module module = new AbstractModule() {
+ @Override protected void configure() {
+ binder().skipSources(getClass()).install(new AbstractModule() {
+ @Override protected void configure() {}
+
+ @TestProvides @Named("foo") String foo() { return "foo"; }
+ });
+ }
+ };
+ Injector injector = Guice.createInjector(module, NamedMunger.module());
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
+ public void testWithSource() throws Exception {
+ Module module = new AbstractModule() {
+ @Override protected void configure() {
+ binder().withSource("source").install(new AbstractModule() {
+ @Override protected void configure() {}
+
+ @TestProvides @Named("foo") String foo() { return "foo"; }
+ });
+ }
+ };
+ Injector injector = Guice.createInjector(module, NamedMunger.module());
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
public void testMoreThanOneClaimedAnnotationFails() throws Exception {
Module module = new AbstractModule() {
@Override protected void configure() {}
@@ -228,6 +256,34 @@
assertMungedBinding(injector, String.class, "foo", "foo");
}
+ public void testPrivateModule_skipSourcesWithinPrivateModule() {
+ Injector injector = Guice.createInjector(NamedMunger.module(), new PrivateModule() {
+ @Override protected void configure() {
+ binder().skipSources(getClass()).install(new AbstractModule() {
+ @Override protected void configure() {}
+ @Exposed @TestProvides @Named("foo") String foo() {
+ return "foo";
+ }
+ });
+ }
+ });
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
+ public void testPrivateModule_skipSourcesForPrivateModule() {
+ Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
+ @Override protected void configure() {
+ binder().skipSources(getClass()).install(new PrivateModule() {
+ @Override protected void configure() {}
+
+ @Exposed @TestProvides @Named("foo") String foo() {
+ return "foo";
+ }
+ });
+ }});
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
public void testPrivateModuleInheritScanner_usingPrivateBinder() {
Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
@Override protected void configure() {
@@ -243,6 +299,36 @@
assertMungedBinding(injector, String.class, "foo", "foo");
}
+ public void testPrivateModuleInheritScanner_skipSourcesFromPrivateBinder() {
+ Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
+ @Override protected void configure() {
+ binder().newPrivateBinder().skipSources(getClass()).install(new AbstractModule() {
+ @Override protected void configure() {}
+
+ @Exposed @TestProvides @Named("foo") String foo() {
+ return "foo";
+ }
+ });
+ }
+ });
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
+ public void testPrivateModuleInheritScanner_skipSourcesFromPrivateBinder2() {
+ Injector injector = Guice.createInjector(NamedMunger.module(), new AbstractModule() {
+ @Override protected void configure() {
+ binder().skipSources(getClass()).newPrivateBinder().install(new AbstractModule() {
+ @Override protected void configure() {}
+
+ @Exposed @TestProvides @Named("foo") String foo() {
+ return "foo";
+ }
+ });
+ }
+ });
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
+
public void testPrivateModuleScannersDontImpactSiblings_usingPrivateModule() {
Injector injector = Guice.createInjector(new PrivateModule() {
@Override protected void configure() {
@@ -289,4 +375,20 @@
}});
assertMungedBinding(injector, String.class, "foo", "foo");
}
+
+ public void testPrivateModuleWithinPrivateModule() {
+ Injector injector = Guice.createInjector(NamedMunger.module(), new PrivateModule() {
+ @Override protected void configure() {
+ expose(Key.get(String.class, named("foo-munged")));
+ install(new PrivateModule() {
+ @Override protected void configure() {}
+
+ @Exposed @TestProvides @Named("foo") String foo() {
+ return "foo";
+ }
+ });
+ }
+ });
+ assertMungedBinding(injector, String.class, "foo", "foo");
+ }
}