/** * Copyright (C) 2009 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.googlecode.guice; import com.google.inject.AbstractModule; import static com.google.inject.Asserts.assertContains; import com.google.inject.CreationException; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Key; import com.google.inject.Scope; import com.google.inject.Scopes; import com.google.inject.Stage; import com.google.inject.TypeLiteral; import com.google.inject.name.Names; import com.google.inject.util.Jsr330; import java.lang.annotation.Annotation; import java.lang.annotation.Retention; import static java.lang.annotation.RetentionPolicy.RUNTIME; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Qualifier; import javax.inject.Singleton; import junit.framework.TestCase; public class Jsr330Test extends TestCase { private final B b = new B(); private final C c = new C(); private final D d = new D(); private final E e = new E(); @Override protected void setUp() throws Exception { J.nextInstanceId = 0; K.nextInstanceId = 0; } public void testInject() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).toInstance(b); bind(C.class).toInstance(c); bind(D.class).toInstance(d); bind(E.class).toInstance(e); bind(A.class); } }); A a = injector.getInstance(A.class); assertSame(b, a.b); assertSame(c, a.c); assertSame(d, a.d); assertSame(e, a.e); } public void testQualifiedInject() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b); bind(C.class).annotatedWith(Red.class).toInstance(c); bind(D.class).annotatedWith(RED).toInstance(d); bind(E.class).annotatedWith(Names.named("jesse")).toInstance(e); bind(F.class); } }); F f = injector.getInstance(F.class); assertSame(b, f.b); assertSame(c, f.c); assertSame(d, f.d); assertSame(e, f.e); } public void testProviderInject() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).annotatedWith(Names.named("jodie")).toInstance(b); bind(C.class).toInstance(c); bind(D.class).annotatedWith(RED).toInstance(d); bind(E.class).toInstance(e); bind(G.class); } }); G g = injector.getInstance(G.class); assertSame(b, g.bProvider.get()); assertSame(c, g.cProvider.get()); assertSame(d, g.dProvider.get()); assertSame(e, g.eProvider.get()); } public void testScopeAnnotation() { final TestScope scope = new TestScope(); Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).in(scope); bind(C.class).in(TestScoped.class); bindScope(TestScoped.class, scope); } }); B b = injector.getInstance(B.class); assertSame(b, injector.getInstance(B.class)); assertSame(b, injector.getInstance(B.class)); C c = injector.getInstance(C.class); assertSame(c, injector.getInstance(C.class)); assertSame(c, injector.getInstance(C.class)); H h = injector.getInstance(H.class); assertSame(h, injector.getInstance(H.class)); assertSame(h, injector.getInstance(H.class)); scope.reset(); assertNotSame(b, injector.getInstance(B.class)); assertNotSame(c, injector.getInstance(C.class)); assertNotSame(h, injector.getInstance(H.class)); } public void testSingleton() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).in(Singleton.class); } }); B b = injector.getInstance(B.class); assertSame(b, injector.getInstance(B.class)); assertSame(b, injector.getInstance(B.class)); J j = injector.getInstance(J.class); assertSame(j, injector.getInstance(J.class)); assertSame(j, injector.getInstance(J.class)); } public void testEagerSingleton() { Guice.createInjector(Stage.PRODUCTION, new AbstractModule() { protected void configure() { bind(J.class); bind(K.class).in(Singleton.class); } }); assertEquals(1, J.nextInstanceId); assertEquals(1, K.nextInstanceId); } public void testScopesIsSingleton() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(J.class); bind(K.class).in(Singleton.class); } }); assertTrue(Scopes.isSingleton(injector.getBinding(J.class))); assertTrue(Scopes.isSingleton(injector.getBinding(K.class))); } public void testInjectingFinalFieldsIsForbidden() { try { Guice.createInjector(new AbstractModule() { protected void configure() { bind(L.class); } }); fail(); } catch (CreationException expected) { assertContains(expected.getMessage(), "1) Injected field " + L.class.getName() + ".b cannot be final."); } } public void testInjectingAbstractMethodsIsForbidden() { try { Guice.createInjector(new AbstractModule() { protected void configure() { bind(M.class); } }); fail(); } catch (CreationException expected) { assertContains(expected.getMessage(), "1) Injected method " + AbstractM.class.getName() + ".setB() cannot be abstract."); } } public void testInjectingMethodsWithTypeParametersIsForbidden() { try { Guice.createInjector(new AbstractModule() { protected void configure() { bind(N.class); } }); fail(); } catch (CreationException expected) { assertContains(expected.getMessage(), "1) Injected method " + N.class.getName() + ".setB() cannot declare type parameters of its own."); } } public void testInjectingMethodsWithNonVoidReturnTypes() { Guice.createInjector(new AbstractModule() { protected void configure() { bind(P.class); } }); } /** * This test verifies that we can compile bindings to provider instances * whose compile-time type implements javax.inject.Provider but not * com.google.inject.Provider. For binary compatibility, we don't (and won't) * support binding to instances of javax.inject.Provider. */ public void testBindProviderClass() { Injector injector = Guice.createInjector(new AbstractModule() { protected void configure() { bind(B.class).toProvider(BProvider.class); bind(B.class).annotatedWith(Names.named("1")).toProvider(BProvider.class); bind(B.class).annotatedWith(Names.named("2")).toProvider(Key.get(BProvider.class)); bind(B.class).annotatedWith(Names.named("3")).toProvider(TypeLiteral.get(BProvider.class)); } }); injector.getInstance(Key.get(B.class)); injector.getInstance(Key.get(B.class, Names.named("1"))); injector.getInstance(Key.get(B.class, Names.named("2"))); injector.getInstance(Key.get(B.class, Names.named("3"))); } public void testGuicify330Provider() { Provider<String> jsr330Provider = new Provider<String>() { public String get() { return "A"; } @Override public String toString() { return "jsr330Provider"; } }; com.google.inject.Provider<String> guicified = Jsr330.guicify(jsr330Provider); assertEquals("guicified(jsr330Provider)", guicified.toString()); assertEquals("A", guicified.get()); // when you guicify the Guice-friendly, it's a no-op assertSame(guicified, Jsr330.guicify(guicified)); } static class A { final B b; @Inject C c; D d; E e; @Inject A(B b) { this.b = b; } @Inject void injectD(D d, E e) { this.d = d; this.e = e; } } static class B {} static class C {} static class D {} static class E {} static class F { final B b; @Inject @Red C c; D d; E e; @Inject F(@Named("jodie") B b) { this.b = b; } @Inject void injectD(@Red D d, @Named("jesse") E e) { this.d = d; this.e = e; } } @Qualifier @Retention(RUNTIME) @interface Red {} public static final Red RED = new Red() { public Class<? extends Annotation> annotationType() { return Red.class; } @Override public boolean equals(Object obj) { return obj instanceof Red; } @Override public int hashCode() { return 0; } }; static class G { final Provider<B> bProvider; @Inject Provider<C> cProvider; Provider<D> dProvider; Provider<E> eProvider; @Inject G(@Named("jodie") Provider<B> bProvider) { this.bProvider = bProvider; } @Inject void injectD(@Red Provider<D> dProvider, Provider<E> eProvider) { this.dProvider = dProvider; this.eProvider = eProvider; } } @javax.inject.Scope @Retention(RUNTIME) @interface TestScoped {} static class TestScope implements Scope { private int now = 0; public <T> com.google.inject.Provider<T> scope(Key<T> key, final com.google.inject.Provider<T> unscoped) { return new com.google.inject.Provider<T>() { private T value; private int snapshotTime = -1; public T get() { if (snapshotTime != now) { value = unscoped.get(); snapshotTime = now; } return value; } }; } public void reset() { now++; } } @TestScoped static class H {} @Singleton static class J { static int nextInstanceId = 0; int instanceId = nextInstanceId++; } static class K { static int nextInstanceId = 0; int instanceId = nextInstanceId++; } static class L { @Inject final B b = null; } static abstract class AbstractM { @Inject abstract void setB(B b); } static class M extends AbstractM { void setB(B b) {} } static class N { @Inject <T> void setB(B b) {} } static class P { @Inject B setB(B b) { return b; } } static class BProvider implements Provider<B> { public B get() { return new B(); } } }