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