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