ModuleAnnotatedMethodScannerTest.java revision 7445e44ba8acbbfc09116fec71d59066cdae8721
1e18906acc38e436613d01b0b96cf5c09623ec987sameb/** 2e18906acc38e436613d01b0b96cf5c09623ec987sameb * Copyright (C) 2015 Google Inc. 3e18906acc38e436613d01b0b96cf5c09623ec987sameb * 4e18906acc38e436613d01b0b96cf5c09623ec987sameb * Licensed under the Apache License, Version 2.0 (the "License"); 5e18906acc38e436613d01b0b96cf5c09623ec987sameb * you may not use this file except in compliance with the License. 6e18906acc38e436613d01b0b96cf5c09623ec987sameb * You may obtain a copy of the License at 7e18906acc38e436613d01b0b96cf5c09623ec987sameb * 8e18906acc38e436613d01b0b96cf5c09623ec987sameb * http://www.apache.org/licenses/LICENSE-2.0 9e18906acc38e436613d01b0b96cf5c09623ec987sameb * 10e18906acc38e436613d01b0b96cf5c09623ec987sameb * Unless required by applicable law or agreed to in writing, software 11e18906acc38e436613d01b0b96cf5c09623ec987sameb * distributed under the License is distributed on an "AS IS" BASIS, 12e18906acc38e436613d01b0b96cf5c09623ec987sameb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13e18906acc38e436613d01b0b96cf5c09623ec987sameb * See the License for the specific language governing permissions and 14e18906acc38e436613d01b0b96cf5c09623ec987sameb * limitations under the License. 15e18906acc38e436613d01b0b96cf5c09623ec987sameb */ 16e18906acc38e436613d01b0b96cf5c09623ec987sameb 17e18906acc38e436613d01b0b96cf5c09623ec987samebpackage com.google.inject.spi; 18e18906acc38e436613d01b0b96cf5c09623ec987sameb 19e18906acc38e436613d01b0b96cf5c09623ec987samebimport static com.google.inject.Asserts.assertContains; 20e18906acc38e436613d01b0b96cf5c09623ec987samebimport static com.google.inject.name.Names.named; 21e18906acc38e436613d01b0b96cf5c09623ec987samebimport static java.lang.annotation.ElementType.METHOD; 22e18906acc38e436613d01b0b96cf5c09623ec987samebimport static java.lang.annotation.RetentionPolicy.RUNTIME; 23e18906acc38e436613d01b0b96cf5c09623ec987sameb 247445e44ba8acbbfc09116fec71d59066cdae8721samebimport com.google.common.collect.Iterables; 257445e44ba8acbbfc09116fec71d59066cdae8721samebimport com.google.common.collect.ImmutableList; 26e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.common.collect.ImmutableSet; 27e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.AbstractModule; 28e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Binder; 29e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Binding; 30e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.CreationException; 31e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Guice; 32e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Injector; 33e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Key; 34e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.Module; 35e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.internal.util.StackTraceElements; 36e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.name.Named; 37e18906acc38e436613d01b0b96cf5c09623ec987samebimport com.google.inject.name.Names; 38e18906acc38e436613d01b0b96cf5c09623ec987sameb 39e18906acc38e436613d01b0b96cf5c09623ec987samebimport junit.framework.TestCase; 40e18906acc38e436613d01b0b96cf5c09623ec987sameb 41e18906acc38e436613d01b0b96cf5c09623ec987samebimport java.lang.annotation.Annotation; 42e18906acc38e436613d01b0b96cf5c09623ec987samebimport java.lang.annotation.Documented; 43e18906acc38e436613d01b0b96cf5c09623ec987samebimport java.lang.annotation.Retention; 44e18906acc38e436613d01b0b96cf5c09623ec987samebimport java.lang.annotation.Target; 45e18906acc38e436613d01b0b96cf5c09623ec987samebimport java.util.Set; 46e18906acc38e436613d01b0b96cf5c09623ec987sameb 47e18906acc38e436613d01b0b96cf5c09623ec987sameb/** Tests for {@link ModuleAnnotatedMethodScanner} usage. */ 48e18906acc38e436613d01b0b96cf5c09623ec987samebpublic class ModuleAnnotatedMethodScannerTest extends TestCase { 49e18906acc38e436613d01b0b96cf5c09623ec987sameb 50e18906acc38e436613d01b0b96cf5c09623ec987sameb public void testScanning() throws Exception { 51e18906acc38e436613d01b0b96cf5c09623ec987sameb Module module = new AbstractModule() { 52e18906acc38e436613d01b0b96cf5c09623ec987sameb @Override protected void configure() { 53e18906acc38e436613d01b0b96cf5c09623ec987sameb install(new NamedMunger().forModule(this)); 54e18906acc38e436613d01b0b96cf5c09623ec987sameb } 55e18906acc38e436613d01b0b96cf5c09623ec987sameb 56e18906acc38e436613d01b0b96cf5c09623ec987sameb @TestProvides @Named("foo") String foo() { 57e18906acc38e436613d01b0b96cf5c09623ec987sameb return "foo"; 58e18906acc38e436613d01b0b96cf5c09623ec987sameb } 59e18906acc38e436613d01b0b96cf5c09623ec987sameb 60e18906acc38e436613d01b0b96cf5c09623ec987sameb @TestProvides @Named("foo2") String foo2() { 61e18906acc38e436613d01b0b96cf5c09623ec987sameb return "foo2"; 62e18906acc38e436613d01b0b96cf5c09623ec987sameb } 63e18906acc38e436613d01b0b96cf5c09623ec987sameb }; 64e18906acc38e436613d01b0b96cf5c09623ec987sameb Injector injector = Guice.createInjector(module); 65e18906acc38e436613d01b0b96cf5c09623ec987sameb 66e18906acc38e436613d01b0b96cf5c09623ec987sameb // assert no bindings named "foo" or "foo2" exist -- they were munged. 67e18906acc38e436613d01b0b96cf5c09623ec987sameb assertNull(injector.getExistingBinding(Key.get(String.class, named("foo")))); 68e18906acc38e436613d01b0b96cf5c09623ec987sameb assertNull(injector.getExistingBinding(Key.get(String.class, named("foo2")))); 69e18906acc38e436613d01b0b96cf5c09623ec987sameb 70e18906acc38e436613d01b0b96cf5c09623ec987sameb Binding<String> fooBinding = injector.getBinding(Key.get(String.class, named("foo-munged"))); 71e18906acc38e436613d01b0b96cf5c09623ec987sameb Binding<String> foo2Binding = injector.getBinding(Key.get(String.class, named("foo2-munged"))); 72e18906acc38e436613d01b0b96cf5c09623ec987sameb assertEquals("foo", fooBinding.getProvider().get()); 73e18906acc38e436613d01b0b96cf5c09623ec987sameb assertEquals("foo2", foo2Binding.getProvider().get()); 74e18906acc38e436613d01b0b96cf5c09623ec987sameb 75e18906acc38e436613d01b0b96cf5c09623ec987sameb // Validate the provider has a sane toString 76e18906acc38e436613d01b0b96cf5c09623ec987sameb assertEquals(methodName(TestProvides.class, "foo", module), 77e18906acc38e436613d01b0b96cf5c09623ec987sameb fooBinding.getProvider().toString()); 78e18906acc38e436613d01b0b96cf5c09623ec987sameb assertEquals(methodName(TestProvides.class, "foo2", module), 79e18906acc38e436613d01b0b96cf5c09623ec987sameb foo2Binding.getProvider().toString()); 80e18906acc38e436613d01b0b96cf5c09623ec987sameb } 81e18906acc38e436613d01b0b96cf5c09623ec987sameb 82e18906acc38e436613d01b0b96cf5c09623ec987sameb public void testMoreThanOneClaimedAnnotationFails() throws Exception { 83e18906acc38e436613d01b0b96cf5c09623ec987sameb final NamedMunger scanner = new NamedMunger(); 84e18906acc38e436613d01b0b96cf5c09623ec987sameb Module module = new AbstractModule() { 85e18906acc38e436613d01b0b96cf5c09623ec987sameb @Override protected void configure() { 86e18906acc38e436613d01b0b96cf5c09623ec987sameb install(scanner.forModule(this)); 87e18906acc38e436613d01b0b96cf5c09623ec987sameb } 88e18906acc38e436613d01b0b96cf5c09623ec987sameb 89e18906acc38e436613d01b0b96cf5c09623ec987sameb @TestProvides @TestProvides2 String foo() { 90e18906acc38e436613d01b0b96cf5c09623ec987sameb return "foo"; 91e18906acc38e436613d01b0b96cf5c09623ec987sameb } 92e18906acc38e436613d01b0b96cf5c09623ec987sameb }; 93e18906acc38e436613d01b0b96cf5c09623ec987sameb try { 94e18906acc38e436613d01b0b96cf5c09623ec987sameb Guice.createInjector(module); 95e18906acc38e436613d01b0b96cf5c09623ec987sameb fail(); 96e18906acc38e436613d01b0b96cf5c09623ec987sameb } catch(CreationException expected) { 97e18906acc38e436613d01b0b96cf5c09623ec987sameb assertEquals(1, expected.getErrorMessages().size()); 98e18906acc38e436613d01b0b96cf5c09623ec987sameb assertContains(expected.getMessage(), 99e18906acc38e436613d01b0b96cf5c09623ec987sameb "More than one annotation claimed by " + scanner + " on method " 100e18906acc38e436613d01b0b96cf5c09623ec987sameb + module.getClass().getName() + ".foo(). Methods can only have " 101e18906acc38e436613d01b0b96cf5c09623ec987sameb + "one annotation claimed per scanner."); 102e18906acc38e436613d01b0b96cf5c09623ec987sameb } 103e18906acc38e436613d01b0b96cf5c09623ec987sameb } 104e18906acc38e436613d01b0b96cf5c09623ec987sameb 105e18906acc38e436613d01b0b96cf5c09623ec987sameb private String methodName(Class<? extends Annotation> annotation, String method, Object container) 106e18906acc38e436613d01b0b96cf5c09623ec987sameb throws Exception { 107e18906acc38e436613d01b0b96cf5c09623ec987sameb return "@" + annotation.getName() + " " 108e18906acc38e436613d01b0b96cf5c09623ec987sameb + StackTraceElements.forMember(container.getClass().getDeclaredMethod(method)); 109e18906acc38e436613d01b0b96cf5c09623ec987sameb } 110e18906acc38e436613d01b0b96cf5c09623ec987sameb 111e18906acc38e436613d01b0b96cf5c09623ec987sameb @Documented @Target(METHOD) @Retention(RUNTIME) 112e18906acc38e436613d01b0b96cf5c09623ec987sameb private @interface TestProvides {} 113e18906acc38e436613d01b0b96cf5c09623ec987sameb 114e18906acc38e436613d01b0b96cf5c09623ec987sameb @Documented @Target(METHOD) @Retention(RUNTIME) 115e18906acc38e436613d01b0b96cf5c09623ec987sameb private @interface TestProvides2 {} 116e18906acc38e436613d01b0b96cf5c09623ec987sameb 117e18906acc38e436613d01b0b96cf5c09623ec987sameb private static class NamedMunger extends ModuleAnnotatedMethodScanner { 118e18906acc38e436613d01b0b96cf5c09623ec987sameb @Override 119e18906acc38e436613d01b0b96cf5c09623ec987sameb public Set<? extends Class<? extends Annotation>> annotationClasses() { 120e18906acc38e436613d01b0b96cf5c09623ec987sameb return ImmutableSet.of(TestProvides.class, TestProvides2.class); 121e18906acc38e436613d01b0b96cf5c09623ec987sameb } 122e18906acc38e436613d01b0b96cf5c09623ec987sameb 123e18906acc38e436613d01b0b96cf5c09623ec987sameb @Override 124e18906acc38e436613d01b0b96cf5c09623ec987sameb public <T> Key<T> prepareMethod(Binder binder, Annotation annotation, Key<T> key, 125e18906acc38e436613d01b0b96cf5c09623ec987sameb InjectionPoint injectionPoint) { 126e18906acc38e436613d01b0b96cf5c09623ec987sameb return Key.get(key.getTypeLiteral(), 127e18906acc38e436613d01b0b96cf5c09623ec987sameb Names.named(((Named) key.getAnnotation()).value() + "-munged")); 128e18906acc38e436613d01b0b96cf5c09623ec987sameb } 129e18906acc38e436613d01b0b96cf5c09623ec987sameb } 1307445e44ba8acbbfc09116fec71d59066cdae8721sameb 1317445e44ba8acbbfc09116fec71d59066cdae8721sameb public void testFailingScanner_scannerOutsideModule() { 1327445e44ba8acbbfc09116fec71d59066cdae8721sameb try { 1337445e44ba8acbbfc09116fec71d59066cdae8721sameb Guice.createInjector(new FailingScanner().forModule(new SomeModule())); 1347445e44ba8acbbfc09116fec71d59066cdae8721sameb fail(); 1357445e44ba8acbbfc09116fec71d59066cdae8721sameb } catch (CreationException expected) { 1367445e44ba8acbbfc09116fec71d59066cdae8721sameb Message m = Iterables.getOnlyElement(expected.getErrorMessages()); 1377445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals( 1387445e44ba8acbbfc09116fec71d59066cdae8721sameb "An exception was caught and reported. Message: Failing in the scanner.", 1397445e44ba8acbbfc09116fec71d59066cdae8721sameb m.getMessage()); 1407445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(IllegalStateException.class, m.getCause().getClass()); 1417445e44ba8acbbfc09116fec71d59066cdae8721sameb ElementSource source = (ElementSource) Iterables.getOnlyElement(m.getSources()); 1427445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(SomeModule.class.getName(), 1437445e44ba8acbbfc09116fec71d59066cdae8721sameb Iterables.getOnlyElement(source.getModuleClassNames())); 1447445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(String.class.getName() + " " + SomeModule.class.getName() + ".aString()", 1457445e44ba8acbbfc09116fec71d59066cdae8721sameb source.toString()); 1467445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1477445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1487445e44ba8acbbfc09116fec71d59066cdae8721sameb 1497445e44ba8acbbfc09116fec71d59066cdae8721sameb public void testFailingScanner_scannerInModule() { 1507445e44ba8acbbfc09116fec71d59066cdae8721sameb Module module = new AbstractModule() { 1517445e44ba8acbbfc09116fec71d59066cdae8721sameb @Override public void configure() { 1527445e44ba8acbbfc09116fec71d59066cdae8721sameb install(new FailingScanner().forModule(new SomeModule())); 1537445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1547445e44ba8acbbfc09116fec71d59066cdae8721sameb }; 1557445e44ba8acbbfc09116fec71d59066cdae8721sameb try { 1567445e44ba8acbbfc09116fec71d59066cdae8721sameb Guice.createInjector(module); 1577445e44ba8acbbfc09116fec71d59066cdae8721sameb fail(); 1587445e44ba8acbbfc09116fec71d59066cdae8721sameb } catch (CreationException expected) { 1597445e44ba8acbbfc09116fec71d59066cdae8721sameb Message m = Iterables.getOnlyElement(expected.getErrorMessages()); 1607445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals( 1617445e44ba8acbbfc09116fec71d59066cdae8721sameb "An exception was caught and reported. Message: Failing in the scanner.", 1627445e44ba8acbbfc09116fec71d59066cdae8721sameb m.getMessage()); 1637445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(IllegalStateException.class, m.getCause().getClass()); 1647445e44ba8acbbfc09116fec71d59066cdae8721sameb ElementSource source = (ElementSource) Iterables.getOnlyElement(m.getSources()); 1657445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(ImmutableList.of(SomeModule.class.getName(), module.getClass().getName()), 1667445e44ba8acbbfc09116fec71d59066cdae8721sameb source.getModuleClassNames()); 1677445e44ba8acbbfc09116fec71d59066cdae8721sameb assertEquals(String.class.getName() + " " + SomeModule.class.getName() + ".aString()", 1687445e44ba8acbbfc09116fec71d59066cdae8721sameb source.toString()); 1697445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1707445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1717445e44ba8acbbfc09116fec71d59066cdae8721sameb 1727445e44ba8acbbfc09116fec71d59066cdae8721sameb public static class FailingScanner extends ModuleAnnotatedMethodScanner { 1737445e44ba8acbbfc09116fec71d59066cdae8721sameb @Override public Set<? extends Class<? extends Annotation>> annotationClasses() { 1747445e44ba8acbbfc09116fec71d59066cdae8721sameb return ImmutableSet.of(TestProvides.class); 1757445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1767445e44ba8acbbfc09116fec71d59066cdae8721sameb 1777445e44ba8acbbfc09116fec71d59066cdae8721sameb @Override public <T> Key<T> prepareMethod( 1787445e44ba8acbbfc09116fec71d59066cdae8721sameb Binder binder, Annotation rawAnnotation, Key<T> key, InjectionPoint injectionPoint) { 1797445e44ba8acbbfc09116fec71d59066cdae8721sameb throw new IllegalStateException("Failing in the scanner."); 1807445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1817445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1827445e44ba8acbbfc09116fec71d59066cdae8721sameb 1837445e44ba8acbbfc09116fec71d59066cdae8721sameb static class SomeModule extends AbstractModule { 1847445e44ba8acbbfc09116fec71d59066cdae8721sameb @TestProvides String aString() { 1857445e44ba8acbbfc09116fec71d59066cdae8721sameb return "Foo"; 1867445e44ba8acbbfc09116fec71d59066cdae8721sameb } 1877445e44ba8acbbfc09116fec71d59066cdae8721sameb 1887445e44ba8acbbfc09116fec71d59066cdae8721sameb @Override protected void configure() {} 1897445e44ba8acbbfc09116fec71d59066cdae8721sameb } 190e18906acc38e436613d01b0b96cf5c09623ec987sameb} 191