| /** |
| * Copyright (C) 2007 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.google.inject.throwingproviders; |
| |
| import static java.lang.annotation.ElementType.METHOD; |
| import static java.lang.annotation.RetentionPolicy.RUNTIME; |
| |
| import com.google.common.base.Function; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableSet; |
| import com.google.common.collect.Iterables; |
| import com.google.common.collect.Lists; |
| import com.google.inject.AbstractModule; |
| import com.google.inject.Asserts; |
| import com.google.inject.BindingAnnotation; |
| import com.google.inject.CreationException; |
| import com.google.inject.Guice; |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| import com.google.inject.Key; |
| import com.google.inject.OutOfScopeException; |
| import com.google.inject.Provider; |
| import com.google.inject.ProvisionException; |
| import com.google.inject.Scope; |
| import com.google.inject.ScopeAnnotation; |
| import com.google.inject.TypeLiteral; |
| import com.google.inject.internal.util.Classes; |
| import com.google.inject.name.Named; |
| import com.google.inject.name.Names; |
| import com.google.inject.spi.Dependency; |
| import com.google.inject.spi.HasDependencies; |
| import com.google.inject.spi.Message; |
| import com.google.inject.throwingproviders.ThrowingProviderBinder.Result; |
| |
| import junit.framework.TestCase; |
| |
| import java.io.IOException; |
| import java.lang.annotation.Annotation; |
| import java.lang.annotation.ElementType; |
| import java.lang.annotation.Retention; |
| import java.lang.annotation.RetentionPolicy; |
| import java.lang.annotation.Target; |
| import java.net.BindException; |
| import java.rmi.AccessException; |
| import java.rmi.RemoteException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| import java.util.Set; |
| import java.util.TooManyListenersException; |
| |
| /** |
| * @author jmourits@google.com (Jerome Mourits) |
| * @author jessewilson@google.com (Jesse Wilson) |
| * @author sameb@google.com (Sam Berlin) |
| */ |
| public class CheckedProviderTest extends TestCase { |
| @Target(METHOD) @Retention(RUNTIME) @BindingAnnotation |
| @interface NotExceptionScoping { }; |
| |
| private static final Function<Dependency<?>, Key<?>> DEPENDENCY_TO_KEY = |
| new Function<Dependency<?>, Key<?>>() { |
| public Key<?> apply(Dependency<?> from) { |
| return from.getKey(); |
| } |
| }; |
| |
| private final TypeLiteral<RemoteProvider<Foo>> remoteProviderOfFoo |
| = new TypeLiteral<RemoteProvider<Foo>>() { }; |
| private final MockRemoteProvider<Foo> mockRemoteProvider = new MockRemoteProvider<Foo>(); |
| private final TestScope testScope = new TestScope(); |
| |
| private Injector bindInjector; |
| private Injector providesInjector; |
| private Injector cxtorInjector; |
| |
| @Override |
| protected void setUp() throws Exception { |
| MockFoo.nextToThrow = null; |
| MockFoo.nextToReturn = null; |
| AnotherMockFoo.nextToThrow = null; |
| AnotherMockFoo.nextToReturn = null; |
| |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .to(mockRemoteProvider) |
| .in(testScope); |
| |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .annotatedWith(NotExceptionScoping.class) |
| .scopeExceptions(false) |
| .to(mockRemoteProvider) |
| .in(testScope); |
| |
| } |
| }); |
| |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| bindScope(TestScope.Scoped.class, testScope); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| @TestScope.Scoped |
| Foo throwOrGet() throws RemoteException, BindException { |
| return mockRemoteProvider.get(); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(value = RemoteProvider.class, scopeExceptions = false) |
| @NotExceptionScoping |
| @TestScope.Scoped |
| Foo notExceptionScopingThrowOrGet() throws RemoteException, BindException { |
| return mockRemoteProvider.get(); |
| } |
| |
| }); |
| |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(MockFoo.class) |
| .in(testScope); |
| |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .annotatedWith(NotExceptionScoping.class) |
| .scopeExceptions(false) |
| .providing(MockFoo.class) |
| .in(testScope); |
| |
| } |
| }); |
| } |
| |
| public void testExceptionsThrown_Bind() throws Exception { |
| tExceptionsThrown(bindInjector); |
| } |
| |
| public void testExceptionsThrown_Provides() throws Exception { |
| tExceptionsThrown(providesInjector); |
| } |
| |
| public void testExceptionsThrown_Cxtor() throws Exception { |
| tExceptionsThrown(cxtorInjector); |
| } |
| |
| private void tExceptionsThrown(Injector injector) throws Exception { |
| RemoteProvider<Foo> remoteProvider = |
| injector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| mockRemoteProvider.throwOnNextGet(new BindException("kaboom!")); |
| MockFoo.nextToThrow = new BindException("kaboom!"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (BindException expected) { |
| assertEquals("kaboom!", expected.getMessage()); |
| } |
| } |
| |
| public void testValuesScoped_Bind() throws Exception { |
| tValuesScoped(bindInjector, null); |
| } |
| |
| public void testValuesScoped_Provides() throws Exception { |
| tValuesScoped(providesInjector, null); |
| } |
| |
| public void testValuesScopedWhenNotExceptionScoping_Bind() throws Exception { |
| tValuesScoped(bindInjector, NotExceptionScoping.class); |
| } |
| |
| public void testValuesScopedWhenNotExceptionScoping_Provides() throws Exception { |
| tValuesScoped(providesInjector, NotExceptionScoping.class); |
| } |
| |
| private void tValuesScoped(Injector injector, |
| Class<? extends Annotation> annotation) throws Exception { |
| Key<RemoteProvider<Foo>> key = annotation != null ? |
| Key.get(remoteProviderOfFoo, annotation) : |
| Key.get(remoteProviderOfFoo); |
| RemoteProvider<Foo> remoteProvider = injector.getInstance(key); |
| |
| mockRemoteProvider.setNextToReturn(new SimpleFoo("A")); |
| assertEquals("A", remoteProvider.get().s()); |
| |
| mockRemoteProvider.setNextToReturn(new SimpleFoo("B")); |
| assertEquals("A", remoteProvider.get().s()); |
| |
| testScope.beginNewScope(); |
| assertEquals("B", remoteProvider.get().s()); |
| } |
| |
| public void testValuesScoped_Cxtor() throws Exception { |
| RemoteProvider<Foo> remoteProvider = |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| Foo retrieved = remoteProvider.get(); |
| assertSame(retrieved, remoteProvider.get()); // same, not in new scope. |
| |
| testScope.beginNewScope(); |
| assertNotSame(retrieved, remoteProvider.get()); // different, new scope. |
| } |
| |
| public void testExceptionsScoped_Bind() throws Exception { |
| tExceptionsScoped(bindInjector); |
| } |
| |
| public void testExceptionsScoped_Provides() throws Exception { |
| tExceptionsScoped(providesInjector); |
| } |
| |
| public void testExceptionScopes_Cxtor() throws Exception { |
| tExceptionsScoped(cxtorInjector); |
| } |
| |
| private void tExceptionsScoped(Injector injector) throws Exception { |
| RemoteProvider<Foo> remoteProvider = |
| injector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| mockRemoteProvider.throwOnNextGet(new RemoteException("A")); |
| MockFoo.nextToThrow = new RemoteException("A"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertEquals("A", expected.getMessage()); |
| } |
| |
| mockRemoteProvider.throwOnNextGet(new RemoteException("B")); |
| MockFoo.nextToThrow = new RemoteException("B"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertEquals("A", expected.getMessage()); |
| } |
| } |
| |
| public void testExceptionsNotScopedWhenNotExceptionScoping_Bind() throws Exception { |
| tExceptionsNotScopedWhenNotExceptionScoping(bindInjector); |
| } |
| |
| public void testExceptionsNotScopedWhenNotExceptionScoping_Provides() throws Exception { |
| tExceptionsNotScopedWhenNotExceptionScoping(providesInjector); |
| } |
| |
| public void testExceptionNotScopedWhenNotExceptionScoping_Cxtor() throws Exception { |
| tExceptionsNotScopedWhenNotExceptionScoping(cxtorInjector); |
| } |
| |
| private void tExceptionsNotScopedWhenNotExceptionScoping(Injector injector) throws Exception { |
| RemoteProvider<Foo> remoteProvider = |
| injector.getInstance(Key.get(remoteProviderOfFoo, NotExceptionScoping.class)); |
| |
| mockRemoteProvider.throwOnNextGet(new RemoteException("A")); |
| MockFoo.nextToThrow = new RemoteException("A"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertEquals("A", expected.getMessage()); |
| } |
| |
| mockRemoteProvider.throwOnNextGet(new RemoteException("B")); |
| MockFoo.nextToThrow = new RemoteException("B"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertEquals("B", expected.getMessage()); |
| } |
| } |
| |
| public void testAnnotations_Bind() throws Exception { |
| final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>(); |
| final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>(); |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .annotatedWith(Names.named("a")) |
| .to(mockRemoteProviderA); |
| |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .to(mockRemoteProviderB); |
| } |
| }); |
| tAnnotations(bindInjector, mockRemoteProviderA, mockRemoteProviderB); |
| } |
| |
| public void testAnnotations_Provides() throws Exception { |
| final MockRemoteProvider<Foo> mockRemoteProviderA = new MockRemoteProvider<Foo>(); |
| final MockRemoteProvider<Foo> mockRemoteProviderB = new MockRemoteProvider<Foo>(); |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| @Named("a") |
| Foo throwOrGet() throws RemoteException, BindException { |
| return mockRemoteProviderA.get(); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| Foo throwOrGet2() throws RemoteException, BindException { |
| return mockRemoteProviderB.get(); |
| } |
| }); |
| tAnnotations(providesInjector, mockRemoteProviderA, mockRemoteProviderB); |
| } |
| |
| private void tAnnotations(Injector injector, MockRemoteProvider<Foo> mockA, |
| MockRemoteProvider<Foo> mockB) throws Exception { |
| mockA.setNextToReturn(new SimpleFoo("A")); |
| mockB.setNextToReturn(new SimpleFoo("B")); |
| assertEquals("A", |
| injector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s()); |
| |
| assertEquals("B", |
| injector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); |
| } |
| |
| public void testAnnotations_Cxtor() throws Exception { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .annotatedWith(Names.named("a")) |
| .providing(MockFoo.class); |
| |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(AnotherMockFoo.class); |
| } |
| }); |
| MockFoo.nextToReturn = "A"; |
| AnotherMockFoo.nextToReturn = "B"; |
| assertEquals("A", |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo, Names.named("a"))).get().s()); |
| |
| assertEquals("B", |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); |
| } |
| |
| public void testUndeclaredExceptions_Bind() throws Exception { |
| tUndeclaredExceptions(bindInjector); |
| } |
| |
| public void testUndeclaredExceptions_Provides() throws Exception { |
| tUndeclaredExceptions(providesInjector); |
| } |
| |
| public void testUndeclaredExceptions_Cxtor() throws Exception { |
| tUndeclaredExceptions(cxtorInjector); |
| } |
| |
| private void tUndeclaredExceptions(Injector injector) throws Exception { |
| RemoteProvider<Foo> remoteProvider = |
| injector.getInstance(Key.get(remoteProviderOfFoo)); |
| mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("A")); |
| MockFoo.nextToThrow = new IndexOutOfBoundsException("A"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RuntimeException e) { |
| assertEquals("A", e.getCause().getMessage()); |
| } |
| |
| // undeclared exceptions shouldn't be scoped |
| mockRemoteProvider.throwOnNextGet(new IndexOutOfBoundsException("B")); |
| MockFoo.nextToThrow = new IndexOutOfBoundsException("B"); |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RuntimeException e) { |
| assertEquals("B", e.getCause().getMessage()); |
| } |
| } |
| |
| public void testThrowingProviderSubclassing() throws Exception { |
| final SubMockRemoteProvider aProvider = new SubMockRemoteProvider(); |
| aProvider.setNextToReturn(new SimpleFoo("A")); |
| |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .to(aProvider); |
| } |
| }); |
| |
| assertEquals("A", |
| bindInjector.getInstance(Key.get(remoteProviderOfFoo)).get().s()); |
| } |
| |
| static class SubMockRemoteProvider extends MockRemoteProvider<Foo> { } |
| |
| public void testBindingToNonInterfaceType_Bind() throws Exception { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(MockRemoteProvider.class, Foo.class) |
| .to(mockRemoteProvider); |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(MockRemoteProvider.class.getName() + " must be an interface", |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testBindingToNonInterfaceType_Provides() throws Exception { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(MockRemoteProvider.class) |
| Foo foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(MockRemoteProvider.class.getName() + " must be an interface", |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testBindingToSubSubInterface_Bind() throws Exception { |
| try { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(SubRemoteProvider.class, Foo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)", |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testBindingToSubSubInterface_Provides() throws Exception { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(SubRemoteProvider.class) |
| Foo foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(SubRemoteProvider.class.getName() + " must extend CheckedProvider (and only CheckedProvider)", |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| interface SubRemoteProvider extends RemoteProvider<String> { } |
| |
| public void testBindingToInterfaceWithExtraMethod_Bind() throws Exception { |
| try { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProviderWithExtraMethod.class, Foo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared " |
| + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(), |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testBindingToInterfaceWithExtraMethod_Provides() throws Exception { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProviderWithExtraMethod.class) |
| Foo foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch (CreationException expected) { |
| assertEquals(RemoteProviderWithExtraMethod.class.getName() + " may not declare any new methods, but declared " |
| + RemoteProviderWithExtraMethod.class.getDeclaredMethods()[0].toGenericString(), |
| Iterables.getOnlyElement(expected.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testDependencies_Bind() { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(String.class).toInstance("Foo"); |
| bind(Integer.class).toInstance(5); |
| bind(Double.class).toInstance(5d); |
| bind(Long.class).toInstance(5L); |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .to(DependentRemoteProvider.class); |
| } |
| }); |
| |
| HasDependencies hasDependencies = |
| (HasDependencies)bindInjector.getBinding(Key.get(remoteProviderOfFoo)); |
| hasDependencies = |
| (HasDependencies)bindInjector.getBinding( |
| Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); |
| // Make sure that that is dependent on DependentRemoteProvider. |
| assertEquals(Dependency.get(Key.get(DependentRemoteProvider.class)), |
| Iterables.getOnlyElement(hasDependencies.getDependencies())); |
| // And make sure DependentRemoteProvider has the proper dependencies. |
| hasDependencies = (HasDependencies)bindInjector.getBinding(DependentRemoteProvider.class); |
| Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( |
| Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); |
| assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), |
| Key.get(Long.class), Key.get(Double.class)), dependencyKeys); |
| } |
| |
| public void testDependencies_Provides() { |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(String.class).toInstance("Foo"); |
| bind(Integer.class).toInstance(5); |
| bind(Double.class).toInstance(5d); |
| bind(Long.class).toInstance(5L); |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| Foo foo(String s, Integer i, Double d, Long l) { |
| return null; |
| } |
| }); |
| |
| HasDependencies hasDependencies = |
| (HasDependencies) providesInjector.getBinding(Key.get(remoteProviderOfFoo)); |
| // RemoteProvider<String> is dependent on the provider method.. |
| hasDependencies = (HasDependencies) providesInjector.getBinding( |
| Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); |
| // And the provider method has our real dependencies.. |
| hasDependencies = (HasDependencies)providesInjector.getBinding( |
| Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey()); |
| Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( |
| Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); |
| assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), |
| Key.get(Long.class), Key.get(Double.class)), dependencyKeys); |
| } |
| |
| public void testDependencies_Cxtor() { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| bind(String.class).toInstance("Foo"); |
| bind(Integer.class).toInstance(5); |
| bind(Double.class).toInstance(5d); |
| bind(Long.class).toInstance(5L); |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(DependentMockFoo.class); |
| } |
| }); |
| |
| Key<?> key = Key.get(remoteProviderOfFoo); |
| |
| // RemoteProvider<String> is dependent on Result. |
| HasDependencies hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); |
| key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); |
| assertEquals(Result.class, key.getTypeLiteral().getRawType()); |
| |
| // Result is dependent on the fake CheckedProvider impl |
| hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); |
| key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); |
| assertTrue(CheckedProvider.class.isAssignableFrom(key.getTypeLiteral().getRawType())); |
| |
| // And the CheckedProvider is dependent on DependentMockFoo... |
| hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); |
| key = Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey(); |
| assertEquals(DependentMockFoo.class, key.getTypeLiteral().getRawType()); |
| |
| // And DependentMockFoo is dependent on the goods. |
| hasDependencies = (HasDependencies) cxtorInjector.getBinding(key); |
| Set<Key<?>> dependencyKeys = ImmutableSet.copyOf( |
| Iterables.transform(hasDependencies.getDependencies(), DEPENDENCY_TO_KEY)); |
| assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), |
| Key.get(Long.class), Key.get(Double.class)), dependencyKeys); |
| } |
| |
| interface RemoteProviderWithExtraMethod<T> extends CheckedProvider<T> { |
| T get(T defaultValue) throws RemoteException, BindException; |
| } |
| |
| interface RemoteProvider<T> extends CheckedProvider<T> { |
| public T get() throws RemoteException, BindException; |
| } |
| |
| static class DependentMockFoo implements Foo { |
| @Inject double foo; |
| |
| @ThrowingInject public DependentMockFoo(String foo, int bar) { |
| } |
| |
| @Inject void initialize(long foo) {} |
| |
| @Override |
| public String s() { |
| return null; |
| } |
| } |
| |
| static class DependentRemoteProvider<T> implements RemoteProvider<T> { |
| @Inject double foo; |
| |
| @Inject public DependentRemoteProvider(String foo, int bar) { |
| } |
| |
| @Inject void initialize(long foo) {} |
| |
| public T get() { |
| return null; |
| } |
| } |
| |
| interface Foo { |
| String s(); |
| } |
| |
| static class SimpleFoo implements Foo { |
| private String s; |
| |
| SimpleFoo(String s) { |
| this.s = s; |
| } |
| |
| @Override |
| public String s() { |
| return s; |
| } |
| |
| @Override |
| public String toString() { |
| return s; |
| } |
| } |
| |
| static class MockFoo implements Foo { |
| static Exception nextToThrow; |
| static String nextToReturn; |
| |
| @ThrowingInject |
| MockFoo() throws RemoteException, BindException { |
| if (nextToThrow instanceof RemoteException) { |
| throw (RemoteException) nextToThrow; |
| } else if (nextToThrow instanceof BindException) { |
| throw (BindException) nextToThrow; |
| } else if (nextToThrow instanceof RuntimeException) { |
| throw (RuntimeException) nextToThrow; |
| } else if (nextToThrow == null) { |
| // Do nothing, return this. |
| } else { |
| throw new AssertionError("nextToThrow must be a runtime or remote exception"); |
| } |
| } |
| |
| @Override |
| public String s() { |
| return nextToReturn; |
| } |
| |
| @Override |
| public String toString() { |
| return nextToReturn; |
| } |
| } |
| |
| static class AnotherMockFoo implements Foo { |
| static Exception nextToThrow; |
| static String nextToReturn; |
| |
| @ThrowingInject |
| AnotherMockFoo() throws RemoteException, BindException { |
| if (nextToThrow instanceof RemoteException) { |
| throw (RemoteException) nextToThrow; |
| } else if (nextToThrow instanceof BindException) { |
| throw (BindException) nextToThrow; |
| } else if (nextToThrow instanceof RuntimeException) { |
| throw (RuntimeException) nextToThrow; |
| } else if (nextToThrow == null) { |
| // Do nothing, return this. |
| } else { |
| throw new AssertionError("nextToThrow must be a runtime or remote exception"); |
| } |
| } |
| |
| @Override |
| public String s() { |
| return nextToReturn; |
| } |
| |
| @Override |
| public String toString() { |
| return nextToReturn; |
| } |
| } |
| |
| static class MockRemoteProvider<T> implements RemoteProvider<T> { |
| Exception nextToThrow; |
| T nextToReturn; |
| |
| public void throwOnNextGet(Exception nextToThrow) { |
| this.nextToThrow = nextToThrow; |
| } |
| |
| public void setNextToReturn(T nextToReturn) { |
| this.nextToReturn = nextToReturn; |
| } |
| |
| public T get() throws RemoteException, BindException { |
| if (nextToThrow instanceof RemoteException) { |
| throw (RemoteException) nextToThrow; |
| } else if (nextToThrow instanceof BindException) { |
| throw (BindException) nextToThrow; |
| } else if (nextToThrow instanceof RuntimeException) { |
| throw (RuntimeException) nextToThrow; |
| } else if (nextToThrow == null) { |
| return nextToReturn; |
| } else { |
| throw new AssertionError("nextToThrow must be a runtime or remote exception"); |
| } |
| } |
| } |
| |
| public void testBindingToInterfaceWithBoundValueType_Bind() throws RemoteException { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(StringRemoteProvider.class, String.class) |
| .to(new StringRemoteProvider() { |
| public String get() { |
| return "A"; |
| } |
| }); |
| } |
| }); |
| |
| assertEquals("A", bindInjector.getInstance(StringRemoteProvider.class).get()); |
| } |
| |
| public void testBindingToInterfaceWithBoundValueType_Provides() throws RemoteException { |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(StringRemoteProvider.class) |
| String foo() throws RemoteException { |
| return "A"; |
| } |
| }); |
| |
| assertEquals("A", providesInjector.getInstance(StringRemoteProvider.class).get()); |
| } |
| |
| interface StringRemoteProvider extends CheckedProvider<String> { |
| @Override String get() throws RemoteException; |
| } |
| |
| @SuppressWarnings("deprecation") |
| public void testBindingToInterfaceWithGeneric_Bind() throws Exception { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, new TypeLiteral<List<String>>() { }.getType()) |
| .to(new RemoteProvider<List<String>>() { |
| public List<String> get() { |
| return Arrays.asList("A", "B"); |
| } |
| }); |
| } |
| }); |
| |
| Key<RemoteProvider<List<String>>> key |
| = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); |
| assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get()); |
| } |
| |
| public void testBindingToInterfaceWithGeneric_BindUsingTypeLiteral() throws Exception { |
| bindInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {}) |
| .to(new RemoteProvider<List<String>>() { |
| public List<String> get() { |
| return Arrays.asList("A", "B"); |
| } |
| }); |
| } |
| }); |
| |
| Key<RemoteProvider<List<String>>> key |
| = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); |
| assertEquals(Arrays.asList("A", "B"), bindInjector.getInstance(key).get()); |
| } |
| |
| public void testBindingToInterfaceWithGeneric_Provides() throws Exception { |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| List<String> foo() throws RemoteException { |
| return Arrays.asList("A", "B"); |
| } |
| }); |
| |
| Key<RemoteProvider<List<String>>> key |
| = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); |
| assertEquals(Arrays.asList("A", "B"), providesInjector.getInstance(key).get()); |
| } |
| |
| public void testBindingToInterfaceWithGeneric_Cxtor() throws Exception { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, new TypeLiteral<List<String>>() {}) |
| .providing(new TypeLiteral<ThrowingArrayList<String>>() {}); |
| } |
| }); |
| |
| Key<RemoteProvider<List<String>>> key |
| = Key.get(new TypeLiteral<RemoteProvider<List<String>>>() { }); |
| assertEquals(Arrays.asList(), cxtorInjector.getInstance(key).get()); |
| } |
| |
| private static class ThrowingArrayList<T> extends ArrayList<T> { |
| @SuppressWarnings("unused") |
| @ThrowingInject |
| ThrowingArrayList() {} |
| } |
| |
| public void testProviderMethodWithWrongException() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| String foo() throws InterruptedException { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(InterruptedException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testCxtorWithWrongException() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(WrongExceptionFoo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException ce) { |
| assertEquals(InterruptedException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| static class WrongExceptionFoo implements Foo { |
| @SuppressWarnings("unused") |
| @ThrowingInject |
| public WrongExceptionFoo() throws InterruptedException { |
| } |
| |
| @Override |
| public String s() { return null; } |
| } |
| |
| public void testProviderMethodWithSubclassOfExceptionIsOk() throws Exception { |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| Foo foo() throws AccessException { |
| throw new AccessException("boo!"); |
| } |
| }); |
| |
| RemoteProvider<Foo> remoteProvider = |
| providesInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertTrue(expected instanceof AccessException); |
| assertEquals("boo!", expected.getMessage()); |
| } |
| } |
| |
| public void testCxtorWithSubclassOfExceptionIsOk() throws Exception { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(SubclassExceptionFoo.class); |
| } |
| }); |
| |
| RemoteProvider<Foo> remoteProvider = |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RemoteException expected) { |
| assertTrue(expected instanceof AccessException); |
| assertEquals("boo!", expected.getMessage()); |
| } |
| } |
| |
| static class SubclassExceptionFoo implements Foo { |
| @ThrowingInject |
| public SubclassExceptionFoo() throws AccessException { |
| throw new AccessException("boo!"); |
| } |
| |
| @Override |
| public String s() { return null; } |
| } |
| |
| public void testProviderMethodWithSuperclassExceptionFails() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| Foo foo() throws IOException { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(IOException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testCxtorWithSuperclassExceptionFails() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(SuperclassExceptionFoo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException ce) { |
| assertEquals(IOException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| static class SuperclassExceptionFoo implements Foo { |
| @SuppressWarnings("unused") |
| @ThrowingInject |
| public SuperclassExceptionFoo() throws IOException { |
| } |
| |
| @Override |
| public String s() { return null; } |
| } |
| |
| public void testProviderMethodWithRuntimeExceptionsIsOk() throws Exception { |
| providesInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| Foo foo() throws RuntimeException { |
| throw new RuntimeException("boo!"); |
| } |
| }); |
| |
| RemoteProvider<Foo> remoteProvider = |
| providesInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RuntimeException expected) { |
| assertEquals("boo!", expected.getCause().getMessage()); |
| } |
| } |
| |
| public void testCxtorWithRuntimeExceptionsIsOk() throws Exception { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(RuntimeExceptionFoo.class); |
| } |
| }); |
| |
| RemoteProvider<Foo> remoteProvider = |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| |
| try { |
| remoteProvider.get(); |
| fail(); |
| } catch (RuntimeException expected) { |
| assertEquals("boo!", expected.getCause().getMessage()); |
| } |
| } |
| |
| static class RuntimeExceptionFoo implements Foo { |
| @ThrowingInject |
| public RuntimeExceptionFoo() throws RuntimeException { |
| throw new RuntimeException("boo!"); |
| } |
| |
| @Override |
| public String s() { return null; } |
| } |
| |
| private static class SubBindException extends BindException {} |
| |
| public void testProviderMethodWithManyExceptions() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(RemoteProvider.class) |
| String foo() throws InterruptedException, RuntimeException, RemoteException, |
| AccessException, TooManyListenersException, |
| BindException, SubBindException { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK. |
| List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages()); |
| assertEquals(InterruptedException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| errors.get(0).getMessage()); |
| assertEquals(TooManyListenersException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| errors.get(1).getMessage()); |
| assertEquals(2, errors.size()); |
| } |
| } |
| |
| public void testCxtorWithManyExceptions() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(ManyExceptionFoo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException ce) { |
| // The only two that should fail are Interrupted & TooManyListeners.. the rest are OK. |
| List<Message> errors = ImmutableList.copyOf(ce.getErrorMessages()); |
| assertEquals(InterruptedException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| errors.get(0).getMessage()); |
| assertEquals(TooManyListenersException.class.getName() |
| + " is not compatible with the exceptions ([" |
| + RemoteException.class + ", " + BindException.class |
| + "]) declared in the CheckedProvider interface (" |
| + RemoteProvider.class.getName() |
| + ")", |
| errors.get(1).getMessage()); |
| assertEquals(2, errors.size()); |
| } |
| } |
| |
| static class ManyExceptionFoo implements Foo { |
| @SuppressWarnings("unused") |
| @ThrowingInject |
| public ManyExceptionFoo() |
| throws InterruptedException, |
| RuntimeException, |
| RemoteException, |
| AccessException, |
| TooManyListenersException, |
| BindException, |
| SubBindException { |
| } |
| |
| @Override |
| public String s() { return null; } |
| } |
| |
| public void testMoreTypeParameters() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(TooManyTypeParameters.class) |
| String foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(TooManyTypeParameters.class.getName() + " has more than one generic type parameter: [T, P]", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testWrongThrowingProviderType() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(WrongThrowingProviderType.class) |
| String foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(WrongThrowingProviderType.class.getName() |
| + " does not properly extend CheckedProvider, the first type parameter of CheckedProvider " |
| + "(java.lang.String) is not a generic type", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testOneMethodThatIsntGet() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(OneNoneGetMethod.class) |
| String foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(OneNoneGetMethod.class.getName() |
| + " may not declare any new methods, but declared " + Classes.toString(OneNoneGetMethod.class.getDeclaredMethods()[0]), |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testManyMethods() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(ManyMethods.class) |
| String foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(ManyMethods.class.getName() |
| + " may not declare any new methods, but declared " + Arrays.asList(ManyMethods.class.getDeclaredMethods()), |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testIncorrectPredefinedType_Bind() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(StringRemoteProvider.class, Integer.class) |
| .to(new StringRemoteProvider() { |
| public String get() { |
| return "A"; |
| } |
| }); |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(StringRemoteProvider.class.getName() |
| + " expects the value type to be java.lang.String, but it was java.lang.Integer", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| public void testIncorrectPredefinedType_Provides() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| install(ThrowingProviderBinder.forModule(this)); |
| } |
| |
| @SuppressWarnings("unused") |
| @CheckedProvides(StringRemoteProvider.class) |
| Integer foo() { |
| return null; |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals(StringRemoteProvider.class.getName() |
| + " expects the value type to be java.lang.String, but it was java.lang.Integer", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| private static interface TooManyTypeParameters<T, P> extends CheckedProvider<T> { |
| } |
| |
| private static interface WrongThrowingProviderType<T> extends CheckedProvider<String> { |
| } |
| |
| private static interface OneNoneGetMethod<T> extends CheckedProvider<T> { |
| T bar(); |
| } |
| |
| private static interface ManyMethods<T> extends CheckedProvider<T> { |
| T bar(); |
| String baz(); |
| } |
| |
| public void testResultSerializes() throws Exception { |
| Result result = Result.forValue("foo"); |
| result = Asserts.reserialize(result); |
| assertEquals("foo", result.getOrThrow()); |
| } |
| |
| public void testResultExceptionSerializes() throws Exception { |
| Result result = Result.forException(new Exception("boo")); |
| result = Asserts.reserialize(result); |
| try { |
| result.getOrThrow(); |
| fail(); |
| } catch(Exception ex) { |
| assertEquals("boo", ex.getMessage()); |
| } |
| } |
| |
| public void testEarlyBindingError() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(StringRemoteProvider.class, String.class) |
| .to(FailingProvider.class); |
| } |
| }); |
| fail(); |
| } catch(CreationException ce) { |
| assertEquals("Could not find a suitable constructor in " + FailingProvider.class.getName() |
| + ". Classes must have either one (and only one) constructor annotated with @Inject" |
| + " or a zero-argument constructor that is not private.", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| private static class FailingProvider implements StringRemoteProvider { |
| // no @Inject. |
| @SuppressWarnings("unused") |
| FailingProvider(Integer foo) {} |
| |
| public String get() { |
| return null; |
| } |
| } |
| |
| public void testNoInjectionPointForUsing() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(InvalidFoo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException ce) { |
| assertEquals("Could not find a suitable constructor in " + InvalidFoo.class.getName() |
| + ". Classes must have either one (and only one) constructor annotated with " |
| + "@ThrowingInject.", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| static class InvalidFoo implements Foo { |
| public InvalidFoo(String dep) { |
| } |
| |
| @Override public String s() { return null; } |
| } |
| |
| public void testNoThrowingInject() { |
| try { |
| Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(NormalInjectableFoo.class); |
| } |
| }); |
| fail(); |
| } catch (CreationException ce) { |
| assertEquals("Could not find a suitable constructor in " + NormalInjectableFoo.class.getName() |
| + ". Classes must have either one (and only one) constructor annotated with " |
| + "@ThrowingInject.", |
| Iterables.getOnlyElement(ce.getErrorMessages()).getMessage()); |
| } |
| } |
| |
| static class NormalInjectableFoo implements Foo { |
| @Inject |
| public NormalInjectableFoo() { |
| } |
| |
| @Override public String s() { return null; } |
| } |
| |
| public void testProvisionExceptionOnDependenciesOfCxtor() throws Exception { |
| Injector injector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(ProvisionExceptionFoo.class); |
| bindScope(BadScope.class, new Scope() { |
| @Override |
| public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) { |
| return new Provider<T>() { |
| @Override |
| public T get() { |
| throw new OutOfScopeException("failure"); |
| } |
| }; |
| } |
| }); |
| } |
| }); |
| |
| try { |
| injector.getInstance(Key.get(remoteProviderOfFoo)).get(); |
| fail(); |
| } catch(ProvisionException pe) { |
| assertEquals(2, pe.getErrorMessages().size()); |
| List<Message> messages = Lists.newArrayList(pe.getErrorMessages()); |
| assertEquals("Error in custom provider, com.google.inject.OutOfScopeException: failure", |
| messages.get(0).getMessage()); |
| assertEquals("Error in custom provider, com.google.inject.OutOfScopeException: failure", |
| messages.get(1).getMessage()); |
| } |
| } |
| |
| @ScopeAnnotation |
| @Target(ElementType.TYPE) |
| @Retention(RetentionPolicy.RUNTIME) |
| private @interface BadScope { } |
| |
| @BadScope private static class Unscoped1 {} |
| @BadScope private static class Unscoped2 {} |
| |
| static class ProvisionExceptionFoo implements Foo { |
| @ThrowingInject |
| public ProvisionExceptionFoo(Unscoped1 a, Unscoped2 b) { |
| } |
| |
| @Override public String s() { return null; } |
| } |
| |
| public void testUsingDoesntClashWithBindingsOfSameType() throws Exception { |
| cxtorInjector = Guice.createInjector(new AbstractModule() { |
| @Override |
| protected void configure() { |
| ThrowingProviderBinder.create(binder()) |
| .bind(RemoteProvider.class, Foo.class) |
| .providing(MockFoo.class); |
| bind(Foo.class).to(MockFoo.class); |
| bind(MockFoo.class).to(SubMockFoo.class); |
| } |
| }); |
| |
| RemoteProvider<Foo> remoteProvider = |
| cxtorInjector.getInstance(Key.get(remoteProviderOfFoo)); |
| Foo providerGot = remoteProvider.get(); |
| Foo fooGot = cxtorInjector.getInstance(Foo.class); |
| Foo mockGot = cxtorInjector.getInstance(MockFoo.class); |
| |
| assertEquals(MockFoo.class, providerGot.getClass()); |
| assertEquals(SubMockFoo.class, fooGot.getClass()); |
| assertEquals(SubMockFoo.class, mockGot.getClass()); |
| } |
| |
| static class SubMockFoo extends MockFoo { |
| public SubMockFoo() throws RemoteException, BindException { |
| } |
| |
| } |
| } |