Home | History | Annotate | Download | only in multibindings
      1 /**
      2  * Copyright (C) 2014 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.inject.multibindings;
     18 
     19 import static com.google.inject.Asserts.assertContains;
     20 import static com.google.inject.multibindings.SpiUtils.assertOptionalVisitor;
     21 import static com.google.inject.multibindings.SpiUtils.instance;
     22 import static com.google.inject.multibindings.SpiUtils.linked;
     23 import static com.google.inject.multibindings.SpiUtils.providerInstance;
     24 import static com.google.inject.multibindings.SpiUtils.providerKey;
     25 import static com.google.inject.name.Names.named;
     26 
     27 import com.google.common.base.Optional;
     28 import com.google.common.collect.ImmutableSet;
     29 import com.google.common.collect.Iterables;
     30 import com.google.common.collect.Lists;
     31 import com.google.common.collect.Sets;
     32 import com.google.inject.AbstractModule;
     33 import com.google.inject.Asserts;
     34 import com.google.inject.Binding;
     35 import com.google.inject.BindingAnnotation;
     36 import com.google.inject.CreationException;
     37 import com.google.inject.Guice;
     38 import com.google.inject.Injector;
     39 import com.google.inject.Key;
     40 import com.google.inject.Module;
     41 import com.google.inject.Provider;
     42 import com.google.inject.Provides;
     43 import com.google.inject.Scopes;
     44 import com.google.inject.TypeLiteral;
     45 import com.google.inject.internal.WeakKeySetUtils;
     46 import com.google.inject.multibindings.OptionalBinder.Actual;
     47 import com.google.inject.multibindings.OptionalBinder.Default;
     48 import com.google.inject.multibindings.SpiUtils.VisitType;
     49 import com.google.inject.name.Named;
     50 import com.google.inject.name.Names;
     51 import com.google.inject.spi.Dependency;
     52 import com.google.inject.spi.Elements;
     53 import com.google.inject.spi.HasDependencies;
     54 import com.google.inject.spi.InstanceBinding;
     55 import com.google.inject.util.Modules;
     56 import com.google.inject.util.Providers;
     57 
     58 import junit.framework.TestCase;
     59 
     60 import java.lang.annotation.Annotation;
     61 import java.lang.annotation.ElementType;
     62 import java.lang.annotation.Retention;
     63 import java.lang.annotation.RetentionPolicy;
     64 import java.lang.annotation.Target;
     65 import java.lang.ref.WeakReference;
     66 import java.lang.reflect.Method;
     67 import java.util.List;
     68 import java.util.Map.Entry;
     69 import java.util.Set;
     70 
     71 /**
     72  * @author sameb (at) google.com (Sam Berlin)
     73  */
     74 public class OptionalBinderTest extends TestCase {
     75 
     76   private static final boolean HAS_JAVA_OPTIONAL;
     77   private static final Class<?> JAVA_OPTIONAL_CLASS;
     78   private static final Method JAVA_OPTIONAL_OR_ELSE;
     79   static {
     80     Class<?> optional = null;
     81     Method orElse = null;
     82     try {
     83       optional = Class.forName("java.util.Optional");
     84       orElse = optional.getDeclaredMethod("orElse", Object.class);
     85     } catch (ClassNotFoundException ignored) {
     86     } catch (NoSuchMethodException ignored) {
     87     } catch (SecurityException ignored) {
     88     }
     89     HAS_JAVA_OPTIONAL = optional != null;
     90     JAVA_OPTIONAL_CLASS = optional;
     91     JAVA_OPTIONAL_OR_ELSE = orElse;
     92   }
     93 
     94   final Key<String> stringKey = Key.get(String.class);
     95   final TypeLiteral<Optional<String>> optionalOfString = new TypeLiteral<Optional<String>>() {};
     96   final TypeLiteral<?> javaOptionalOfString =  HAS_JAVA_OPTIONAL ?
     97       OptionalBinder.javaOptionalOf(stringKey.getTypeLiteral()) : null;
     98   final TypeLiteral<Optional<Provider<String>>> optionalOfProviderString =
     99       new TypeLiteral<Optional<Provider<String>>>() {};
    100   final TypeLiteral<?> javaOptionalOfProviderString = HAS_JAVA_OPTIONAL ?
    101       OptionalBinder.javaOptionalOfProvider(stringKey.getTypeLiteral()) : null;
    102   final TypeLiteral<Optional<javax.inject.Provider<String>>> optionalOfJavaxProviderString =
    103       new TypeLiteral<Optional<javax.inject.Provider<String>>>() {};
    104   final TypeLiteral<?> javaOptionalOfJavaxProviderString = HAS_JAVA_OPTIONAL ?
    105       OptionalBinder.javaOptionalOfJavaxProvider(stringKey.getTypeLiteral()) : null;
    106 
    107   final Key<Integer> intKey = Key.get(Integer.class);
    108   final TypeLiteral<Optional<Integer>> optionalOfInteger = new TypeLiteral<Optional<Integer>>() {};
    109   final TypeLiteral<?> javaOptionalOfInteger =  HAS_JAVA_OPTIONAL ?
    110       OptionalBinder.javaOptionalOf(intKey.getTypeLiteral()) : null;
    111   final TypeLiteral<Optional<Provider<Integer>>> optionalOfProviderInteger =
    112       new TypeLiteral<Optional<Provider<Integer>>>() {};
    113   final TypeLiteral<?> javaOptionalOfProviderInteger = HAS_JAVA_OPTIONAL ?
    114       OptionalBinder.javaOptionalOfProvider(intKey.getTypeLiteral()) : null;
    115   final TypeLiteral<Optional<javax.inject.Provider<Integer>>> optionalOfJavaxProviderInteger =
    116       new TypeLiteral<Optional<javax.inject.Provider<Integer>>>() {};
    117   final TypeLiteral<?> javaOptionalOfJavaxProviderInteger = HAS_JAVA_OPTIONAL ?
    118       OptionalBinder.javaOptionalOfJavaxProvider(intKey.getTypeLiteral()) : null;
    119 
    120   final TypeLiteral<List<String>> listOfStrings = new TypeLiteral<List<String>>() {};
    121 
    122   public void testTypeNotBoundByDefault() {
    123     Module module = new AbstractModule() {
    124       @Override protected void configure() {
    125         OptionalBinder.newOptionalBinder(binder(), String.class);
    126         requireBinding(new Key<Optional<String>>() {}); // the above specifies this.
    127         requireBinding(String.class); // but it doesn't specify this.
    128         binder().requireExplicitBindings(); // need to do this, otherwise String will JIT
    129 
    130         if (HAS_JAVA_OPTIONAL) {
    131           requireBinding(Key.get(javaOptionalOfString));
    132         }
    133       }
    134     };
    135 
    136     try {
    137       Guice.createInjector(module);
    138       fail();
    139     } catch (CreationException ce) {
    140       assertContains(ce.getMessage(),
    141           "1) Explicit bindings are required and java.lang.String is not explicitly bound.");
    142       assertEquals(1, ce.getErrorMessages().size());
    143     }
    144   }
    145 
    146   public void testOptionalIsAbsentByDefault() throws Exception {
    147     Module module = new AbstractModule() {
    148       @Override protected void configure() {
    149         OptionalBinder.newOptionalBinder(binder(), String.class);
    150       }
    151     };
    152 
    153     Injector injector = Guice.createInjector(module);
    154     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    155     assertFalse(optional.isPresent());
    156 
    157     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    158     assertFalse(optionalP.isPresent());
    159 
    160     Optional<javax.inject.Provider<String>> optionalJxP =
    161         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    162     assertFalse(optionalJxP.isPresent());
    163 
    164     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, null, null);
    165 
    166     if (HAS_JAVA_OPTIONAL) {
    167       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    168       assertFalse(optional.isPresent());
    169 
    170       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    171       assertFalse(optionalP.isPresent());
    172 
    173       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    174       assertFalse(optionalJxP.isPresent());
    175     }
    176   }
    177 
    178   public void testUsesUserBoundValue() throws Exception {
    179     Module module = new AbstractModule() {
    180       @Override protected void configure() {
    181         OptionalBinder.newOptionalBinder(binder(), String.class);
    182       }
    183       @Provides String provideString() { return "foo"; }
    184     };
    185 
    186     Injector injector = Guice.createInjector(module);
    187     assertEquals("foo", injector.getInstance(String.class));
    188 
    189     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    190     assertEquals("foo", optional.get());
    191 
    192     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    193     assertEquals("foo", optionalP.get().get());
    194 
    195     Optional<javax.inject.Provider<String>> optionalJxP =
    196         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    197     assertEquals("foo", optionalJxP.get().get());
    198 
    199     assertOptionalVisitor(stringKey,
    200         setOf(module),
    201         VisitType.BOTH,
    202         0,
    203         null,
    204         null,
    205         providerInstance("foo"));
    206 
    207     if (HAS_JAVA_OPTIONAL) {
    208       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    209       assertEquals("foo", optional.get());
    210 
    211       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    212       assertEquals("foo", optionalP.get().get());
    213 
    214       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    215       assertEquals("foo", optionalJxP.get().get());
    216     }
    217   }
    218 
    219   public void testSetDefault() throws Exception {
    220     Module module = new AbstractModule() {
    221       @Override protected void configure() {
    222         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    223       }
    224     };
    225     Injector injector = Guice.createInjector(module);
    226     assertEquals("a", injector.getInstance(String.class));
    227 
    228     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    229     assertTrue(optional.isPresent());
    230     assertEquals("a", optional.get());
    231 
    232     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    233     assertTrue(optionalP.isPresent());
    234     assertEquals("a", optionalP.get().get());
    235 
    236     Optional<javax.inject.Provider<String>> optionalJxP =
    237         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    238     assertTrue(optionalJxP.isPresent());
    239     assertEquals("a", optionalJxP.get().get());
    240 
    241     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, instance("a"), null, null);
    242 
    243     if (HAS_JAVA_OPTIONAL) {
    244       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    245       assertTrue(optional.isPresent());
    246       assertEquals("a", optional.get());
    247 
    248       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    249       assertTrue(optionalP.isPresent());
    250       assertEquals("a", optionalP.get().get());
    251 
    252       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    253       assertTrue(optionalJxP.isPresent());
    254       assertEquals("a", optionalJxP.get().get());
    255     }
    256   }
    257 
    258   public void testSetBinding() throws Exception {
    259     Module module = new AbstractModule() {
    260       @Override protected void configure() {
    261         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("a");
    262       }
    263     };
    264     Injector injector = Guice.createInjector(module);
    265     assertEquals("a", injector.getInstance(String.class));
    266 
    267     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    268     assertTrue(optional.isPresent());
    269     assertEquals("a", optional.get());
    270 
    271     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    272     assertTrue(optionalP.isPresent());
    273     assertEquals("a", optionalP.get().get());
    274 
    275     Optional<javax.inject.Provider<String>> optionalJxP =
    276         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    277     assertTrue(optionalJxP.isPresent());
    278     assertEquals("a", optionalJxP.get().get());
    279 
    280     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, instance("a"), null);
    281 
    282     if (HAS_JAVA_OPTIONAL) {
    283       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    284       assertTrue(optional.isPresent());
    285       assertEquals("a", optional.get());
    286 
    287       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    288       assertTrue(optionalP.isPresent());
    289       assertEquals("a", optionalP.get().get());
    290 
    291       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    292       assertTrue(optionalJxP.isPresent());
    293       assertEquals("a", optionalJxP.get().get());
    294     }
    295   }
    296 
    297   public void testSetBindingOverridesDefault() throws Exception {
    298     Module module = new AbstractModule() {
    299       @Override protected void configure() {
    300         OptionalBinder<String> optionalBinder =
    301             OptionalBinder.newOptionalBinder(binder(), String.class);
    302         optionalBinder.setDefault().toInstance("a");
    303         optionalBinder.setBinding().toInstance("b");
    304       }
    305     };
    306     Injector injector = Guice.createInjector(module);
    307     assertEquals("b", injector.getInstance(String.class));
    308 
    309     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    310     assertTrue(optional.isPresent());
    311     assertEquals("b", optional.get());
    312 
    313     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    314     assertTrue(optionalP.isPresent());
    315     assertEquals("b", optionalP.get().get());
    316 
    317     Optional<javax.inject.Provider<String>> optionalJxP =
    318         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    319     assertTrue(optionalJxP.isPresent());
    320     assertEquals("b", optionalJxP.get().get());
    321 
    322     assertOptionalVisitor(stringKey,
    323         setOf(module),
    324         VisitType.BOTH,
    325         0,
    326         instance("a"),
    327         instance("b"),
    328         null);
    329 
    330     if (HAS_JAVA_OPTIONAL) {
    331       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    332       assertTrue(optional.isPresent());
    333       assertEquals("b", optional.get());
    334 
    335       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    336       assertTrue(optionalP.isPresent());
    337       assertEquals("b", optionalP.get().get());
    338 
    339       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    340       assertTrue(optionalJxP.isPresent());
    341       assertEquals("b", optionalJxP.get().get());
    342     }
    343   }
    344 
    345   public void testSpreadAcrossModules() throws Exception {
    346     Module module1 = new AbstractModule() {
    347       @Override protected void configure() {
    348         OptionalBinder.newOptionalBinder(binder(), String.class);
    349       }
    350     };
    351     Module module2 = new AbstractModule() {
    352       @Override protected void configure() {
    353         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    354       }
    355     };
    356     Module module3 = new AbstractModule() {
    357       @Override protected void configure() {
    358         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b");
    359       }
    360     };
    361 
    362     Injector injector = Guice.createInjector(module1, module2, module3);
    363     assertEquals("b", injector.getInstance(String.class));
    364 
    365     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    366     assertTrue(optional.isPresent());
    367     assertEquals("b", optional.get());
    368 
    369     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    370     assertTrue(optionalP.isPresent());
    371     assertEquals("b", optionalP.get().get());
    372 
    373     Optional<javax.inject.Provider<String>> optionalJxP =
    374         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    375     assertTrue(optionalJxP.isPresent());
    376     assertEquals("b", optionalJxP.get().get());
    377 
    378     assertOptionalVisitor(stringKey,
    379         setOf(module1, module2, module3),
    380         VisitType.BOTH,
    381         0,
    382         instance("a"),
    383         instance("b"),
    384         null);
    385 
    386     if (HAS_JAVA_OPTIONAL) {
    387       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    388       assertTrue(optional.isPresent());
    389       assertEquals("b", optional.get());
    390 
    391       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    392       assertTrue(optionalP.isPresent());
    393       assertEquals("b", optionalP.get().get());
    394 
    395       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    396       assertTrue(optionalJxP.isPresent());
    397       assertEquals("b", optionalJxP.get().get());
    398     }
    399   }
    400 
    401   public void testExactSameBindingCollapses_defaults() throws Exception {
    402     Module module = new AbstractModule() {
    403       @Override protected void configure() {
    404         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault()
    405             .toInstance(new String("a")); // using new String to ensure .equals is checked.
    406         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault()
    407             .toInstance(new String("a"));
    408       }
    409     };
    410     Injector injector = Guice.createInjector(module);
    411     assertEquals("a", injector.getInstance(String.class));
    412 
    413     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    414     assertTrue(optional.isPresent());
    415     assertEquals("a", optional.get());
    416 
    417     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    418     assertTrue(optionalP.isPresent());
    419     assertEquals("a", optionalP.get().get());
    420 
    421     Optional<javax.inject.Provider<String>> optionalJxP =
    422         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    423     assertTrue(optionalJxP.isPresent());
    424     assertEquals("a", optionalJxP.get().get());
    425 
    426     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, instance("a"), null, null);
    427 
    428     if (HAS_JAVA_OPTIONAL) {
    429       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    430       assertTrue(optional.isPresent());
    431       assertEquals("a", optional.get());
    432 
    433       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    434       assertTrue(optionalP.isPresent());
    435       assertEquals("a", optionalP.get().get());
    436 
    437       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    438       assertTrue(optionalJxP.isPresent());
    439       assertEquals("a", optionalJxP.get().get());
    440     }
    441   }
    442 
    443   public void testExactSameBindingCollapses_actual() throws Exception {
    444     Module module = new AbstractModule() {
    445       @Override protected void configure() {
    446         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding()
    447             .toInstance(new String("a")); // using new String to ensure .equals is checked.
    448         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding()
    449             .toInstance(new String("a"));
    450       }
    451     };
    452     Injector injector = Guice.createInjector(module);
    453     assertEquals("a", injector.getInstance(String.class));
    454 
    455     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    456     assertTrue(optional.isPresent());
    457     assertEquals("a", optional.get());
    458 
    459     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    460     assertTrue(optionalP.isPresent());
    461     assertEquals("a", optionalP.get().get());
    462 
    463     Optional<javax.inject.Provider<String>> optionalJxP =
    464         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    465     assertTrue(optionalJxP.isPresent());
    466     assertEquals("a", optionalJxP.get().get());
    467 
    468     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 0, null, instance("a"), null);
    469 
    470     if (HAS_JAVA_OPTIONAL) {
    471       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    472       assertTrue(optional.isPresent());
    473       assertEquals("a", optional.get());
    474 
    475       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    476       assertTrue(optionalP.isPresent());
    477       assertEquals("a", optionalP.get().get());
    478 
    479       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    480       assertTrue(optionalJxP.isPresent());
    481       assertEquals("a", optionalJxP.get().get());
    482     }
    483   }
    484 
    485   public void testDifferentBindingsFail_defaults() {
    486     Module module = new AbstractModule() {
    487       @Override protected void configure() {
    488         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    489         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("b");
    490       }
    491     };
    492     try {
    493       Guice.createInjector(module);
    494       fail();
    495     } catch (CreationException ce) {
    496       assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
    497       assertContains(ce.getMessage(),
    498           "1) A binding to java.lang.String annotated with @"
    499               + Default.class.getName() + " was already configured at "
    500               + module.getClass().getName() + ".configure(",
    501           "at " + module.getClass().getName() + ".configure(");
    502     }
    503   }
    504 
    505   public void testDifferentBindingsFail_actual() {
    506     Module module = new AbstractModule() {
    507       @Override protected void configure() {
    508         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("a");
    509         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b");
    510       }
    511     };
    512     try {
    513       Guice.createInjector(module);
    514       fail();
    515     } catch (CreationException ce) {
    516       assertEquals(ce.getMessage(), 1, ce.getErrorMessages().size());
    517       assertContains(ce.getMessage(),
    518           "1) A binding to java.lang.String annotated with @"
    519               + Actual.class.getName() + " was already configured at "
    520               + module.getClass().getName() + ".configure(",
    521           "at " + module.getClass().getName() + ".configure(");
    522     }
    523   }
    524 
    525   public void testDifferentBindingsFail_both() {
    526     Module module = new AbstractModule() {
    527       @Override protected void configure() {
    528         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    529         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("b");
    530         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("b");
    531         OptionalBinder.newOptionalBinder(binder(), String.class).setBinding().toInstance("c");
    532       }
    533     };
    534     try {
    535       Guice.createInjector(module);
    536       fail();
    537     } catch (CreationException ce) {
    538       assertEquals(ce.getMessage(), 2, ce.getErrorMessages().size());
    539       assertContains(ce.getMessage(),
    540           "1) A binding to java.lang.String annotated with @"
    541               + Default.class.getName() + " was already configured at "
    542               + module.getClass().getName() + ".configure(",
    543           "at " + module.getClass().getName() + ".configure(",
    544           "2) A binding to java.lang.String annotated with @"
    545               + Actual.class.getName() + " was already configured at "
    546               + module.getClass().getName() + ".configure(",
    547           "at " + module.getClass().getName() + ".configure(");
    548     }
    549   }
    550 
    551   public void testQualifiedAggregatesTogether() throws Exception {
    552     Module module1 = new AbstractModule() {
    553       @Override
    554       protected void configure() {
    555         OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo")));
    556       }
    557     };
    558     Module module2 = new AbstractModule() {
    559       @Override
    560       protected void configure() {
    561         OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo")))
    562             .setDefault().toInstance("a");
    563       }
    564     };
    565     Module module3 = new AbstractModule() {
    566       @Override
    567       protected void configure() {
    568         OptionalBinder.newOptionalBinder(binder(), Key.get(String.class, Names.named("foo")))
    569             .setBinding().toInstance("b");
    570       }
    571     };
    572 
    573     Injector injector = Guice.createInjector(module1, module2, module3);
    574     assertEquals("b", injector.getInstance(Key.get(String.class, Names.named("foo"))));
    575 
    576     Optional<String> optional = injector.getInstance(Key.get(optionalOfString, Names.named("foo")));
    577     assertTrue(optional.isPresent());
    578     assertEquals("b", optional.get());
    579 
    580     Optional<Provider<String>> optionalP =
    581         injector.getInstance(Key.get(optionalOfProviderString, Names.named("foo")));
    582     assertTrue(optionalP.isPresent());
    583     assertEquals("b", optionalP.get().get());
    584 
    585     Optional<javax.inject.Provider<String>> optionalJxP =
    586         injector.getInstance(Key.get(optionalOfJavaxProviderString, Names.named("foo")));
    587     assertTrue(optionalJxP.isPresent());
    588     assertEquals("b", optionalJxP.get().get());
    589 
    590     assertOptionalVisitor(Key.get(String.class, Names.named("foo")),
    591         setOf(module1, module2, module3),
    592         VisitType.BOTH,
    593         0,
    594         instance("a"),
    595         instance("b"),
    596         null);
    597 
    598     if (HAS_JAVA_OPTIONAL) {
    599       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString, Names.named("foo"))));
    600       assertTrue(optional.isPresent());
    601       assertEquals("b", optional.get());
    602 
    603       optionalP = toOptional(injector.getInstance
    604           (Key.get(javaOptionalOfProviderString, Names.named("foo"))));
    605       assertTrue(optionalP.isPresent());
    606       assertEquals("b", optionalP.get().get());
    607 
    608       optionalJxP = toOptional(injector.getInstance(
    609           Key.get(javaOptionalOfJavaxProviderString, Names.named("foo"))));
    610       assertTrue(optionalJxP.isPresent());
    611       assertEquals("b", optionalJxP.get().get());
    612     }
    613   }
    614 
    615   public void testMultipleDifferentOptionals() {
    616     final Key<String> bKey = Key.get(String.class, named("b"));
    617     final Key<String> cKey = Key.get(String.class, named("c"));
    618     Module module = new AbstractModule() {
    619       @Override protected void configure() {
    620         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    621         OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(1);
    622 
    623         OptionalBinder.newOptionalBinder(binder(), bKey).setDefault().toInstance("b");
    624         OptionalBinder.newOptionalBinder(binder(), cKey).setDefault().toInstance("c");
    625       }
    626     };
    627     Injector injector = Guice.createInjector(module);
    628     assertEquals("a", injector.getInstance(String.class));
    629     assertEquals(1, injector.getInstance(Integer.class).intValue());
    630     assertEquals("b", injector.getInstance(bKey));
    631     assertEquals("c", injector.getInstance(cKey));
    632 
    633     assertOptionalVisitor(stringKey, setOf(module), VisitType.BOTH, 3, instance("a"), null, null);
    634     assertOptionalVisitor(intKey, setOf(module), VisitType.BOTH, 3, instance(1), null, null);
    635     assertOptionalVisitor(bKey, setOf(module), VisitType.BOTH, 3, instance("b"), null, null);
    636     assertOptionalVisitor(cKey, setOf(module), VisitType.BOTH, 3, instance("c"), null, null);
    637   }
    638 
    639   public void testOptionalIsAppropriatelyLazy() throws Exception {
    640     Module module = new AbstractModule() {
    641       int nextValue = 1;
    642       @Override protected void configure() {
    643         OptionalBinder.newOptionalBinder(binder(), Integer.class)
    644             .setDefault().to(Key.get(Integer.class, Names.named("foo")));
    645       }
    646       @Provides @Named("foo") int provideInt() {
    647         return nextValue++;
    648       }
    649     };
    650     Injector injector = Guice.createInjector(module);
    651 
    652     Optional<Provider<Integer>> optionalP =
    653         injector.getInstance(Key.get(optionalOfProviderInteger));
    654     Optional<javax.inject.Provider<Integer>> optionalJxP =
    655         injector.getInstance(Key.get(optionalOfJavaxProviderInteger));
    656 
    657     assertEquals(1, injector.getInstance(Integer.class).intValue());
    658     assertEquals(2, injector.getInstance(Integer.class).intValue());
    659 
    660     // Calling .get() on an Optional<Integer> multiple times will keep giving the same thing
    661     Optional<Integer> optional = injector.getInstance(Key.get(optionalOfInteger));
    662     assertEquals(3, optional.get().intValue());
    663     assertEquals(3, optional.get().intValue());
    664     // But getting another Optional<Integer> will give a new one.
    665     assertEquals(4, injector.getInstance(Key.get(optionalOfInteger)).get().intValue());
    666 
    667     // And the Optional<Provider> will return a provider that gives a new value each time.
    668     assertEquals(5, optionalP.get().get().intValue());
    669     assertEquals(6, optionalP.get().get().intValue());
    670 
    671     assertEquals(7, optionalJxP.get().get().intValue());
    672     assertEquals(8, optionalJxP.get().get().intValue());
    673 
    674     // and same rules with java.util.Optional
    675     if (HAS_JAVA_OPTIONAL) {
    676       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfInteger)));
    677       assertEquals(9, optional.get().intValue());
    678       assertEquals(9, optional.get().intValue());
    679       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfInteger)));
    680       assertEquals(10, optional.get().intValue());
    681 
    682       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderInteger)));
    683       assertEquals(11, optionalP.get().get().intValue());
    684       assertEquals(12, optionalP.get().get().intValue());
    685 
    686       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderInteger)));
    687       assertEquals(13, optionalJxP.get().get().intValue());
    688       assertEquals(14, optionalJxP.get().get().intValue());
    689     }
    690   }
    691 
    692   public void testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_default()
    693       throws Exception {
    694     Module module = new AbstractModule() {
    695       @Override protected void configure() {
    696         OptionalBinder.newOptionalBinder(binder(), String.class)
    697             .setDefault().toProvider(Providers.<String>of(null));
    698       }
    699     };
    700     Injector injector = Guice.createInjector(module);
    701     assertNull(injector.getInstance(String.class));
    702 
    703     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    704     assertFalse(optional.isPresent());
    705 
    706     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    707     assertTrue(optionalP.isPresent());
    708     assertNull(optionalP.get().get());
    709 
    710     Optional<javax.inject.Provider<String>> optionalJxP =
    711         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    712     assertTrue(optionalJxP.isPresent());
    713     assertNull(optionalJxP.get().get());
    714 
    715     assertOptionalVisitor(stringKey,
    716         setOf(module),
    717         VisitType.BOTH,
    718         0,
    719         SpiUtils.<String>providerInstance(null),
    720         null,
    721         null);
    722 
    723     if (HAS_JAVA_OPTIONAL) {
    724       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    725       assertFalse(optional.isPresent());
    726 
    727       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    728       assertTrue(optionalP.isPresent());
    729       assertNull(optionalP.get().get());
    730 
    731       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    732       assertTrue(optionalJxP.isPresent());
    733       assertNull(optionalJxP.get().get());
    734     }
    735   }
    736 
    737   public void testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_actual()
    738       throws Exception {
    739     Module module = new AbstractModule() {
    740       @Override protected void configure() {
    741         OptionalBinder.newOptionalBinder(binder(), String.class)
    742             .setBinding().toProvider(Providers.<String>of(null));
    743       }
    744     };
    745     Injector injector = Guice.createInjector(module);
    746     assertNull(injector.getInstance(String.class));
    747 
    748     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    749     assertFalse(optional.isPresent());
    750 
    751     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    752     assertTrue(optionalP.isPresent());
    753     assertNull(optionalP.get().get());
    754 
    755     Optional<javax.inject.Provider<String>> optionalJxP =
    756         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    757     assertTrue(optionalJxP.isPresent());
    758     assertNull(optionalJxP.get().get());
    759 
    760     assertOptionalVisitor(stringKey,
    761         setOf(module),
    762         VisitType.BOTH,
    763         0,
    764         null,
    765         SpiUtils.<String>providerInstance(null),
    766         null);
    767 
    768     if (HAS_JAVA_OPTIONAL) {
    769       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    770       assertFalse(optional.isPresent());
    771 
    772       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    773       assertTrue(optionalP.isPresent());
    774       assertNull(optionalP.get().get());
    775 
    776       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    777       assertTrue(optionalJxP.isPresent());
    778       assertNull(optionalJxP.get().get());
    779     }
    780   }
    781 
    782   // TODO(sameb): Maybe change this?
    783   public void testLinkedToNullActualDoesntFallbackToDefault() throws Exception {
    784     Module module = new AbstractModule() {
    785       @Override protected void configure() {
    786         OptionalBinder.newOptionalBinder(binder(), String.class).setDefault().toInstance("a");
    787         OptionalBinder.newOptionalBinder(binder(), String.class)
    788             .setBinding().toProvider(Providers.<String>of(null));
    789       }
    790     };
    791     Injector injector = Guice.createInjector(module);
    792     assertNull(injector.getInstance(String.class));
    793 
    794     Optional<String> optional = injector.getInstance(Key.get(optionalOfString));
    795     assertFalse(optional.isPresent());
    796 
    797     Optional<Provider<String>> optionalP = injector.getInstance(Key.get(optionalOfProviderString));
    798     assertTrue(optionalP.isPresent());
    799     assertNull(optionalP.get().get());
    800 
    801     Optional<javax.inject.Provider<String>> optionalJxP =
    802         injector.getInstance(Key.get(optionalOfJavaxProviderString));
    803     assertTrue(optionalJxP.isPresent());
    804     assertNull(optionalP.get().get());
    805 
    806     assertOptionalVisitor(stringKey,
    807         setOf(module),
    808         VisitType.BOTH,
    809         0,
    810         instance("a"),
    811         SpiUtils.<String>providerInstance(null),
    812         null);
    813 
    814     if (HAS_JAVA_OPTIONAL) {
    815       optional = toOptional(injector.getInstance(Key.get(javaOptionalOfString)));
    816       assertFalse(optional.isPresent());
    817 
    818       optionalP = toOptional(injector.getInstance(Key.get(javaOptionalOfProviderString)));
    819       assertTrue(optionalP.isPresent());
    820       assertNull(optionalP.get().get());
    821 
    822       optionalJxP = toOptional(injector.getInstance(Key.get(javaOptionalOfJavaxProviderString)));
    823       assertTrue(optionalJxP.isPresent());
    824       assertNull(optionalJxP.get().get());
    825     }
    826   }
    827 
    828   public void testSourceLinesInException() {
    829     try {
    830       Guice.createInjector(new AbstractModule() {
    831         @Override protected void configure() {
    832           OptionalBinder.newOptionalBinder(binder(),  Integer.class).setDefault();
    833         }
    834       });
    835       fail();
    836     } catch (CreationException expected) {
    837       assertContains(expected.getMessage(), "No implementation for java.lang.Integer",
    838           "at " + getClass().getName());
    839     }
    840   }
    841 
    842   public void testDependencies_both() {
    843     Injector injector = Guice.createInjector(new AbstractModule() {
    844       @Override protected void configure() {
    845         OptionalBinder<String> optionalbinder =
    846             OptionalBinder.newOptionalBinder(binder(), String.class);
    847         optionalbinder.setDefault().toInstance("A");
    848         optionalbinder.setBinding().to(Key.get(String.class, Names.named("b")));
    849         bindConstant().annotatedWith(Names.named("b")).to("B");
    850       }
    851     });
    852 
    853     Binding<String> binding = injector.getBinding(Key.get(String.class));
    854     HasDependencies withDependencies = (HasDependencies) binding;
    855     Set<String> elements = Sets.newHashSet();
    856     elements.addAll(recurseForDependencies(injector, withDependencies));
    857     assertEquals(ImmutableSet.of("B"), elements);
    858   }
    859 
    860   public void testDependencies_actual() {
    861     Injector injector = Guice.createInjector(new AbstractModule() {
    862       @Override protected void configure() {
    863         OptionalBinder<String> optionalbinder =
    864             OptionalBinder.newOptionalBinder(binder(), String.class);
    865         optionalbinder.setBinding().to(Key.get(String.class, Names.named("b")));
    866         bindConstant().annotatedWith(Names.named("b")).to("B");
    867       }
    868     });
    869 
    870     Binding<String> binding = injector.getBinding(Key.get(String.class));
    871     HasDependencies withDependencies = (HasDependencies) binding;
    872     Set<String> elements = Sets.newHashSet();
    873     elements.addAll(recurseForDependencies(injector, withDependencies));
    874     assertEquals(ImmutableSet.of("B"), elements);
    875   }
    876 
    877   public void testDependencies_default() {
    878     Injector injector = Guice.createInjector(new AbstractModule() {
    879       @Override protected void configure() {
    880         OptionalBinder<String> optionalbinder =
    881             OptionalBinder.newOptionalBinder(binder(), String.class);
    882         optionalbinder.setDefault().toInstance("A");
    883       }
    884     });
    885 
    886     Binding<String> binding = injector.getBinding(Key.get(String.class));
    887     HasDependencies withDependencies = (HasDependencies) binding;
    888     Set<String> elements = Sets.newHashSet();
    889     elements.addAll(recurseForDependencies(injector, withDependencies));
    890     assertEquals(ImmutableSet.of("A"), elements);
    891   }
    892 
    893   @SuppressWarnings("rawtypes")
    894   private Set<String> recurseForDependencies(Injector injector, HasDependencies hasDependencies) {
    895     Set<String> elements = Sets.newHashSet();
    896     for (Dependency<?> dependency : hasDependencies.getDependencies()) {
    897       Binding<?> binding = injector.getBinding(dependency.getKey());
    898       HasDependencies deps = (HasDependencies) binding;
    899       if (binding instanceof InstanceBinding) {
    900         elements.add((String) ((InstanceBinding) binding).getInstance());
    901       } else {
    902         elements.addAll(recurseForDependencies(injector, deps));
    903       }
    904     }
    905     return elements;
    906   }
    907 
    908   /**
    909    * Doubly-installed modules should not conflict, even when one is overridden.
    910    */
    911   public void testModuleOverrideRepeatedInstalls_toInstance() {
    912     Module m = new AbstractModule() {
    913       @Override protected void configure() {
    914         OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class);
    915         b.setDefault().toInstance("A");
    916         b.setBinding().toInstance("B");
    917       }
    918     };
    919 
    920     assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class)));
    921 
    922     Injector injector = Guice.createInjector(m, Modules.override(m).with(m));
    923     assertEquals("B", injector.getInstance(Key.get(String.class)));
    924 
    925     assertOptionalVisitor(stringKey,
    926         setOf(m, Modules.override(m).with(m)),
    927         VisitType.BOTH,
    928         0,
    929         instance("A"),
    930         instance("B"),
    931         null);
    932   }
    933 
    934   public void testModuleOverrideRepeatedInstalls_toKey() {
    935     final Key<String> aKey = Key.get(String.class, Names.named("A_string"));
    936     final Key<String> bKey = Key.get(String.class, Names.named("B_string"));
    937     Module m = new AbstractModule() {
    938       @Override protected void configure() {
    939         bind(aKey).toInstance("A");
    940         bind(bKey).toInstance("B");
    941 
    942         OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class);
    943         b.setDefault().to(aKey);
    944         b.setBinding().to(bKey);
    945       }
    946     };
    947 
    948     assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class)));
    949 
    950     Injector injector = Guice.createInjector(m, Modules.override(m).with(m));
    951     assertEquals("B", injector.getInstance(Key.get(String.class)));
    952 
    953     assertOptionalVisitor(stringKey,
    954         setOf(m, Modules.override(m).with(m)),
    955         VisitType.BOTH,
    956         0,
    957         linked(aKey),
    958         linked(bKey),
    959         null);
    960   }
    961 
    962   public void testModuleOverrideRepeatedInstalls_toProviderInstance() {
    963     // Providers#of() does not redefine equals/hashCode, so use the same one both times.
    964     final Provider<String> aProvider = Providers.of("A");
    965     final Provider<String> bProvider = Providers.of("B");
    966     Module m = new AbstractModule() {
    967       @Override protected void configure() {
    968         OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class);
    969         b.setDefault().toProvider(aProvider);
    970         b.setBinding().toProvider(bProvider);
    971       }
    972     };
    973 
    974     assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class)));
    975 
    976     Injector injector = Guice.createInjector(m, Modules.override(m).with(m));
    977     assertEquals("B", injector.getInstance(Key.get(String.class)));
    978 
    979     assertOptionalVisitor(stringKey,
    980         setOf(m, Modules.override(m).with(m)),
    981         VisitType.BOTH,
    982         0,
    983         providerInstance("A"),
    984         providerInstance("B"),
    985         null);
    986   }
    987 
    988   private static class AStringProvider implements Provider<String> {
    989     public String get() {
    990       return "A";
    991     }
    992   }
    993 
    994   private static class BStringProvider implements Provider<String> {
    995     public String get() {
    996       return "B";
    997     }
    998   }
    999 
   1000   public void testModuleOverrideRepeatedInstalls_toProviderKey() {
   1001     Module m = new AbstractModule() {
   1002       @Override protected void configure() {
   1003         OptionalBinder<String> b = OptionalBinder.newOptionalBinder(binder(), String.class);
   1004         b.setDefault().toProvider(Key.get(AStringProvider.class));
   1005         b.setBinding().toProvider(Key.get(BStringProvider.class));
   1006       }
   1007     };
   1008 
   1009     assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(String.class)));
   1010 
   1011     Injector injector = Guice.createInjector(m, Modules.override(m).with(m));
   1012     assertEquals("B", injector.getInstance(Key.get(String.class)));
   1013 
   1014     assertOptionalVisitor(stringKey,
   1015         setOf(m, Modules.override(m).with(m)),
   1016         VisitType.BOTH,
   1017         0,
   1018         providerKey(Key.get(AStringProvider.class)),
   1019         providerKey(Key.get(BStringProvider.class)),
   1020         null);
   1021   }
   1022 
   1023   private static class StringGrabber {
   1024     private final String string;
   1025 
   1026     @SuppressWarnings("unused")  // Found by reflection
   1027     public StringGrabber(@Named("A_string") String string) {
   1028       this.string = string;
   1029     }
   1030 
   1031     @SuppressWarnings("unused")  // Found by reflection
   1032     public StringGrabber(@Named("B_string") String string, int unused) {
   1033       this.string = string;
   1034     }
   1035 
   1036     @Override
   1037     public int hashCode() {
   1038       return string.hashCode();
   1039     }
   1040 
   1041     @Override
   1042     public boolean equals(Object obj) {
   1043       return (obj instanceof StringGrabber) && ((StringGrabber) obj).string.equals(string);
   1044     }
   1045 
   1046     @Override
   1047     public String toString() {
   1048       return "StringGrabber(" + string + ")";
   1049     }
   1050   }
   1051 
   1052   public void testModuleOverrideRepeatedInstalls_toConstructor() {
   1053     Module m = new AbstractModule() {
   1054       @Override protected void configure() {
   1055         Key<String> aKey = Key.get(String.class, Names.named("A_string"));
   1056         Key<String> bKey = Key.get(String.class, Names.named("B_string"));
   1057         bind(aKey).toInstance("A");
   1058         bind(bKey).toInstance("B");
   1059         bind(Integer.class).toInstance(0);  // used to disambiguate constructors
   1060 
   1061 
   1062         OptionalBinder<StringGrabber> b =
   1063             OptionalBinder.newOptionalBinder(binder(), StringGrabber.class);
   1064         try {
   1065           b.setDefault().toConstructor(
   1066               StringGrabber.class.getConstructor(String.class));
   1067           b.setBinding().toConstructor(
   1068               StringGrabber.class.getConstructor(String.class, int.class));
   1069         } catch (NoSuchMethodException e) {
   1070           fail("No such method: " + e.getMessage());
   1071         }
   1072       }
   1073     };
   1074 
   1075     assertEquals("B", Guice.createInjector(m, m).getInstance(Key.get(StringGrabber.class)).string);
   1076 
   1077     Injector injector = Guice.createInjector(m, Modules.override(m).with(m));
   1078     assertEquals("B", injector.getInstance(Key.get(StringGrabber.class)).string);
   1079   }
   1080 
   1081   /**
   1082    * Unscoped bindings should not conflict, whether they were bound with no explicit scope, or
   1083    * explicitly bound in {@link Scopes#NO_SCOPE}.
   1084    */
   1085   public void testDuplicateUnscopedBindings() {
   1086     Module m = new AbstractModule() {
   1087       @Override protected void configure() {
   1088         OptionalBinder<Integer> b = OptionalBinder.newOptionalBinder(binder(), Integer.class);
   1089         b.setDefault().to(Key.get(Integer.class, named("foo")));
   1090         b.setDefault().to(Key.get(Integer.class, named("foo"))).in(Scopes.NO_SCOPE);
   1091         b.setBinding().to(Key.get(Integer.class, named("foo")));
   1092         b.setBinding().to(Key.get(Integer.class, named("foo"))).in(Scopes.NO_SCOPE);
   1093       }
   1094       @Provides @Named("foo") int provideInt() { return 5; }
   1095     };
   1096     assertEquals(5, Guice.createInjector(m).getInstance(Integer.class).intValue());
   1097   }
   1098 
   1099   /**
   1100    * Ensure key hash codes are fixed at injection time, not binding time.
   1101    */
   1102   public void testKeyHashCodesFixedAtInjectionTime() {
   1103     Module m = new AbstractModule() {
   1104       @Override protected void configure() {
   1105         OptionalBinder<List<String>> b = OptionalBinder.newOptionalBinder(binder(), listOfStrings);
   1106         List<String> list = Lists.newArrayList();
   1107         b.setDefault().toInstance(list);
   1108         b.setBinding().toInstance(list);
   1109         list.add("A");
   1110         list.add("B");
   1111       }
   1112     };
   1113 
   1114     Injector injector = Guice.createInjector(m);
   1115     for (Entry<Key<?>, Binding<?>> entry : injector.getAllBindings().entrySet()) {
   1116       Key<?> bindingKey = entry.getKey();
   1117       Key<?> clonedKey;
   1118       if (bindingKey.getAnnotation() != null) {
   1119         clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotation());
   1120       } else if (bindingKey.getAnnotationType() != null) {
   1121         clonedKey = Key.get(bindingKey.getTypeLiteral(), bindingKey.getAnnotationType());
   1122       } else {
   1123         clonedKey = Key.get(bindingKey.getTypeLiteral());
   1124       }
   1125       assertEquals(bindingKey, clonedKey);
   1126       assertEquals("Incorrect hashcode for " + bindingKey + " -> " + entry.getValue(),
   1127           bindingKey.hashCode(), clonedKey.hashCode());
   1128     }
   1129   }
   1130 
   1131   /**
   1132    * Ensure bindings do not rehash their keys once returned from {@link Elements#getElements}.
   1133    */
   1134   public void testBindingKeysFixedOnReturnFromGetElements() {
   1135     final List<String> list = Lists.newArrayList();
   1136     Module m = new AbstractModule() {
   1137       @Override protected void configure() {
   1138         OptionalBinder<List<String>> b = OptionalBinder.newOptionalBinder(binder(), listOfStrings);
   1139         b.setDefault().toInstance(list);
   1140         list.add("A");
   1141         list.add("B");
   1142       }
   1143     };
   1144 
   1145     InstanceBinding<?> binding = Iterables.getOnlyElement(
   1146         Iterables.filter(Elements.getElements(m), InstanceBinding.class));
   1147     Key<?> keyBefore = binding.getKey();
   1148     assertEquals(listOfStrings, keyBefore.getTypeLiteral());
   1149 
   1150     list.add("C");
   1151     Key<?> keyAfter = binding.getKey();
   1152     assertSame(keyBefore, keyAfter);
   1153   }
   1154 
   1155   @BindingAnnotation
   1156   @Retention(RetentionPolicy.RUNTIME)
   1157   @Target({ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD})
   1158   private static @interface Marker {}
   1159 
   1160   @Marker
   1161   public void testMatchingMarkerAnnotations() throws Exception {
   1162     Method m = OptionalBinderTest.class.getDeclaredMethod("testMatchingMarkerAnnotations");
   1163     assertNotNull(m);
   1164     final Annotation marker = m.getAnnotation(Marker.class);
   1165     Injector injector = Guice.createInjector(new AbstractModule() {
   1166       @Override public void configure() {
   1167         OptionalBinder<Integer> mb1 =
   1168             OptionalBinder.newOptionalBinder(binder(), Key.get(Integer.class, Marker.class));
   1169         OptionalBinder<Integer> mb2 =
   1170             OptionalBinder.newOptionalBinder(binder(), Key.get(Integer.class, marker));
   1171         mb1.setDefault().toInstance(1);
   1172         mb2.setBinding().toInstance(2);
   1173 
   1174         // This assures us that the two binders are equivalent, so we expect the instance added to
   1175         // each to have been added to one set.
   1176         assertEquals(mb1, mb2);
   1177       }
   1178     });
   1179     Integer i1 = injector.getInstance(Key.get(Integer.class, Marker.class));
   1180     Integer i2 = injector.getInstance(Key.get(Integer.class, marker));
   1181 
   1182     // These must be identical, because the marker annotations collapsed to the same thing.
   1183     assertSame(i1, i2);
   1184     assertEquals(2, i2.intValue());
   1185   }
   1186 
   1187  // Tests for com.google.inject.internal.WeakKeySet not leaking memory.
   1188  public void testWeakKeySet_integration() {
   1189    Injector parentInjector = Guice.createInjector(new AbstractModule() {
   1190          @Override protected void configure() {
   1191            bind(String.class).toInstance("hi");
   1192          }
   1193        });
   1194    WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class));
   1195 
   1196    Injector childInjector = parentInjector.createChildInjector(new AbstractModule() {
   1197      @Override protected void configure() {
   1198        OptionalBinder.newOptionalBinder(binder(), Integer.class).setDefault().toInstance(4);
   1199      }
   1200    });
   1201    WeakReference<Injector> weakRef = new WeakReference<Injector>(childInjector);
   1202    WeakKeySetUtils.assertBlacklisted(parentInjector, Key.get(Integer.class));
   1203 
   1204    // Clear the ref, GC, and ensure that we are no longer blacklisting.
   1205    childInjector = null;
   1206 
   1207    Asserts.awaitClear(weakRef);
   1208    WeakKeySetUtils.assertNotBlacklisted(parentInjector, Key.get(Integer.class));
   1209  }
   1210 
   1211  public void testCompareEqualsAgainstOtherAnnotation() {
   1212    OptionalBinder.Actual impl1 = new OptionalBinder.ActualImpl("foo");
   1213    OptionalBinder.Actual other1 = Dummy.class.getAnnotation(OptionalBinder.Actual.class);
   1214    assertEquals(impl1, other1);
   1215 
   1216    OptionalBinder.Default impl2 = new OptionalBinder.DefaultImpl("foo");
   1217    OptionalBinder.Default other2 = Dummy.class.getAnnotation(OptionalBinder.Default.class);
   1218    assertEquals(impl2, other2);
   1219 
   1220    assertFalse(impl1.equals(impl2));
   1221    assertFalse(impl1.equals(other2));
   1222    assertFalse(impl2.equals(other1));
   1223    assertFalse(other1.equals(other2));
   1224  }
   1225 
   1226   @OptionalBinder.Actual("foo")
   1227   @OptionalBinder.Default("foo")
   1228   static class Dummy {}
   1229 
   1230   @SuppressWarnings("unchecked")
   1231   private <V> Set<V> setOf(V... elements) {
   1232     return ImmutableSet.copyOf(elements);
   1233   }
   1234 
   1235   @SuppressWarnings("unchecked")
   1236   private <T> Optional<T> toOptional(Object object) throws Exception {
   1237     assertTrue("not a java.util.Optional: " + object.getClass(),
   1238         JAVA_OPTIONAL_CLASS.isInstance(object));
   1239     return Optional.fromNullable((T) JAVA_OPTIONAL_OR_ELSE.invoke(object, (Void) null));
   1240   }
   1241 }
   1242