• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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 package dagger.internal.codegen;
17 
18 import com.google.common.base.Joiner;
19 import com.google.common.collect.ImmutableList;
20 import com.google.common.collect.ImmutableSet;
21 import com.google.testing.compile.JavaFileObjects;
22 import java.io.IOException;
23 import java.io.Writer;
24 import java.util.Set;
25 import javax.annotation.processing.AbstractProcessor;
26 import javax.annotation.processing.RoundEnvironment;
27 import javax.lang.model.element.TypeElement;
28 import javax.tools.JavaFileObject;
29 import org.junit.Test;
30 import org.junit.runner.RunWith;
31 import org.junit.runners.JUnit4;
32 
33 import static com.google.common.truth.Truth.assertAbout;
34 import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource;
35 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources;
36 import static javax.tools.StandardLocation.CLASS_OUTPUT;
37 
38 @RunWith(JUnit4.class)
39 public class MembersInjectionTest {
40   @Test
parentClass_noInjectedMembers()41   public void parentClass_noInjectedMembers() {
42     JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
43         "package test;",
44         "",
45         "import javax.inject.Inject;",
46         "",
47         "public final class Child extends Parent {",
48         "  @Inject Child() {}",
49         "}");
50     JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
51         "package test;",
52         "",
53         "public abstract class Parent {}");
54 
55     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
56         "package test;",
57         "",
58         "import dagger.Component;",
59         "",
60         "",
61         "@Component",
62         "interface TestComponent {",
63         "  Child child();",
64         "}");
65     JavaFileObject generatedComponent = JavaFileObjects.forSourceLines(
66         "test.DaggerTestComponent",
67         "package test;",
68         "",
69         "import dagger.MembersInjector;",
70         "import dagger.internal.MembersInjectors;",
71         "import javax.annotation.Generated;",
72         "import javax.inject.Provider;",
73         "",
74         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
75         "public final class DaggerTestComponent implements TestComponent {",
76         "  private Provider<Child> childProvider;",
77         "",
78         "  private DaggerTestComponent(Builder builder) {",
79         "    assert builder != null;",
80         "    initialize(builder);",
81         "  }",
82         "",
83         "  public static Builder builder() {",
84         "    return new Builder();",
85         "  }",
86         "",
87         "  public static TestComponent create() {",
88         "    return builder().build();",
89         "  }",
90         "",
91         "  @SuppressWarnings(\"unchecked\")",
92         "  private void initialize(final Builder builder) {",
93         "    this.childProvider =",
94         "        Child_Factory.create((MembersInjector) MembersInjectors.noOp());",
95         "  }",
96         "",
97         "  @Override",
98         "  public Child child() {",
99         "    return childProvider.get();",
100         "  }",
101         "",
102         "  public static final class Builder {",
103         "    private Builder() {",
104         "    }",
105         "",
106         "    public TestComponent build() {",
107         "      return new DaggerTestComponent(this);",
108         "    }",
109         "  }",
110         "}");
111     assertAbout(javaSources())
112         .that(ImmutableList.of(childFile, parentFile, componentFile))
113         .processedWith(new ComponentProcessor())
114         .compilesWithoutError()
115         .and().generatesSources(generatedComponent);
116   }
117 
118   @Test
parentClass_injectedMembersInSupertype()119   public void parentClass_injectedMembersInSupertype() {
120     JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child",
121         "package test;",
122         "",
123         "import javax.inject.Inject;",
124         "",
125         "public final class Child extends Parent {",
126         "  @Inject Child() {}",
127         "}");
128     JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent",
129         "package test;",
130         "",
131         "import javax.inject.Inject;",
132         "",
133         "public abstract class Parent {",
134         "  @Inject Dep dep;",
135         "}");
136     JavaFileObject depFile = JavaFileObjects.forSourceLines("test.Dep",
137         "package test;",
138         "",
139         "import javax.inject.Inject;",
140         "",
141         "final class Dep {",
142         "  @Inject Dep() {}",
143         "}");
144     JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent",
145         "package test;",
146         "",
147         "import dagger.Component;",
148         "",
149         "",
150         "@Component",
151         "interface TestComponent {",
152         "  Child child();",
153         "}");
154     JavaFileObject generatedComponent =
155         JavaFileObjects.forSourceLines(
156             "test.DaggerTestComponent",
157             "package test;",
158             "",
159             "import dagger.MembersInjector;",
160             "import javax.annotation.Generated;",
161             "import javax.inject.Provider;",
162             "",
163             "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
164             "public final class DaggerTestComponent implements TestComponent {",
165             "  private MembersInjector<Child> childMembersInjector;",
166             "  private Provider<Child> childProvider;",
167             "",
168             "  private DaggerTestComponent(Builder builder) {",
169             "    assert builder != null;",
170             "    initialize(builder);",
171             "  }",
172             "",
173             "  public static Builder builder() {",
174             "    return new Builder();",
175             "  }",
176             "",
177             "  public static TestComponent create() {",
178             "    return builder().build();",
179             "  }",
180             "",
181             "  @SuppressWarnings(\"unchecked\")",
182             "  private void initialize(final Builder builder) {",
183             "    this.childMembersInjector = Child_MembersInjector.create(Dep_Factory.create());",
184             "    this.childProvider = Child_Factory.create(childMembersInjector);",
185             "  }",
186             "",
187             "  @Override",
188             "  public Child child() {",
189             "    return childProvider.get();",
190             "  }",
191             "",
192             "  public static final class Builder {",
193             "    private Builder() {}",
194             "",
195             "    public TestComponent build() {",
196             "      return new DaggerTestComponent(this);",
197             "    }",
198             "  }",
199             "}");
200     assertAbout(javaSources())
201         .that(ImmutableList.of(childFile, parentFile, depFile, componentFile))
202         .processedWith(new ComponentProcessor())
203         .compilesWithoutError()
204         .and()
205         .generatesSources(generatedComponent);
206   }
207 
fieldAndMethodGenerics()208   @Test public void fieldAndMethodGenerics() {
209     JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass",
210         "package test;",
211         "",
212         "import javax.inject.Inject;",
213         "",
214         "class GenericClass<A, B> {",
215         "  @Inject A a;",
216         "",
217         "  @Inject GenericClass() {}",
218         "",
219         " @Inject void register(B b) {}",
220         "}");
221     JavaFileObject expected = JavaFileObjects.forSourceLines(
222         "test.GenericClass_MembersInjector",
223         "package test;",
224         "",
225         "import dagger.MembersInjector;",
226         "import javax.annotation.Generated;",
227         "import javax.inject.Provider;",
228         "",
229         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
230         "public final class GenericClass_MembersInjector<A, B>",
231         "    implements MembersInjector<GenericClass<A, B>> {",
232         "  private final Provider<A> aProvider;",
233         "  private final Provider<B> bProvider;",
234         "",
235         "  public GenericClass_MembersInjector(Provider<A> aProvider, Provider<B> bProvider) {",
236         "    assert aProvider != null;",
237         "    this.aProvider = aProvider;",
238         "    assert bProvider != null;",
239         "    this.bProvider = bProvider;",
240         "  }",
241         "",
242         "  @Override",
243         "  public void injectMembers(GenericClass<A, B> instance) {",
244         "    if (instance == null) {",
245         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
246         "    }",
247         "    instance.a = aProvider.get();",
248         "    instance.register(bProvider.get());",
249         "  }",
250         "",
251         "  public static <A, B> MembersInjector<GenericClass<A, B>> create(",
252         "      Provider<A> aProvider, Provider<B> bProvider) {",
253         "    return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);",
254         "  }",
255         "",
256         "  public static <A, B> void injectA(GenericClass<A, B> instance, Provider<A> aProvider) {",
257         "    instance.a = aProvider.get();",
258         "  }",
259         "",
260         "  public static <A, B> void injectRegister(",
261         "      GenericClass<A, B> instance, Provider<B> bProvider) {",
262         "    instance.register(bProvider.get());",
263         "  }",
264         "",
265         "}");
266     assertAbout(javaSource())
267         .that(file)
268         .processedWith(new ComponentProcessor())
269         .compilesWithoutError()
270         .and()
271         .generatesSources(expected);
272   }
273 
subclassedGenericMembersInjectors()274   @Test public void subclassedGenericMembersInjectors() {
275     JavaFileObject a = JavaFileObjects.forSourceLines("test.A",
276         "package test;",
277         "",
278         "import javax.inject.Inject;",
279         "",
280         "final class A {",
281         "  @Inject A() {}",
282         "}");
283     JavaFileObject a2 = JavaFileObjects.forSourceLines("test.A2",
284         "package test;",
285         "",
286         "import javax.inject.Inject;",
287         "",
288         "final class A2 {",
289         "  @Inject A2() {}",
290         "}");
291     JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent",
292         "package test;",
293         "",
294         "import javax.inject.Inject;",
295         "",
296         "class Parent<X, Y> {",
297         "  @Inject X x;",
298         "  @Inject Y y;",
299         "  @Inject A2 a2;",
300         "",
301         "  @Inject Parent() {}",
302         "}");
303     JavaFileObject child = JavaFileObjects.forSourceLines("test.Child",
304         "package test;",
305         "",
306         "import javax.inject.Inject;",
307         "",
308         "class Child<T> extends Parent<T, A> {",
309         "  @Inject A a;",
310         "  @Inject T t;",
311         "",
312         "  @Inject Child() {}",
313         "}");
314     JavaFileObject expected = JavaFileObjects.forSourceLines(
315         "test.Child_MembersInjector",
316         "package test;",
317         "",
318         "import dagger.MembersInjector;",
319         "import javax.annotation.Generated;",
320         "import javax.inject.Provider;",
321         "",
322         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
323         "public final class Child_MembersInjector<T>",
324         "    implements MembersInjector<Child<T>> {",
325         "  private final Provider<T> tAndXProvider;",
326         "  private final Provider<A> aAndYProvider;",
327         "  private final Provider<A2> a2Provider;",
328         "",
329         "  public Child_MembersInjector(",
330         "      Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
331         "    assert tAndXProvider != null;",
332         "    this.tAndXProvider = tAndXProvider;",
333         "    assert aAndYProvider != null;",
334         "    this.aAndYProvider = aAndYProvider;",
335         "    assert a2Provider != null;",
336         "    this.a2Provider = a2Provider;",
337         "  }",
338         "",
339         "  @Override",
340         "  public void injectMembers(Child<T> instance) {",
341         "    if (instance == null) {",
342         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
343         "    }",
344         "    ((test.Parent) instance).x = tAndXProvider.get();",
345         "    ((test.Parent) instance).y = aAndYProvider.get();",
346         "    ((test.Parent) instance).a2 = a2Provider.get();",
347         "    instance.a = aAndYProvider.get();",
348         "    instance.t = tAndXProvider.get();",
349         "  }",
350         "",
351         "  public static <T> MembersInjector<Child<T>> create(",
352         "      Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {",
353         "    return new Child_MembersInjector<T>(tAndXProvider, aAndYProvider, a2Provider);",
354         "  }",
355         "",
356         "  public static <T> void injectA(Child<T> instance, Provider<A> aProvider) {",
357         "    instance.a = aProvider.get();",
358         "  }",
359         "",
360         "  public static <T> void injectT(Child<T> instance, Provider<T> tProvider) {",
361         "    instance.t = tProvider.get();",
362         "  }",
363         "}");
364     assertAbout(javaSources())
365         .that(ImmutableList.of(a, a2, parent, child))
366         .processedWith(new ComponentProcessor())
367         .compilesWithoutError()
368         .and()
369         .generatesSources(expected);
370   }
371 
fieldInjection()372   @Test public void fieldInjection() {
373     JavaFileObject file = JavaFileObjects.forSourceLines("test.FieldInjection",
374         "package test;",
375         "",
376         "import dagger.Lazy;",
377         "import javax.inject.Inject;",
378         "import javax.inject.Provider;",
379         "",
380         "class FieldInjection {",
381         "  @Inject String string;",
382         "  @Inject Lazy<String> lazyString;",
383         "  @Inject Provider<String> stringProvider;",
384         "}");
385     JavaFileObject expected = JavaFileObjects.forSourceLines(
386         "test.FieldInjection_MembersInjector",
387         "package test;",
388         "",
389         "import dagger.MembersInjector;",
390         "import dagger.internal.DoubleCheckLazy;",
391         "import javax.annotation.Generated;",
392         "import javax.inject.Provider;",
393         "",
394         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
395         "public final class FieldInjection_MembersInjector",
396         "    implements MembersInjector<FieldInjection> {",
397         "  private final Provider<String> stringProvider;",
398         "",
399         "  public FieldInjection_MembersInjector(Provider<String> stringProvider) {",
400         "    assert stringProvider != null;",
401         "    this.stringProvider = stringProvider;",
402         "  }",
403         "",
404         "  @Override",
405         "  public void injectMembers(FieldInjection instance) {",
406         "    if (instance == null) {",
407         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
408         "    }",
409         "    instance.string = stringProvider.get();",
410         "    instance.lazyString = DoubleCheckLazy.create(stringProvider);",
411         "    instance.stringProvider = stringProvider;",
412         "  }",
413         "",
414         "  public static MembersInjector<FieldInjection> create(Provider<String> stringProvider) {",
415         "    return new FieldInjection_MembersInjector(stringProvider);",
416         "  }",
417         "",
418         "  public static void injectString(",
419         "      FieldInjection instance, Provider<String> stringProvider) {",
420         "    instance.string = stringProvider.get();",
421         "  }",
422         "",
423         "  public static void injectLazyString(",
424         "      FieldInjection instance, Provider<String> lazyStringProvider) {",
425         "    instance.lazyString = DoubleCheckLazy.create(lazyStringProvider);",
426         "  }",
427         "",
428         "  public static void injectStringProvider(",
429         "      FieldInjection instance, Provider<String> stringProvider) {",
430         "    instance.stringProvider = stringProvider;",
431         "  }",
432         "}");
433     assertAbout(javaSource())
434         .that(file)
435         .processedWith(new ComponentProcessor())
436         .compilesWithoutError()
437         .and()
438         .generatesSources(expected);
439   }
440 
methodInjection()441   @Test public void methodInjection() {
442     JavaFileObject file = JavaFileObjects.forSourceLines("test.MethodInjection",
443         "package test;",
444         "",
445         "import dagger.Lazy;",
446         "import javax.inject.Inject;",
447         "import javax.inject.Provider;",
448         "",
449         "class MethodInjection {",
450         "  @Inject void noArgs() {}",
451         "  @Inject void oneArg(String string) {}",
452         "  @Inject void manyArgs(",
453         "      String string, Lazy<String> lazyString, Provider<String> stringProvider) {}",
454         "}");
455     JavaFileObject expected = JavaFileObjects.forSourceLines(
456         "test.MethodInjection_MembersInjector",
457         "package test;",
458         "",
459         "import dagger.MembersInjector;",
460         "import dagger.internal.DoubleCheckLazy;",
461         "import javax.annotation.Generated;",
462         "import javax.inject.Provider;",
463         "",
464         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
465         "public final class MethodInjection_MembersInjector",
466         "     implements MembersInjector<MethodInjection> {",
467         "",
468         "  private final Provider<String> stringProvider;",
469         "",
470         "  public MethodInjection_MembersInjector(Provider<String> stringProvider) {",
471         "    assert stringProvider != null;",
472         "    this.stringProvider = stringProvider;",
473         "  }",
474         "",
475         "  @Override",
476         "  public void injectMembers(MethodInjection instance) {",
477         "    if (instance == null) {",
478         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
479         "    }",
480         "    instance.noArgs();",
481         "    instance.oneArg(stringProvider.get());",
482         "    instance.manyArgs(stringProvider.get(), DoubleCheckLazy.create(stringProvider),",
483         "        stringProvider);",
484         "  }",
485         "",
486         "  public static MembersInjector<MethodInjection> create(",
487         "      Provider<String> stringProvider) {",
488         "    return new MethodInjection_MembersInjector(stringProvider);",
489         "  }",
490         "",
491         "  public static void injectNoArgs(MethodInjection instance) {",
492         "    instance.noArgs();",
493         "  }",
494         "",
495         "  public static void injectOneArg(",
496         "      MethodInjection instance, Provider<String> stringProvider) {",
497         "    instance.oneArg(stringProvider.get());",
498         "  }",
499         "",
500         "  public static void injectManyArgs(",
501         "      MethodInjection instance,",
502         "      Provider<String> stringProvider,",
503         "      Provider<String> lazyStringProvider,",
504         "      Provider<String> stringProvider2) {",
505         "    instance.manyArgs(",
506         "        stringProvider.get(),",
507         "        DoubleCheckLazy.create(lazyStringProvider),",
508         "        stringProvider2);",
509         "  }",
510         "}");
511     assertAbout(javaSource())
512         .that(file)
513         .processedWith(new ComponentProcessor())
514         .compilesWithoutError()
515         .and()
516         .generatesSources(expected);
517   }
518 
519   @Test
mixedMemberInjection()520   public void mixedMemberInjection() {
521     JavaFileObject file = JavaFileObjects.forSourceLines(
522         "test.MixedMemberInjection",
523         "package test;",
524         "",
525         "import dagger.Lazy;",
526         "import javax.inject.Inject;",
527         "import javax.inject.Provider;",
528         "",
529         "class MixedMemberInjection {",
530         "  @Inject String string;",
531         "  @Inject void setString(String s) {}",
532         "  @Inject Object object;",
533         "  @Inject void setObject(Object o) {}",
534         "}");
535     JavaFileObject expected = JavaFileObjects.forSourceLines(
536         "test.MixedMemberInjection_MembersInjector",
537         "package test;",
538         "",
539         "import dagger.MembersInjector;",
540         "import javax.annotation.Generated;",
541         "import javax.inject.Provider;",
542         "",
543         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
544         "public final class MixedMemberInjection_MembersInjector",
545         "    implements MembersInjector<MixedMemberInjection> {",
546         "",
547         "  private final Provider<String> stringAndSProvider;",
548         "  private final Provider<Object> objectAndOProvider;",
549         "",
550         "  public MixedMemberInjection_MembersInjector(",
551         "      Provider<String> stringAndSProvider,",
552         "      Provider<Object> objectAndOProvider) {",
553         "    assert stringAndSProvider != null;",
554         "    this.stringAndSProvider = stringAndSProvider;",
555         "    assert objectAndOProvider != null;",
556         "    this.objectAndOProvider = objectAndOProvider;",
557         "  }",
558         "",
559         "  @Override",
560         "  public void injectMembers(MixedMemberInjection instance) {",
561         "    if (instance == null) {",
562         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
563         "    }",
564         "    instance.string = stringAndSProvider.get();",
565         "    instance.object = objectAndOProvider.get();",
566         "    instance.setString(stringAndSProvider.get());",
567         "    instance.setObject(objectAndOProvider.get());",
568         "  }",
569         "",
570         "  public static MembersInjector<MixedMemberInjection> create(",
571         "      Provider<String> stringAndSProvider,",
572         "      Provider<Object> objectAndOProvider) {",
573         "    return new MixedMemberInjection_MembersInjector(",
574         "        stringAndSProvider, objectAndOProvider);",
575         "  }",
576         "  public static void injectString(",
577         "      MixedMemberInjection instance, Provider<String> stringProvider) {",
578         "    instance.string = stringProvider.get();",
579         "  }",
580         "",
581         "  public static void injectObject(",
582         "      MixedMemberInjection instance, Provider<Object> objectProvider) {",
583         "    instance.object = objectProvider.get();",
584         "  }",
585         "",
586         "  public static void injectSetString(",
587         "      MixedMemberInjection instance, Provider<String> sProvider) {",
588         "    instance.setString(sProvider.get());",
589         "  }",
590         "",
591         "  public static void injectSetObject(",
592         "      MixedMemberInjection instance, Provider<Object> oProvider) {",
593         "    instance.setObject(oProvider.get());",
594         "  }",
595         "}");
596     assertAbout(javaSource())
597         .that(file)
598         .processedWith(new ComponentProcessor())
599         .compilesWithoutError()
600         .and()
601         .generatesSources(expected);
602   }
603 
injectConstructorAndMembersInjection()604   @Test public void injectConstructorAndMembersInjection() {
605     JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections",
606         "package test;",
607         "",
608         "import javax.inject.Inject;",
609         "",
610         "class AllInjections {",
611         "  @Inject String s;",
612         "  @Inject AllInjections(String s) {}",
613         "  @Inject void s(String s) {}",
614         "}");
615     JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
616         "test.AllInjections_MembersInjector",
617         "package test;",
618         "",
619         "import dagger.MembersInjector;",
620         "import javax.annotation.Generated;",
621         "import javax.inject.Provider;",
622         "",
623         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
624         "public final class AllInjections_MembersInjector ",
625         "    implements MembersInjector<AllInjections> {",
626         "",
627         "  private final Provider<String> sProvider;",
628         "",
629         "  public AllInjections_MembersInjector(Provider<String> sProvider) {",
630         "    assert sProvider != null;",
631         "    this.sProvider = sProvider;",
632         "  }",
633         "",
634         "  @Override",
635         "  public void injectMembers(AllInjections instance) {",
636         "    if (instance == null) {",
637         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
638         "    }",
639         "    instance.s = sProvider.get();",
640         "    instance.s(sProvider.get());",
641         "  }",
642         "",
643         "  public static MembersInjector<AllInjections> create(Provider<String> sProvider) {",
644         "      return new AllInjections_MembersInjector(sProvider);",
645         "  }",
646         "",
647         "  public static void injectS(AllInjections instance, Provider<String> sProvider) {",
648         "    instance.s = sProvider.get();",
649         "  }",
650         "}");
651     assertAbout(javaSource())
652         .that(file)
653         .processedWith(new ComponentProcessor())
654         .compilesWithoutError()
655         .and()
656         .generatesSources(expectedMembersInjector);
657   }
658 
supertypeMembersInjection()659   @Test public void supertypeMembersInjection() {
660     JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A",
661         "package test;",
662         "",
663         "class A {}");
664     JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B",
665         "package test;",
666         "",
667         "import javax.inject.Inject;",
668         "",
669         "class B extends A {",
670         "  @Inject String s;",
671         "}");
672     JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines(
673         "test.AllInjections_MembersInjector",
674         "package test;",
675         "",
676         "import dagger.MembersInjector;",
677         "import javax.annotation.Generated;",
678         "import javax.inject.Provider;",
679         "",
680         "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
681         "public final class B_MembersInjector implements MembersInjector<B> {",
682         "  private final Provider<String> sProvider;",
683         "",
684         "  public B_MembersInjector(Provider<String> sProvider) {",
685         "    assert sProvider != null;",
686         "    this.sProvider = sProvider;",
687         "  }",
688         "",
689         "  @Override",
690         "  public void injectMembers(B instance) {",
691         "    if (instance == null) {",
692         "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
693         "    }",
694         "    instance.s = sProvider.get();",
695         "  }",
696         "",
697         "  public static MembersInjector<B> create(Provider<String> sProvider) {",
698         "      return new B_MembersInjector(sProvider);",
699         "  }",
700         "  public static void injectS(B instance, Provider<String> sProvider) {",
701         "    instance.s = sProvider.get();",
702         "  }",
703         "}");
704     assertAbout(javaSources())
705         .that(ImmutableList.of(aFile, bFile))
706         .processedWith(new ComponentProcessor())
707         .compilesWithoutError()
708         .and()
709         .generatesSources(expectedMembersInjector);
710   }
711 
712   @Test
simpleComponentWithNesting()713   public void simpleComponentWithNesting() {
714     JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines(
715           "test.OuterType",
716           "package test;",
717           "",
718           "import dagger.Component;",
719           "import javax.inject.Inject;",
720           "",
721           "final class OuterType {",
722           "  static class A {",
723           "    @Inject A() {}",
724           "  }",
725           "  static class B {",
726           "    @Inject A a;",
727           "  }",
728           "  @Component interface SimpleComponent {",
729           "    A a();",
730           "    void inject(B b);",
731           "  }",
732           "}");
733     JavaFileObject bMembersInjector = JavaFileObjects.forSourceLines(
734           "test.OuterType$B_MembersInjector",
735           "package test;",
736           "",
737           "import dagger.MembersInjector;",
738           "import javax.annotation.Generated;",
739           "import javax.inject.Provider;",
740           "import test.OuterType.A;",
741           "import test.OuterType.B;",
742           "",
743           "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
744           "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
745           "  private final Provider<A> aProvider;",
746           "",
747           "  public OuterType$B_MembersInjector(Provider<A> aProvider) {",
748           "    assert aProvider != null;",
749           "    this.aProvider = aProvider;",
750           "  }",
751           "",
752           "  @Override",
753           "  public void injectMembers(B instance) {",
754           "    if (instance == null) {",
755           "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
756           "    }",
757           "    instance.a = aProvider.get();",
758           "  }",
759           "",
760           "  public static MembersInjector<B> create(Provider<A> aProvider) {",
761           "    return new OuterType$B_MembersInjector(aProvider);",
762           "  }",
763           "",
764           "  public static void injectA(B instance, Provider<A> aProvider) {",
765           "    instance.a = aProvider.get();",
766           "  }",
767           "}");
768     assertAbout(javaSources())
769         .that(ImmutableList.of(nestedTypesFile))
770         .processedWith(new ComponentProcessor())
771         .compilesWithoutError()
772         .and()
773         .generatesSources(bMembersInjector);
774   }
775 
776   @Test
componentWithNestingAndGeneratedType()777   public void componentWithNestingAndGeneratedType() {
778     JavaFileObject nestedTypesFile =
779         JavaFileObjects.forSourceLines(
780             "test.OuterType",
781             "package test;",
782             "",
783             "import dagger.Component;",
784             "import javax.inject.Inject;",
785             "",
786             "final class OuterType {",
787             "  @Inject GeneratedType generated;",
788             "  static class A {",
789             "    @Inject A() {}",
790             "  }",
791             "  static class B {",
792             "    @Inject A a;",
793             "  }",
794             "  @Component interface SimpleComponent {",
795             "    A a();",
796             "    void inject(B b);",
797             "  }",
798             "}");
799     JavaFileObject bMembersInjector =
800         JavaFileObjects.forSourceLines(
801             "test.OuterType$B_MembersInjector",
802             "package test;",
803             "",
804             "import dagger.MembersInjector;",
805             "import javax.annotation.Generated;",
806             "import javax.inject.Provider;",
807             "import test.OuterType.A;",
808             "import test.OuterType.B;",
809             "",
810             "@Generated(\"dagger.internal.codegen.ComponentProcessor\")",
811             "public final class OuterType$B_MembersInjector implements MembersInjector<B> {",
812             "  private final Provider<A> aProvider;",
813             "",
814             "  public OuterType$B_MembersInjector(Provider<A> aProvider) {",
815             "    assert aProvider != null;",
816             "    this.aProvider = aProvider;",
817             "  }",
818             "",
819             "  @Override",
820             "  public void injectMembers(B instance) {",
821             "    if (instance == null) {",
822             "      throw new NullPointerException(\"Cannot inject members into a null reference\");",
823             "    }",
824             "    instance.a = aProvider.get();",
825             "  }",
826             "",
827             "  public static MembersInjector<B> create(Provider<A> aProvider) {",
828             "    return new OuterType$B_MembersInjector(aProvider);",
829             "  }",
830             "",
831             "  public static void injectA(B instance, Provider<A> aProvider) {",
832             "    instance.a = aProvider.get();",
833             "  }",
834             "}");
835     assertAbout(javaSource())
836         .that(nestedTypesFile)
837         .processedWith(
838             new ComponentProcessor(),
839             new AbstractProcessor() {
840               private boolean done;
841 
842               @Override
843               public Set<String> getSupportedAnnotationTypes() {
844                 return ImmutableSet.of("*");
845               }
846 
847               @Override
848               public boolean process(
849                   Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
850                 if (!done) {
851                   done = true;
852                   try (Writer writer =
853                           processingEnv
854                               .getFiler()
855                               .createSourceFile("test.GeneratedType")
856                               .openWriter()) {
857                     writer.write(
858                         Joiner.on('\n')
859                             .join(
860                                 "package test;",
861                                 "",
862                                 "import javax.inject.Inject;",
863                                 "",
864                                 "class GeneratedType {",
865                                 "  @Inject GeneratedType() {}",
866                                 "}"));
867                   } catch (IOException e) {
868                     throw new RuntimeException(e);
869                   }
870                 }
871                 return false;
872               }
873             })
874         .compilesWithoutError()
875         .and()
876         .generatesSources(bMembersInjector);
877   }
878 
879   @Test
lowerCaseNamedMembersInjector_forLowerCaseType()880   public void lowerCaseNamedMembersInjector_forLowerCaseType() {
881     JavaFileObject foo =
882         JavaFileObjects.forSourceLines(
883             "test.foo",
884             "package test;",
885             "",
886             "import javax.inject.Inject;",
887             "",
888             "class foo {",
889             "  @Inject String string;",
890             "}");
891     JavaFileObject fooModule =
892         JavaFileObjects.forSourceLines(
893             "test.fooModule",
894             "package test;",
895             "",
896             "import dagger.Module;",
897             "import dagger.Provides;",
898             "",
899             "@Module",
900             "class fooModule {",
901             "  @Provides String string() { return \"foo\"; }",
902             "}");
903     JavaFileObject fooComponent =
904         JavaFileObjects.forSourceLines(
905             "test.fooComponent",
906             "package test;",
907             "",
908             "import dagger.Component;",
909             "",
910             "@Component(modules = fooModule.class)",
911             "interface fooComponent {",
912             "  void inject(foo target);",
913             "}");
914 
915     assertAbout(javaSources())
916         .that(ImmutableList.of(foo, fooModule, fooComponent))
917         .processedWith(new ComponentProcessor())
918         .compilesWithoutError()
919         .and().generatesFileNamed(CLASS_OUTPUT, "test", "foo_MembersInjector.class");
920   }
921 }
922