1 /**
2  * Copyright (C) 2008 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.spi;
18 
19 import static com.google.common.collect.Iterables.getOnlyElement;
20 import static com.google.inject.Asserts.assertContains;
21 import static com.google.inject.Asserts.getDeclaringSourcePart;
22 import static com.google.inject.Asserts.isIncludeStackTraceComplete;
23 import static java.lang.annotation.RetentionPolicy.RUNTIME;
24 
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.inject.AbstractModule;
28 import com.google.inject.Binding;
29 import com.google.inject.BindingAnnotation;
30 import com.google.inject.Inject;
31 import com.google.inject.Key;
32 import com.google.inject.MembersInjector;
33 import com.google.inject.Module;
34 import com.google.inject.PrivateBinder;
35 import com.google.inject.Provider;
36 import com.google.inject.Scope;
37 import com.google.inject.Scopes;
38 import com.google.inject.Singleton;
39 import com.google.inject.Stage;
40 import com.google.inject.TypeLiteral;
41 import com.google.inject.binder.AnnotatedBindingBuilder;
42 import com.google.inject.binder.AnnotatedConstantBindingBuilder;
43 import com.google.inject.binder.ConstantBindingBuilder;
44 import com.google.inject.binder.ScopedBindingBuilder;
45 import com.google.inject.matcher.Matcher;
46 import com.google.inject.matcher.Matchers;
47 import com.google.inject.name.Named;
48 import com.google.inject.name.Names;
49 import com.google.inject.util.Providers;
50 
51 import junit.framework.TestCase;
52 
53 import java.lang.annotation.Annotation;
54 import java.lang.annotation.ElementType;
55 import java.lang.annotation.Retention;
56 import java.lang.annotation.Target;
57 import java.lang.reflect.Constructor;
58 import java.lang.reflect.Field;
59 import java.util.ArrayList;
60 import java.util.Arrays;
61 import java.util.Collection;
62 import java.util.HashMap;
63 import java.util.Iterator;
64 import java.util.List;
65 import java.util.Map;
66 import java.util.Set;
67 import java.util.TreeSet;
68 import java.util.concurrent.atomic.AtomicInteger;
69 import java.util.concurrent.atomic.AtomicReference;
70 
71 /**
72  * @author jessewilson@google.com (Jesse Wilson)
73  */
74 public class ElementsTest extends TestCase {
75 
76   // Binder fidelity tests
77 
testAddMessageErrorCommand()78   public void testAddMessageErrorCommand() {
79     checkModule(
80         new AbstractModule() {
81           @Override protected void configure() {
82             addError("Message %s %d %s", "A", 5, "C");
83           }
84         },
85 
86         new FailingElementVisitor() {
87           @Override public Void visit(Message command) {
88             assertEquals("Message A 5 C", command.getMessage());
89             assertNull(command.getCause());
90             assertContains(command.getSources().toString(),
91                 ElementsTest.class.getName(),
92                 getDeclaringSourcePart(ElementsTest.class));
93             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
94             return null;
95           }
96         }
97     );
98   }
99 
testAddThrowableErrorCommand()100   public void testAddThrowableErrorCommand() {
101     checkModule(
102         new AbstractModule() {
103           protected void configure() {
104             addError(new Exception("A"));
105           }
106         },
107 
108         new FailingElementVisitor() {
109           @Override public Void visit(Message command) {
110             assertEquals("A", command.getCause().getMessage());
111             assertEquals(command.getMessage(),
112                 "An exception was caught and reported. Message: A");
113             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
114             return null;
115           }
116         }
117     );
118   }
119 
testErrorsAddedWhenExceptionsAreThrown()120   public void testErrorsAddedWhenExceptionsAreThrown() {
121     checkModule(
122         new AbstractModule() {
123           protected void configure() {
124             install(new AbstractModule() {
125               protected void configure() {
126                 throw new RuntimeException("Throwing RuntimeException in AbstractModule.configure().");
127               }
128             });
129 
130             addError("Code after the exception still gets executed");
131           }
132         },
133 
134         new FailingElementVisitor() {
135           @Override public Void visit(Message command) {
136             assertEquals("Throwing RuntimeException in AbstractModule.configure().",
137                 command.getCause().getMessage());
138             return null;
139           }
140         },
141 
142         new FailingElementVisitor() {
143           @Override public Void visit(Message command) {
144             assertEquals("Code after the exception still gets executed",
145                 command.getMessage());
146             return null;
147           }
148         }
149     );
150   }
151 
getInstance(Binding<T> binding)152   private <T> T getInstance(Binding<T> binding) {
153     return binding.acceptTargetVisitor(Elements.<T>getInstanceVisitor());
154   }
155 
testBindConstantAnnotations()156   public void testBindConstantAnnotations() {
157     checkModule(
158         new AbstractModule() {
159           protected void configure() {
160             bindConstant().annotatedWith(SampleAnnotation.class).to("A");
161             bindConstant().annotatedWith(Names.named("Bee")).to("B");
162           }
163         },
164 
165         new FailingElementVisitor() {
166           @Override public <T> Void visit(Binding<T> command) {
167             assertTrue(command instanceof InstanceBinding);
168             assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
169             assertEquals("A", getInstance(command));
170             return null;
171           }
172         },
173 
174         new FailingElementVisitor() {
175           @Override public <T> Void visit(Binding<T> command) {
176             assertTrue(command instanceof InstanceBinding);
177             assertEquals(Key.get(String.class, Names.named("Bee")), command.getKey());
178             assertEquals("B", getInstance(command));
179             return null;
180           }
181         }
182     );
183   }
184 
testBindConstantTypes()185   public void testBindConstantTypes() {
186     checkModule(
187         new AbstractModule() {
188           protected void configure() {
189             bindConstant().annotatedWith(Names.named("String")).to("A");
190             bindConstant().annotatedWith(Names.named("int")).to(2);
191             bindConstant().annotatedWith(Names.named("long")).to(3L);
192             bindConstant().annotatedWith(Names.named("boolean")).to(false);
193             bindConstant().annotatedWith(Names.named("double")).to(5.0d);
194             bindConstant().annotatedWith(Names.named("float")).to(6.0f);
195             bindConstant().annotatedWith(Names.named("short")).to((short) 7);
196             bindConstant().annotatedWith(Names.named("char")).to('h');
197             bindConstant().annotatedWith(Names.named("byte")).to((byte) 8);
198             bindConstant().annotatedWith(Names.named("Class")).to(Iterator.class);
199             bindConstant().annotatedWith(Names.named("Enum")).to(CoinSide.TAILS);
200           }
201         },
202 
203         new FailingElementVisitor() {
204           @Override public <T> Void visit(Binding<T> command) {
205             assertTrue(command instanceof InstanceBinding);
206             assertEquals(Key.get(String.class, Names.named("String")), command.getKey());
207             assertEquals("A", getInstance(command));
208             return null;
209           }
210         },
211 
212         new FailingElementVisitor() {
213           @Override public <T> Void visit(Binding<T> command) {
214             assertTrue(command instanceof InstanceBinding);
215             assertEquals(Key.get(Integer.class, Names.named("int")), command.getKey());
216             assertEquals(2, getInstance(command));
217             return null;
218           }
219         },
220 
221         new FailingElementVisitor() {
222           @Override public <T> Void visit(Binding<T> command) {
223             assertTrue(command instanceof InstanceBinding);
224             assertEquals(Key.get(Long.class, Names.named("long")), command.getKey());
225             assertEquals(3L, getInstance(command));
226             return null;
227           }
228         },
229 
230         new FailingElementVisitor() {
231           @Override public <T> Void visit(Binding<T> command) {
232             assertTrue(command instanceof InstanceBinding);
233             assertEquals(Key.get(Boolean.class, Names.named("boolean")), command.getKey());
234             assertEquals(false, getInstance(command));
235             return null;
236           }
237         },
238 
239         new FailingElementVisitor() {
240           @Override public <T> Void visit(Binding<T> command) {
241             assertTrue(command instanceof InstanceBinding);
242             assertEquals(Key.get(Double.class, Names.named("double")), command.getKey());
243             assertEquals(5.0d, getInstance(command));
244             return null;
245           }
246         },
247 
248         new FailingElementVisitor() {
249           @Override public <T> Void visit(Binding<T> command) {
250             assertTrue(command instanceof InstanceBinding);
251             assertEquals(Key.get(Float.class, Names.named("float")), command.getKey());
252             assertEquals(6.0f, getInstance(command));
253             return null;
254           }
255         },
256 
257         new FailingElementVisitor() {
258           @Override public <T> Void visit(Binding<T> command) {
259             assertTrue(command instanceof InstanceBinding);
260             assertEquals(Key.get(Short.class, Names.named("short")), command.getKey());
261             assertEquals((short) 7, getInstance(command));
262             return null;
263           }
264         },
265 
266         new FailingElementVisitor() {
267           @Override public <T> Void visit(Binding<T> command) {
268             assertTrue(command instanceof InstanceBinding);
269             assertEquals(Key.get(Character.class, Names.named("char")), command.getKey());
270             assertEquals('h', getInstance(command));
271             return null;
272           }
273         },
274 
275         new FailingElementVisitor() {
276           @Override public <T> Void visit(Binding<T> command) {
277             assertTrue(command instanceof InstanceBinding);
278             assertEquals(Key.get(Byte.class, Names.named("byte")), command.getKey());
279             assertEquals((byte) 8, getInstance(command));
280             return null;
281           }
282         },
283 
284         new FailingElementVisitor() {
285           @Override public <T> Void visit(Binding<T> command) {
286             assertTrue(command instanceof InstanceBinding);
287             assertEquals(Key.get(Class.class, Names.named("Class")), command.getKey());
288             assertEquals(Iterator.class, getInstance(command));
289             return null;
290           }
291         },
292 
293         new FailingElementVisitor() {
294           @Override public <T> Void visit(Binding<T> command) {
295             assertTrue(command instanceof InstanceBinding);
296             assertEquals(Key.get(CoinSide.class, Names.named("Enum")), command.getKey());
297             assertEquals(CoinSide.TAILS, getInstance(command));
298             return null;
299           }
300         }
301     );
302   }
303 
testBindKeysNoAnnotations()304   public void testBindKeysNoAnnotations() {
305     FailingElementVisitor keyChecker = new FailingElementVisitor() {
306       @Override public <T> Void visit(Binding<T> command) {
307         assertEquals(Key.get(String.class), command.getKey());
308         return null;
309       }
310     };
311 
312     checkModule(
313         new AbstractModule() {
314           protected void configure() {
315             bind(String.class).toInstance("A");
316             bind(new TypeLiteral<String>() {}).toInstance("B");
317             bind(Key.get(String.class)).toInstance("C");
318           }
319         },
320         keyChecker,
321         keyChecker,
322         keyChecker
323     );
324   }
325 
testBindKeysWithAnnotationType()326   public void testBindKeysWithAnnotationType() {
327     FailingElementVisitor annotationChecker = new FailingElementVisitor() {
328       @Override public <T> Void visit(Binding<T> command) {
329         assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
330         return null;
331       }
332     };
333 
334     checkModule(
335         new AbstractModule() {
336           protected void configure() {
337             bind(String.class).annotatedWith(SampleAnnotation.class).toInstance("A");
338             bind(new TypeLiteral<String>() {}).annotatedWith(SampleAnnotation.class).toInstance("B");
339           }
340         },
341         annotationChecker,
342         annotationChecker
343     );
344   }
345 
testBindKeysWithAnnotationInstance()346   public void testBindKeysWithAnnotationInstance() {
347     FailingElementVisitor annotationChecker = new FailingElementVisitor() {
348       @Override public <T> Void visit(Binding<T> command) {
349         assertEquals(Key.get(String.class, Names.named("a")), command.getKey());
350         return null;
351       }
352     };
353 
354 
355     checkModule(
356         new AbstractModule() {
357           protected void configure() {
358             bind(String.class).annotatedWith(Names.named("a")).toInstance("B");
359             bind(new TypeLiteral<String>() {}).annotatedWith(Names.named("a")).toInstance("C");
360           }
361         },
362         annotationChecker,
363         annotationChecker
364     );
365   }
366 
testBindToProvider()367   public void testBindToProvider() {
368     final Provider<String> aProvider = new Provider<String>() {
369       public String get() {
370         return "A";
371       }
372     };
373 
374     final javax.inject.Provider<Integer> intJavaxProvider = new javax.inject.Provider<Integer>() {
375       public Integer get() {
376         return 42;
377       }
378     };
379 
380     final javax.inject.Provider<Double> doubleJavaxProvider = new javax.inject.Provider<Double>() {
381       @javax.inject.Inject String string;
382 
383       public Double get() {
384         return 42.42;
385       }
386     };
387 
388     checkModule(
389         new AbstractModule() {
390           protected void configure() {
391             bind(String.class).toProvider(aProvider);
392             bind(Integer.class).toProvider(intJavaxProvider);
393             bind(Double.class).toProvider(doubleJavaxProvider);
394             bind(List.class).toProvider(ListProvider.class);
395             bind(Collection.class).toProvider(Key.get(ListProvider.class));
396             bind(Iterable.class).toProvider(new TypeLiteral<TProvider<List>>() {});
397           }
398         },
399 
400         new FailingElementVisitor() {
401           @Override public <T> Void visit(Binding<T> command) {
402             assertTrue(command instanceof ProviderInstanceBinding);
403             assertEquals(Key.get(String.class), command.getKey());
404             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
405               @Override public Void visit(
406                   ProviderInstanceBinding<? extends T> binding) {
407                 assertSame(aProvider, binding.getUserSuppliedProvider());
408                 assertSame(aProvider, binding.getProviderInstance());
409                 return null;
410               }
411             });
412             return null;
413           }
414         },
415 
416         new FailingElementVisitor() {
417           @Override public <T> Void visit(Binding<T> command) {
418             assertTrue(command instanceof ProviderInstanceBinding);
419             assertEquals(Key.get(Integer.class), command.getKey());
420             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
421               @Override public Void visit(
422                   ProviderInstanceBinding<? extends T> binding) {
423                 assertSame(intJavaxProvider, binding.getUserSuppliedProvider());
424                 assertEquals(42, binding.getProviderInstance().get());
425                 // we don't wrap this w/ dependencies if there were none.
426                 assertFalse(binding.getProviderInstance() instanceof HasDependencies);
427                 return null;
428               }
429             });
430             return null;
431           }
432         },
433 
434         new FailingElementVisitor() {
435           @Override public <T> Void visit(Binding<T> command) {
436             assertTrue(command instanceof ProviderInstanceBinding);
437             assertEquals(Key.get(Double.class), command.getKey());
438             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
439               @Override public Void visit(
440                   ProviderInstanceBinding<? extends T> binding) {
441                 assertSame(doubleJavaxProvider, binding.getUserSuppliedProvider());
442                 assertEquals(42.42, binding.getProviderInstance().get());
443                 // we do wrap it with dependencies if there were some.
444                 assertTrue(binding.getProviderInstance() instanceof HasDependencies);
445                 Set<Dependency<?>> deps =
446                     ((HasDependencies) binding.getProviderInstance()).getDependencies();
447                 assertEquals(1, deps.size());
448                 assertEquals(String.class,
449                     deps.iterator().next().getKey().getTypeLiteral().getRawType());
450                 return null;
451               }
452             });
453             return null;
454           }
455         },
456 
457         new FailingElementVisitor() {
458           @Override public <T> Void visit(Binding<T> command) {
459             assertTrue(command instanceof ProviderKeyBinding);
460             assertEquals(Key.get(List.class), command.getKey());
461             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
462               @Override public Void visit(ProviderKeyBinding<? extends T> binding) {
463                 assertEquals(Key.get(ListProvider.class), binding.getProviderKey());
464                 return null;
465               }
466             });
467             return null;
468           }
469         },
470 
471         new FailingElementVisitor() {
472           @Override public <T> Void visit(Binding<T> command) {
473             assertTrue(command instanceof ProviderKeyBinding);
474             assertEquals(Key.get(Collection.class), command.getKey());
475             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
476               @Override public Void visit(ProviderKeyBinding<? extends T> binding) {
477                 assertEquals(Key.get(ListProvider.class), binding.getProviderKey());
478                 return null;
479               }
480             });
481             return null;
482           }
483         },
484 
485         new FailingElementVisitor() {
486           @Override public <T> Void visit(Binding<T> command) {
487             assertTrue(command instanceof ProviderKeyBinding);
488             assertEquals(Key.get(Iterable.class), command.getKey());
489             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
490               @Override public Void visit(ProviderKeyBinding<? extends T> binding) {
491                 assertEquals(new Key<TProvider<List>>() {}, binding.getProviderKey());
492                 return null;
493               }
494             });
495             return null;
496           }
497         }
498     );
499   }
500 
testBindToLinkedBinding()501   public void testBindToLinkedBinding() {
502     checkModule(
503         new AbstractModule() {
504           protected void configure() {
505             bind(List.class).to(ArrayList.class);
506             bind(Map.class).to(new TypeLiteral<HashMap<Integer, String>>() {});
507             bind(Set.class).to(Key.get(TreeSet.class, SampleAnnotation.class));
508           }
509         },
510 
511         new FailingElementVisitor() {
512           @Override public <T> Void visit(Binding<T> command) {
513             assertTrue(command instanceof LinkedKeyBinding);
514             assertEquals(Key.get(List.class), command.getKey());
515             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
516               @Override public Void visit(LinkedKeyBinding<? extends T> binding) {
517                 assertEquals(Key.get(ArrayList.class), binding.getLinkedKey());
518                 return null;
519               }
520             });
521             return null;
522           }
523         },
524 
525         new FailingElementVisitor() {
526           @Override public <T> Void visit(Binding<T> command) {
527             assertTrue(command instanceof LinkedKeyBinding);
528             assertEquals(Key.get(Map.class), command.getKey());
529             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
530               @Override public Void visit(LinkedKeyBinding<? extends T> binding) {
531                 assertEquals(Key.get(new TypeLiteral<HashMap<Integer, String>>() {}),
532                     binding.getLinkedKey());
533                 return null;
534               }
535             });
536             return null;
537           }
538         },
539 
540         new FailingElementVisitor() {
541           @Override public <T> Void visit(Binding<T> command) {
542             assertTrue(command instanceof LinkedKeyBinding);
543             assertEquals(Key.get(Set.class), command.getKey());
544             command.acceptTargetVisitor(new FailingTargetVisitor<T>() {
545               @Override public Void visit(LinkedKeyBinding<? extends T> binding) {
546                 assertEquals(Key.get(TreeSet.class, SampleAnnotation.class),
547                     binding.getLinkedKey());
548                 return null;
549               }
550             });
551             return null;
552           }
553         }
554     );
555   }
556 
testBindToInstance()557   public void testBindToInstance() {
558     checkModule(
559         new AbstractModule() {
560           protected void configure() {
561             bind(String.class).toInstance("A");
562           }
563         },
564 
565         new FailingElementVisitor() {
566           @Override public <T> Void visit(Binding<T> command) {
567             assertTrue(command instanceof InstanceBinding);
568             assertEquals(Key.get(String.class), command.getKey());
569             assertEquals("A", getInstance(command));
570             return null;
571           }
572         }
573     );
574   }
575 
testBindInScopes()576   public void testBindInScopes() {
577     checkModule(
578         new AbstractModule() {
579           protected void configure() {
580             bind(String.class);
581             bind(List.class).to(ArrayList.class).in(Scopes.SINGLETON);
582             bind(Map.class).to(HashMap.class).in(Singleton.class);
583             bind(Set.class).to(TreeSet.class).asEagerSingleton();
584           }
585         },
586 
587         new FailingElementVisitor() {
588           @Override public <T> Void visit(Binding<T> command) {
589             assertEquals(Key.get(String.class), command.getKey());
590             command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
591               @Override public Void visitNoScoping() {
592                 return null;
593               }
594             });
595             return null;
596           }
597         },
598 
599         new FailingElementVisitor() {
600           @Override public <T> Void visit(Binding<T> command) {
601             assertEquals(Key.get(List.class), command.getKey());
602             command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
603               @Override public Void visitScope(Scope scope) {
604                 assertEquals(Scopes.SINGLETON, scope);
605                 return null;
606               }
607             });
608             return null;
609           }
610         },
611 
612         new FailingElementVisitor() {
613           @Override public <T> Void visit(Binding<T> command) {
614             assertEquals(Key.get(Map.class), command.getKey());
615             command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
616               @Override public Void visitScopeAnnotation(Class<? extends Annotation> annotation) {
617                 assertEquals(Singleton.class, annotation);
618                 return null;
619               }
620             });
621             return null;
622           }
623         },
624 
625         new FailingElementVisitor() {
626           @Override public <T> Void visit(Binding<T> command) {
627             assertEquals(Key.get(Set.class), command.getKey());
628             command.acceptScopingVisitor(new FailingBindingScopingVisitor() {
629               public Void visitEagerSingleton() {
630                 return null;
631               }
632             });
633             return null;
634           }
635         }
636     );
637   }
638 
testBindToInstanceInScope()639   public void testBindToInstanceInScope() {
640     checkModule(
641         new AbstractModule() {
642           protected void configure() {
643             AnnotatedBindingBuilder<String> b = bind(String.class);
644             b.toInstance("A");
645             b.in(Singleton.class);
646           }
647         },
648 
649         new FailingElementVisitor() {
650           @Override public <T> Void visit(Binding<T> command) {
651             return null;
652           }
653         },
654 
655         new FailingElementVisitor() {
656           @Override public Void visit(Message command) {
657             assertEquals("Setting the scope is not permitted when binding to a single instance.",
658                 command.getMessage());
659             assertNull(command.getCause());
660             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
661             return null;
662           }
663         }
664       );
665   }
666 
testBindToInstanceScope()667   public void testBindToInstanceScope() {
668     checkModule(
669         new AbstractModule() {
670           protected void configure() {
671             bind(String.class).toInstance("A");
672           }
673         },
674 
675         new FailingElementVisitor() {
676           @Override public <T> Void visit(Binding<T> binding) {
677             assertEquals(Key.get(String.class), binding.getKey());
678             binding.acceptScopingVisitor(new FailingBindingScopingVisitor() {
679               public Void visitEagerSingleton() {
680                 return null;
681               }
682             });
683             return null;
684           }
685         }
686       );
687   }
688 
689   /*if[AOP]*/
testBindIntercepor()690   public void testBindIntercepor() {
691     final Matcher<Class> classMatcher = Matchers.subclassesOf(List.class);
692     final Matcher<Object> methodMatcher = Matchers.any();
693     final org.aopalliance.intercept.MethodInterceptor methodInterceptor
694         = new org.aopalliance.intercept.MethodInterceptor() {
695       public Object invoke(org.aopalliance.intercept.MethodInvocation methodInvocation) {
696         return null;
697       }
698     };
699 
700     checkModule(
701         new AbstractModule() {
702           protected void configure() {
703             bindInterceptor(classMatcher, methodMatcher, methodInterceptor);
704           }
705         },
706 
707         new FailingElementVisitor() {
708           @Override public Void visit(InterceptorBinding command) {
709             assertSame(classMatcher, command.getClassMatcher());
710             assertSame(methodMatcher, command.getMethodMatcher());
711             assertEquals(Arrays.asList(methodInterceptor), command.getInterceptors());
712             return null;
713           }
714         }
715     );
716   }
717   /*end[AOP]*/
718 
testBindScope()719   public void testBindScope() {
720     checkModule(
721         new AbstractModule() {
722           protected void configure() {
723             bindScope(SampleAnnotation.class, Scopes.NO_SCOPE);
724           }
725         },
726 
727         new FailingElementVisitor() {
728           @Override public Void visit(ScopeBinding command) {
729             assertSame(SampleAnnotation.class, command.getAnnotationType());
730             assertSame(Scopes.NO_SCOPE, command.getScope());
731             return null;
732           }
733         }
734     );
735   }
736 
testBindListener()737   public void testBindListener() {
738     final Matcher<Object> typeMatcher = Matchers.only(TypeLiteral.get(String.class));
739     final TypeListener listener = new TypeListener() {
740       public <I> void hear(TypeLiteral<I> type, TypeEncounter<I> encounter) {
741         throw new UnsupportedOperationException();
742       }
743     };
744 
745     checkModule(
746         new AbstractModule() {
747           protected void configure() {
748             bindListener(typeMatcher, listener);
749           }
750         },
751 
752         new FailingElementVisitor() {
753           @Override public Void visit(TypeListenerBinding binding) {
754             assertSame(typeMatcher, binding.getTypeMatcher());
755             assertSame(listener, binding.getListener());
756             return null;
757           }
758         }
759     );
760   }
761 
testConvertToTypes()762   public void testConvertToTypes() {
763     final TypeConverter typeConverter = new TypeConverter() {
764       public Object convert(String value, TypeLiteral<?> toType) {
765         return value;
766       }
767     };
768 
769     checkModule(
770         new AbstractModule() {
771           protected void configure() {
772             convertToTypes(Matchers.any(), typeConverter);
773           }
774         },
775 
776         new FailingElementVisitor() {
777           @Override public Void visit(TypeConverterBinding command) {
778             assertSame(typeConverter, command.getTypeConverter());
779             assertSame(Matchers.any(), command.getTypeMatcher());
780             return null;
781           }
782         }
783     );
784   }
785 
testGetProvider()786   public void testGetProvider() {
787     checkModule(
788         new AbstractModule() {
789           protected void configure() {
790             Provider<String> keyGetProvider
791                 = getProvider(Key.get(String.class, SampleAnnotation.class));
792             try {
793               keyGetProvider.get();
794             } catch (IllegalStateException e) {
795               assertEquals("This Provider cannot be used until the Injector has been created.",
796                   e.getMessage());
797             }
798 
799             Provider<String> typeGetProvider = getProvider(String.class);
800             try {
801               typeGetProvider.get();
802             } catch (IllegalStateException e) {
803               assertEquals("This Provider cannot be used until the Injector has been created.",
804                   e.getMessage());
805             }
806           }
807         },
808 
809         new FailingElementVisitor() {
810           @Override public <T> Void visit(ProviderLookup<T> command) {
811             assertEquals(Key.get(String.class, SampleAnnotation.class), command.getKey());
812             assertNull(command.getDelegate());
813             return null;
814           }
815         },
816 
817         new FailingElementVisitor() {
818           @Override public <T> Void visit(ProviderLookup<T> command) {
819             assertEquals(Key.get(String.class), command.getKey());
820             assertNull(command.getDelegate());
821             return null;
822           }
823         }
824     );
825   }
826 
testElementInitialization()827   public void testElementInitialization() {
828     final AtomicReference<Provider<String>> providerFromBinder
829         = new AtomicReference<Provider<String>>();
830     final AtomicReference<MembersInjector<String>> membersInjectorFromBinder
831         = new AtomicReference<MembersInjector<String>>();
832 
833     final AtomicReference<String> lastInjected = new AtomicReference<String>();
834     final MembersInjector<String> stringInjector = new MembersInjector<String>() {
835       public void injectMembers(String instance) {
836         lastInjected.set(instance);
837       }
838     };
839 
840     checkModule(
841         new AbstractModule() {
842           protected void configure() {
843             providerFromBinder.set(getProvider(String.class));
844             membersInjectorFromBinder.set(getMembersInjector(String.class));
845           }
846         },
847 
848         new FailingElementVisitor() {
849           public <T> Void visit(ProviderLookup<T> providerLookup) {
850             @SuppressWarnings("unchecked") // we know that T is a String here
851             ProviderLookup<String> stringLookup = (ProviderLookup<String>) providerLookup;
852             stringLookup.initializeDelegate(Providers.of("out"));
853 
854             assertEquals("out", providerFromBinder.get().get());
855             return null;
856           }
857         },
858 
859         new FailingElementVisitor() {
860           @Override public <T> Void visit(MembersInjectorLookup<T> lookup) {
861             @SuppressWarnings("unchecked") // we know that T is a String here
862             MembersInjectorLookup<String> stringLookup = (MembersInjectorLookup<String>) lookup;
863             stringLookup.initializeDelegate(stringInjector);
864 
865             membersInjectorFromBinder.get().injectMembers("in");
866             assertEquals("in", lastInjected.get());
867             return null;
868           }
869         });
870   }
871 
testGetMembersInjector()872   public void testGetMembersInjector() {
873     checkModule(
874         new AbstractModule() {
875           protected void configure() {
876             MembersInjector<A<String>> typeMembersInjector
877                 = getMembersInjector(new TypeLiteral<A<String>>() {});
878             try {
879               typeMembersInjector.injectMembers(new A<String>());
880             } catch (IllegalStateException e) {
881               assertEquals(
882                   "This MembersInjector cannot be used until the Injector has been created.",
883                   e.getMessage());
884             }
885 
886             MembersInjector<String> classMembersInjector = getMembersInjector(String.class);
887             try {
888               classMembersInjector.injectMembers("hello");
889             } catch (IllegalStateException e) {
890               assertEquals(
891                   "This MembersInjector cannot be used until the Injector has been created.",
892                   e.getMessage());
893             }
894           }
895         },
896 
897         new FailingElementVisitor() {
898           @Override public <T> Void visit(MembersInjectorLookup<T> command) {
899             assertEquals(new TypeLiteral<A<String>>() {}, command.getType());
900             assertNull(command.getDelegate());
901             return null;
902           }
903         },
904 
905         new FailingElementVisitor() {
906           @Override public <T> Void visit(MembersInjectorLookup<T> command) {
907             assertEquals(TypeLiteral.get(String.class), command.getType());
908             assertNull(command.getDelegate());
909             return null;
910           }
911         }
912     );
913   }
914 
testRequestInjection()915   public void testRequestInjection() {
916     final Object firstObject = new Object();
917     final Object secondObject = new Object();
918 
919     checkModule(
920         new AbstractModule() {
921           protected void configure() {
922             requestInjection(firstObject);
923             requestInjection(secondObject);
924           }
925         },
926 
927         new FailingElementVisitor() {
928           @Override public Void visit(InjectionRequest<?> command) {
929             assertEquals(firstObject, command.getInstance());
930             return null;
931           }
932         },
933 
934         new FailingElementVisitor() {
935           @Override public Void visit(InjectionRequest<?> command) {
936             assertEquals(secondObject, command.getInstance());
937             return null;
938           }
939         }
940     );
941   }
942 
testRequestStaticInjection()943   public void testRequestStaticInjection() {
944     checkModule(
945         new AbstractModule() {
946           protected void configure() {
947             requestStaticInjection(ArrayList.class);
948           }
949         },
950 
951         new FailingElementVisitor() {
952           @Override public Void visit(StaticInjectionRequest command) {
953             assertEquals(ArrayList.class, command.getType());
954             return null;
955           }
956         }
957     );
958   }
959 
testNewPrivateBinder()960   public void testNewPrivateBinder() {
961     final Key<Collection> collection = Key.get(Collection.class, SampleAnnotation.class);
962     final Key<ArrayList> arrayList = Key.get(ArrayList.class);
963     final ImmutableSet<Key<?>> collections = ImmutableSet.<Key<?>>of(arrayList, collection);
964 
965     final Key<?> a = Key.get(String.class, Names.named("a"));
966     final Key<?> b = Key.get(String.class, Names.named("b"));
967     final ImmutableSet<Key<?>> ab = ImmutableSet.of(a, b);
968 
969     checkModule(
970         new AbstractModule() {
971           protected void configure() {
972             PrivateBinder one = binder().newPrivateBinder();
973             one.expose(ArrayList.class);
974             one.expose(Collection.class).annotatedWith(SampleAnnotation.class);
975             one.bind(List.class).to(ArrayList.class);
976 
977             PrivateBinder two = binder().withSource("1 FooBar")
978                 .newPrivateBinder().withSource("2 FooBar");
979             two.expose(String.class).annotatedWith(Names.named("a"));
980             two.expose(b);
981             two.bind(List.class).to(ArrayList.class);
982           }
983         },
984 
985         new FailingElementVisitor() {
986           @Override public Void visit(PrivateElements one) {
987             assertEquals(collections, one.getExposedKeys());
988             checkElements(one.getElements(),
989                 new FailingElementVisitor() {
990                   @Override public <T> Void visit(Binding<T> binding) {
991                     assertEquals(Key.get(List.class), binding.getKey());
992                     return null;
993                   }
994                 }
995             );
996             return null;
997           }
998         },
999 
1000         new ExternalFailureVisitor() {
1001           @Override public Void visit(PrivateElements two) {
1002             assertEquals(ab, two.getExposedKeys());
1003             assertEquals("1 FooBar", two.getSource().toString());
1004             checkElements(two.getElements(),
1005                 new ExternalFailureVisitor() {
1006                   @Override public <T> Void visit(Binding<T> binding) {
1007                     assertEquals("2 FooBar", binding.getSource().toString());
1008                     assertEquals(Key.get(List.class), binding.getKey());
1009                     return null;
1010                   }
1011                 }
1012             );
1013             return null;
1014           }
1015         }
1016     );
1017   }
1018 
testBindWithMultipleAnnotationsAddsError()1019   public void testBindWithMultipleAnnotationsAddsError() {
1020     checkModule(
1021         new AbstractModule() {
1022           protected void configure() {
1023             AnnotatedBindingBuilder<String> abb = bind(String.class);
1024             abb.annotatedWith(SampleAnnotation.class);
1025             abb.annotatedWith(Names.named("A"));
1026           }
1027         },
1028 
1029         new FailingElementVisitor() {
1030           @Override public <T> Void visit(Binding<T> command) {
1031             return null;
1032           }
1033         },
1034 
1035         new FailingElementVisitor() {
1036           @Override public Void visit(Message command) {
1037             assertEquals("More than one annotation is specified for this binding.",
1038                 command.getMessage());
1039             assertNull(command.getCause());
1040             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
1041             return null;
1042           }
1043         }
1044     );
1045   }
1046 
testBindWithMultipleTargetsAddsError()1047   public void testBindWithMultipleTargetsAddsError() {
1048     checkModule(
1049         new AbstractModule() {
1050           protected void configure() {
1051             AnnotatedBindingBuilder<String> abb = bind(String.class);
1052             abb.toInstance("A");
1053             abb.toInstance("B");
1054           }
1055         },
1056 
1057         new FailingElementVisitor() {
1058           @Override public <T> Void visit(Binding<T> command) {
1059             return null;
1060           }
1061         },
1062 
1063         new FailingElementVisitor() {
1064           @Override public Void visit(Message command) {
1065             assertEquals("Implementation is set more than once.", command.getMessage());
1066             assertNull(command.getCause());
1067             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
1068             return null;
1069           }
1070         }
1071     );
1072   }
1073 
testBindWithMultipleScopesAddsError()1074   public void testBindWithMultipleScopesAddsError() {
1075     checkModule(
1076         new AbstractModule() {
1077           protected void configure() {
1078             ScopedBindingBuilder sbb = bind(List.class).to(ArrayList.class);
1079             sbb.in(Scopes.NO_SCOPE);
1080             sbb.asEagerSingleton();
1081           }
1082         },
1083 
1084         new FailingElementVisitor() {
1085           @Override public <T> Void visit(Binding<T> command) {
1086             return null;
1087           }
1088         },
1089 
1090         new FailingElementVisitor() {
1091           @Override public Void visit(Message command) {
1092             assertEquals("Scope is set more than once.", command.getMessage());
1093             assertNull(command.getCause());
1094             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
1095             return null;
1096           }
1097         }
1098     );
1099   }
1100 
testBindConstantWithMultipleAnnotationsAddsError()1101   public void testBindConstantWithMultipleAnnotationsAddsError() {
1102     checkModule(
1103         new AbstractModule() {
1104           protected void configure() {
1105             AnnotatedConstantBindingBuilder cbb = bindConstant();
1106             cbb.annotatedWith(SampleAnnotation.class).to("A");
1107             cbb.annotatedWith(Names.named("A"));
1108           }
1109         },
1110 
1111         new FailingElementVisitor() {
1112           @Override public <T> Void visit(Binding<T> command) {
1113             return null;
1114           }
1115         },
1116 
1117         new FailingElementVisitor() {
1118           @Override public Void visit(Message command) {
1119             assertEquals("More than one annotation is specified for this binding.",
1120                 command.getMessage());
1121             assertNull(command.getCause());
1122             assertContains(command.getSource(), getDeclaringSourcePart(ElementsTest.class));
1123             return null;
1124           }
1125         }
1126     );
1127   }
1128 
testBindConstantWithMultipleTargetsAddsError()1129   public void testBindConstantWithMultipleTargetsAddsError() {
1130     checkModule(
1131         new AbstractModule() {
1132           protected void configure() {
1133             ConstantBindingBuilder cbb = bindConstant().annotatedWith(SampleAnnotation.class);
1134             cbb.to("A");
1135             cbb.to("B");
1136           }
1137         },
1138 
1139         new FailingElementVisitor() {
1140           @Override public <T> Void visit(Binding<T> command) {
1141             return null;
1142           }
1143         },
1144 
1145         new FailingElementVisitor() {
1146           @Override public Void visit(Message message) {
1147             assertEquals("Constant value is set more than once.", message.getMessage());
1148             assertNull(message.getCause());
1149             assertContains(message.getSource(), getDeclaringSourcePart(ElementsTest.class));
1150             return null;
1151           }
1152         }
1153     );
1154   }
1155 
testBindToConstructor()1156   public void testBindToConstructor() throws NoSuchMethodException, NoSuchFieldException {
1157     final Constructor<A> aConstructor = A.class.getDeclaredConstructor();
1158     final Constructor<B> bConstructor = B.class.getDeclaredConstructor(Object.class);
1159     final Field field = B.class.getDeclaredField("stage");
1160 
1161     checkModule(
1162         new AbstractModule() {
1163           protected void configure() {
1164             bind(A.class).toConstructor(aConstructor);
1165             bind(B.class).toConstructor(bConstructor, new TypeLiteral<B<Integer>>() {})
1166                 .in(Singleton.class);
1167           }
1168         },
1169 
1170         new FailingElementVisitor() {
1171           @Override public <T> Void visit(Binding<T> binding) {
1172             assertEquals(new Key<A>() {}, binding.getKey());
1173 
1174             return binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
1175               @Override public Void visit(ConstructorBinding<? extends T> constructorBinding) {
1176                 InjectionPoint injectionPoint = constructorBinding.getConstructor();
1177                 assertEquals(aConstructor, injectionPoint.getMember());
1178                 assertEquals(new TypeLiteral<A>() {}, injectionPoint.getDeclaringType());
1179                 return null;
1180               }
1181             });
1182           }
1183         },
1184 
1185         new FailingElementVisitor() {
1186           @Override public <T> Void visit(Binding<T> binding) {
1187             assertEquals(new Key<B>() {}, binding.getKey());
1188             binding.acceptScopingVisitor(new FailingBindingScopingVisitor() {
1189               @Override public Void visitScopeAnnotation(Class<? extends Annotation> annotation) {
1190                 assertEquals(Singleton.class, annotation);
1191                 return null;
1192               }
1193             });
1194 
1195             binding.acceptTargetVisitor(new FailingTargetVisitor<T>() {
1196               @Override public Void visit(ConstructorBinding<? extends T> constructorBinding) {
1197                 assertEquals(bConstructor, constructorBinding.getConstructor().getMember());
1198                 assertEquals(Key.get(Integer.class),
1199                     getOnlyElement(constructorBinding.getConstructor().getDependencies()).getKey());
1200                 assertEquals(field,
1201                     getOnlyElement(constructorBinding.getInjectableMembers()).getMember());
1202                 assertEquals(2, constructorBinding.getDependencies().size());
1203 /*if[AOP]*/
1204                 assertEquals(ImmutableMap.of(), constructorBinding.getMethodInterceptors());
1205 /*end[AOP]*/
1206                 return null;
1207               }
1208             });
1209             return null;
1210           }
1211         }
1212     );
1213   }
1214 
testBindToMalformedConstructor()1215   public void testBindToMalformedConstructor() throws NoSuchMethodException, NoSuchFieldException {
1216     final Constructor<C> constructor = C.class.getDeclaredConstructor(Integer.class);
1217 
1218     checkModule(
1219         new AbstractModule() {
1220           protected void configure() {
1221             bind(C.class).toConstructor(constructor);
1222           }
1223         },
1224 
1225         new FailingElementVisitor() {
1226           @Override public <T> Void visit(Binding<T> binding) {
1227             assertEquals(Key.get(C.class), binding.getKey());
1228             assertTrue(binding instanceof UntargettedBinding);
1229             return null;
1230           }
1231         },
1232 
1233         new ExternalFailureVisitor() {
1234           @Override public Void visit(Message message) {
1235             assertContains(message.getMessage(),
1236                 C.class.getName() + ".a has more than one annotation ",
1237                 Named.class.getName(), SampleAnnotation.class.getName());
1238             return null;
1239           }
1240         },
1241 
1242         new ExternalFailureVisitor() {
1243           @Override public Void visit(Message message) {
1244             assertContains(message.getMessage(),
1245                 C.class.getName() + ".<init>() has more than one annotation ",
1246                 Named.class.getName(), SampleAnnotation.class.getName());
1247             return null;
1248           }
1249         }
1250     );
1251   }
1252 
1253   // Business logic tests
1254 
testModulesAreInstalledAtMostOnce()1255   public void testModulesAreInstalledAtMostOnce() {
1256     final AtomicInteger aConfigureCount = new AtomicInteger(0);
1257     final Module a = new AbstractModule() {
1258       public void configure() {
1259         aConfigureCount.incrementAndGet();
1260       }
1261     };
1262 
1263     Elements.getElements(a, a);
1264     assertEquals(1, aConfigureCount.get());
1265 
1266     aConfigureCount.set(0);
1267     Module b = new AbstractModule() {
1268       protected void configure() {
1269         install(a);
1270         install(a);
1271       }
1272     };
1273 
1274     Elements.getElements(b);
1275     assertEquals(1, aConfigureCount.get());
1276   }
1277 
1278   /**
1279    * Ensures the module performs the commands consistent with {@code visitors}.
1280    */
checkModule(Module module, ElementVisitor<?>... visitors)1281   protected void checkModule(Module module, ElementVisitor<?>... visitors) {
1282     List<Element> elements = Elements.getElements(module);
1283     assertEquals(elements.size(), visitors.length);
1284     checkElements(elements, visitors);
1285   }
1286 
checkElements(List<Element> elements, ElementVisitor<?>... visitors)1287   protected void checkElements(List<Element> elements, ElementVisitor<?>... visitors) {
1288     for (int i = 0; i < visitors.length; i++) {
1289       ElementVisitor<?> visitor = visitors[i];
1290       Element element = elements.get(i);
1291       if (!(element instanceof Message)) {
1292           ElementSource source = (ElementSource) element.getSource();
1293           assertFalse(source.getModuleClassNames().isEmpty());
1294           if (isIncludeStackTraceComplete()) {
1295             assertTrue(source.getStackTrace().length > 0);
1296           } else {
1297             assertEquals(0, source.getStackTrace().length);
1298           }
1299       }
1300       if (!(visitor instanceof ExternalFailureVisitor)) {
1301         assertContains(element.getSource().toString(), getDeclaringSourcePart(ElementsTest.class));
1302       }
1303       element.acceptVisitor(visitor);
1304     }
1305   }
1306 
1307   private static class ListProvider implements Provider<List> {
get()1308     public List get() {
1309       return new ArrayList();
1310     }
1311   }
1312 
1313   private static class TProvider<T> implements Provider<T> {
get()1314     public T get() {
1315       return null;
1316     }
1317   }
1318 
1319   /**
1320    * By extending this interface rather than FailingElementVisitor, the source of the error doesn't
1321    * need to contain the string {@code ElementsTest.java}.
1322    */
1323   abstract class ExternalFailureVisitor extends FailingElementVisitor {}
1324 
1325   @Retention(RUNTIME)
1326   @Target({ ElementType.FIELD, ElementType.PARAMETER, ElementType.METHOD })
1327   @BindingAnnotation
1328   public @interface SampleAnnotation { }
1329 
1330   public enum CoinSide { HEADS, TAILS }
1331 
1332   static class A<T> {
1333     @Inject Stage stage;
1334   }
1335 
1336   static class B<T> {
1337     @Inject Stage stage;
B(T t)1338     B(T t) {}
1339   }
1340 
1341   static class C {
1342     @Inject @Named("foo") @SampleAnnotation String a;
C(@amed"bar") @ampleAnnotation Integer b)1343     C(@Named("bar") @SampleAnnotation Integer b) {}
1344   }
1345 }
1346