| /** |
| * Copyright (C) 2008 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.spi; |
| |
| import com.google.inject.AbstractModule; |
| import static com.google.inject.Asserts.assertContains; |
| import com.google.inject.Binding; |
| import com.google.inject.Guice; |
| import com.google.inject.Inject; |
| import com.google.inject.Injector; |
| import com.google.inject.Key; |
| import com.google.inject.Module; |
| import com.google.inject.Provider; |
| import com.google.inject.Scope; |
| import com.google.inject.Scopes; |
| import com.google.inject.Singleton; |
| import com.google.inject.Stage; |
| import com.google.inject.internal.util.ImmutableSet; |
| import com.google.inject.internal.util.Lists; |
| import com.google.inject.name.Names; |
| import java.lang.reflect.Constructor; |
| import java.util.Collections; |
| import java.util.Comparator; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.concurrent.atomic.AtomicBoolean; |
| import java.util.logging.Logger; |
| |
| import junit.framework.AssertionFailedError; |
| import junit.framework.TestCase; |
| |
| /** |
| * @author jessewilson@google.com (Jesse Wilson) |
| */ |
| public class SpiBindingsTest extends TestCase { |
| |
| public void testBindConstant() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bindConstant().annotatedWith(Names.named("one")).to(1); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof InstanceBinding); |
| assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey()); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testToInstanceBinding() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(String.class).toInstance("A"); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof InstanceBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(Key.get(String.class), binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit(InstanceBinding<? extends T> binding) { |
| assertEquals("A", binding.getInstance()); |
| return null; |
| } |
| }); |
| binding.acceptScopingVisitor(new FailingBindingScopingVisitor() { |
| public Void visitEagerSingleton() { |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testToProviderBinding() { |
| final Provider<String> stringProvider = new StringProvider(); |
| |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(String.class).toProvider(stringProvider); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof ProviderInstanceBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(Key.get(String.class), binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit( |
| ProviderInstanceBinding<? extends T> binding) { |
| assertSame(stringProvider, binding.getProviderInstance()); |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testToProviderKeyBinding() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(String.class).toProvider(StringProvider.class); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof ProviderKeyBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(Key.get(String.class), binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit(ProviderKeyBinding<? extends T> binding) { |
| assertEquals(Key.get(StringProvider.class), binding.getProviderKey()); |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testToKeyBinding() { |
| final Key<String> aKey = Key.get(String.class, Names.named("a")); |
| final Key<String> bKey = Key.get(String.class, Names.named("b")); |
| |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(aKey).to(bKey); |
| bind(bKey).toInstance("B"); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof LinkedKeyBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(aKey, binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit(LinkedKeyBinding<? extends T> binding) { |
| assertEquals(bKey, binding.getLinkedKey()); |
| return null; |
| } |
| }); |
| return null; |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertEquals(bKey, binding.getKey()); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testToConstructorBinding() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(D.class); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof ConstructorBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(Key.get(D.class), binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit(ConstructorBinding<? extends T> binding) { |
| Constructor<?> expected = D.class.getDeclaredConstructors()[0]; |
| assertEquals(expected, binding.getConstructor().getMember()); |
| assertEquals(ImmutableSet.<InjectionPoint>of(), binding.getInjectableMembers()); |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testConstantBinding() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bindConstant().annotatedWith(Names.named("one")).to(1); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> binding) { |
| assertTrue(binding instanceof InstanceBinding); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey()); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<T>() { |
| @Override public Void visit(InstanceBinding<? extends T> binding) { |
| assertEquals(1, binding.getInstance()); |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testConvertedConstantBinding() { |
| Injector injector = Guice.createInjector(new AbstractModule() { |
| protected void configure() { |
| bindConstant().annotatedWith(Names.named("one")).to("1"); |
| } |
| }); |
| |
| Binding<Integer> binding = injector.getBinding(Key.get(Integer.class, Names.named("one"))); |
| assertEquals(Key.get(Integer.class, Names.named("one")), binding.getKey()); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertTrue(binding instanceof ConvertedConstantBinding); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<Integer>() { |
| @Override public Void visit( |
| ConvertedConstantBinding<? extends Integer> binding) { |
| assertEquals((Integer) 1, binding.getValue()); |
| assertEquals(Key.get(String.class, Names.named("one")), binding.getSourceKey()); |
| return null; |
| } |
| }); |
| } |
| |
| public void testProviderBinding() { |
| Injector injector = Guice.createInjector(new AbstractModule() { |
| protected void configure() { |
| bind(String.class).toInstance("A"); |
| } |
| }); |
| |
| Key<Provider<String>> providerOfStringKey = new Key<Provider<String>>() {}; |
| Binding<Provider<String>> binding = injector.getBinding(providerOfStringKey); |
| assertEquals(providerOfStringKey, binding.getKey()); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertTrue(binding instanceof ProviderBinding); |
| binding.acceptTargetVisitor(new FailingTargetVisitor<Provider<String>>() { |
| @Override public Void visit( |
| ProviderBinding<? extends Provider<String>> binding) { |
| assertEquals(Key.get(String.class), binding.getProvidedKey()); |
| return null; |
| } |
| }); |
| } |
| |
| public void testScopes() { |
| checkInjector( |
| new AbstractModule() { |
| protected void configure() { |
| bind(String.class).annotatedWith(Names.named("a")) |
| .toProvider(StringProvider.class).in(Singleton.class); |
| bind(String.class).annotatedWith(Names.named("b")) |
| .toProvider(StringProvider.class).in(Scopes.SINGLETON); |
| bind(String.class).annotatedWith(Names.named("c")) |
| .toProvider(StringProvider.class).asEagerSingleton(); |
| bind(String.class).annotatedWith(Names.named("d")) |
| .toProvider(StringProvider.class); |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> command) { |
| assertEquals(Key.get(String.class, Names.named("a")), command.getKey()); |
| command.acceptScopingVisitor(new FailingBindingScopingVisitor() { |
| @Override public Void visitScope(Scope scope) { |
| // even though we bound with an annotation, the injector always uses instances |
| assertSame(Scopes.SINGLETON, scope); |
| return null; |
| } |
| }); |
| return null; |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> command) { |
| assertEquals(Key.get(String.class, Names.named("b")), command.getKey()); |
| command.acceptScopingVisitor(new FailingBindingScopingVisitor() { |
| @Override public Void visitScope(Scope scope) { |
| assertSame(Scopes.SINGLETON, scope); |
| return null; |
| } |
| }); |
| return null; |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> command) { |
| assertEquals(Key.get(String.class, Names.named("c")), command.getKey()); |
| command.acceptScopingVisitor(new FailingBindingScopingVisitor() { |
| @Override public Void visitEagerSingleton() { |
| return null; |
| } |
| }); |
| return null; |
| } |
| }, |
| |
| new FailingElementVisitor() { |
| @Override public <T> Void visit(Binding<T> command) { |
| assertEquals(Key.get(String.class, Names.named("d")), command.getKey()); |
| command.acceptScopingVisitor(new FailingBindingScopingVisitor() { |
| @Override public Void visitNoScoping() { |
| return null; |
| } |
| }); |
| return null; |
| } |
| } |
| ); |
| } |
| |
| public void testExtensionSpi() { |
| final AtomicBoolean visiting = new AtomicBoolean(false); |
| |
| final Injector injector = Guice.createInjector(new AbstractModule() { |
| protected void configure() { |
| bind(String.class).toProvider(new ProviderWithExtensionVisitor<String>() { |
| public <B, V> V acceptExtensionVisitor(BindingTargetVisitor<B, V> visitor, |
| ProviderInstanceBinding<? extends B> binding) { |
| assertSame(this, binding.getProviderInstance()); |
| // We can't always check for FailingSpiTargetVisitor, |
| // because constructing the injector visits here, and we need |
| // to process the binding as normal |
| if(visiting.get()) { |
| assertTrue("visitor: " + visitor, visitor instanceof FailingSpiTargetVisitor); |
| return (V)"visited"; |
| } else { |
| return visitor.visit(binding); |
| } |
| } |
| |
| public String get() { |
| return "FooBar"; |
| } |
| }); |
| } |
| }); |
| |
| visiting.set(true); |
| |
| // Check for Provider<String> binding -- that is still a ProviderBinding. |
| Key<Provider<String>> providerOfStringKey = new Key<Provider<String>>() {}; |
| Binding<Provider<String>> providerBinding = injector.getBinding(providerOfStringKey); |
| assertEquals(providerOfStringKey, providerBinding.getKey()); |
| assertContains(providerBinding.getSource().toString(), "SpiBindingsTest.java"); |
| assertTrue("binding: " + providerBinding, providerBinding instanceof ProviderBinding); |
| providerBinding.acceptTargetVisitor(new FailingTargetVisitor<Provider<String>>() { |
| @Override public Void visit(ProviderBinding<? extends Provider<String>> binding) { |
| assertEquals(Key.get(String.class), binding.getProvidedKey()); |
| return null; |
| } |
| }); |
| |
| // Check for String binding -- that one is ProviderInstanceBinding, and gets hooked |
| Binding<String> binding = injector.getBinding(String.class); |
| assertEquals(Key.get(String.class), binding.getKey()); |
| assertContains(binding.getSource().toString(), "SpiBindingsTest.java"); |
| assertTrue(binding instanceof ProviderInstanceBinding); |
| assertEquals("visited", binding.acceptTargetVisitor(new FailingSpiTargetVisitor<String>())); |
| } |
| |
| private static class FailingSpiTargetVisitor<T> extends DefaultBindingTargetVisitor<T, String> { |
| @Override |
| protected String visitOther(Binding<? extends T> binding) { |
| throw new AssertionFailedError(); |
| } |
| } |
| |
| public void checkInjector(Module module, ElementVisitor<?>... visitors) { |
| Injector injector = Guice.createInjector(module); |
| |
| List<Binding<?>> bindings = Lists.newArrayList(injector.getBindings().values()); |
| for (Iterator<Binding<?>> i = bindings.iterator(); i.hasNext(); ) { |
| if (BUILT_IN_BINDINGS.contains(i.next().getKey())) { |
| i.remove(); |
| } |
| } |
| |
| Collections.sort(bindings, orderByKey); |
| |
| assertEquals(bindings.size(), visitors.length); |
| |
| for (int i = 0; i < visitors.length; i++) { |
| ElementVisitor<?> visitor = visitors[i]; |
| Binding<?> binding = bindings.get(i); |
| binding.acceptVisitor(visitor); |
| } |
| } |
| |
| private final ImmutableSet<Key<?>> BUILT_IN_BINDINGS = ImmutableSet.of( |
| Key.get(Injector.class), Key.get(Stage.class), Key.get(Logger.class)); |
| |
| private final Comparator<Binding<?>> orderByKey = new Comparator<Binding<?>>() { |
| public int compare(Binding<?> a, Binding<?> b) { |
| return a.getKey().toString().compareTo(b.getKey().toString()); |
| } |
| }; |
| |
| private static class StringProvider implements Provider<String> { |
| public String get() { |
| return "A"; |
| } |
| } |
| |
| private static class C { } |
| |
| private static class D extends C { |
| @Inject public D(Injector unused) { } |
| } |
| } |