• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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@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 
testTypeNotBoundByDefault()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 
testOptionalIsAbsentByDefault()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 
testUsesUserBoundValue()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 
testSetDefault()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 
testSetBinding()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 
testSetBindingOverridesDefault()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 
testSpreadAcrossModules()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 
testExactSameBindingCollapses_defaults()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 
testExactSameBindingCollapses_actual()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 
testDifferentBindingsFail_defaults()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 
testDifferentBindingsFail_actual()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 
testDifferentBindingsFail_both()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 
testQualifiedAggregatesTogether()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 
testMultipleDifferentOptionals()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 
testOptionalIsAppropriatelyLazy()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 
testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_default()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 
testLinkedToNullProvidersMakeAbsentValuesAndPresentProviders_actual()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?
testLinkedToNullActualDoesntFallbackToDefault()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 
testSourceLinesInException()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 
testDependencies_both()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 
testDependencies_actual()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 
testDependencies_default()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")
recurseForDependencies(Injector injector, HasDependencies hasDependencies)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    */
testModuleOverrideRepeatedInstalls_toInstance()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 
testModuleOverrideRepeatedInstalls_toKey()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 
testModuleOverrideRepeatedInstalls_toProviderInstance()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> {
get()989     public String get() {
990       return "A";
991     }
992   }
993 
994   private static class BStringProvider implements Provider<String> {
get()995     public String get() {
996       return "B";
997     }
998   }
999 
testModuleOverrideRepeatedInstalls_toProviderKey()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
StringGrabber(@amed"A_string") String string)1027     public StringGrabber(@Named("A_string") String string) {
1028       this.string = string;
1029     }
1030 
1031     @SuppressWarnings("unused")  // Found by reflection
StringGrabber(@amed"B_string") String string, int unused)1032     public StringGrabber(@Named("B_string") String string, int unused) {
1033       this.string = string;
1034     }
1035 
1036     @Override
hashCode()1037     public int hashCode() {
1038       return string.hashCode();
1039     }
1040 
1041     @Override
equals(Object obj)1042     public boolean equals(Object obj) {
1043       return (obj instanceof StringGrabber) && ((StringGrabber) obj).string.equals(string);
1044     }
1045 
1046     @Override
toString()1047     public String toString() {
1048       return "StringGrabber(" + string + ")";
1049     }
1050   }
1051 
testModuleOverrideRepeatedInstalls_toConstructor()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    */
testDuplicateUnscopedBindings()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    */
testKeyHashCodesFixedAtInjectionTime()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    */
testBindingKeysFixedOnReturnFromGetElements()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
testMatchingMarkerAnnotations()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.
testWeakKeySet_integration()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 
testCompareEqualsAgainstOtherAnnotation()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")
setOf(V... elements)1231   private <V> Set<V> setOf(V... elements) {
1232     return ImmutableSet.copyOf(elements);
1233   }
1234 
1235   @SuppressWarnings("unchecked")
toOptional(Object object)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