1 /* 2 * Copyright (C) 2015 The Dagger Authors. 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 dagger.internal.codegen; 18 19 import static com.google.common.truth.Truth.assertAbout; 20 import static com.google.testing.compile.CompilationSubject.assertThat; 21 import static com.google.testing.compile.JavaSourceSubjectFactory.javaSource; 22 import static com.google.testing.compile.JavaSourcesSubjectFactory.javaSources; 23 import static dagger.internal.codegen.CompilerMode.DEFAULT_MODE; 24 import static dagger.internal.codegen.CompilerMode.FAST_INIT_MODE; 25 import static dagger.internal.codegen.Compilers.daggerCompiler; 26 import static dagger.internal.codegen.GeneratedLines.GENERATED_ANNOTATION; 27 import static dagger.internal.codegen.GeneratedLines.IMPORT_GENERATED_ANNOTATION; 28 import static javax.tools.StandardLocation.CLASS_OUTPUT; 29 30 import com.google.common.base.Joiner; 31 import com.google.common.collect.ImmutableList; 32 import com.google.common.collect.ImmutableSet; 33 import com.google.testing.compile.Compilation; 34 import com.google.testing.compile.JavaFileObjects; 35 import java.io.IOException; 36 import java.io.Writer; 37 import java.util.Collection; 38 import java.util.Set; 39 import javax.annotation.processing.AbstractProcessor; 40 import javax.annotation.processing.RoundEnvironment; 41 import javax.lang.model.element.TypeElement; 42 import javax.tools.JavaFileObject; 43 import org.junit.Test; 44 import org.junit.runner.RunWith; 45 import org.junit.runners.Parameterized; 46 import org.junit.runners.Parameterized.Parameters; 47 48 @RunWith(Parameterized.class) 49 public class MembersInjectionTest { 50 @Parameters(name = "{0}") parameters()51 public static Collection<Object[]> parameters() { 52 return CompilerMode.TEST_PARAMETERS; 53 } 54 55 private final CompilerMode compilerMode; 56 MembersInjectionTest(CompilerMode compilerMode)57 public MembersInjectionTest(CompilerMode compilerMode) { 58 this.compilerMode = compilerMode; 59 } 60 61 @Test parentClass_noInjectedMembers()62 public void parentClass_noInjectedMembers() { 63 JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child", 64 "package test;", 65 "", 66 "import javax.inject.Inject;", 67 "", 68 "public final class Child extends Parent {", 69 " @Inject Child() {}", 70 "}"); 71 JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent", 72 "package test;", 73 "", 74 "public abstract class Parent {}"); 75 76 JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent", 77 "package test;", 78 "", 79 "import dagger.Component;", 80 "", 81 "@Component", 82 "interface TestComponent {", 83 " Child child();", 84 "}"); 85 JavaFileObject generatedComponent = 86 JavaFileObjects.forSourceLines( 87 "test.DaggerTestComponent", 88 "package test;", 89 "", 90 GENERATED_ANNOTATION, 91 "final class DaggerTestComponent implements TestComponent {", 92 " @Override", 93 " public Child child() {", 94 " return new Child();", 95 " }", 96 "}"); 97 Compilation compilation = 98 daggerCompiler() 99 .withOptions(compilerMode.javacopts()) 100 .compile(childFile, parentFile, componentFile); 101 102 assertThat(compilation).succeeded(); 103 assertThat(compilation) 104 .generatedSourceFile("test.DaggerTestComponent") 105 .containsElementsIn(generatedComponent); 106 } 107 108 @Test parentClass_injectedMembersInSupertype()109 public void parentClass_injectedMembersInSupertype() { 110 JavaFileObject childFile = JavaFileObjects.forSourceLines("test.Child", 111 "package test;", 112 "", 113 "import javax.inject.Inject;", 114 "", 115 "public final class Child extends Parent {", 116 " @Inject Child() {}", 117 "}"); 118 JavaFileObject parentFile = JavaFileObjects.forSourceLines("test.Parent", 119 "package test;", 120 "", 121 "import javax.inject.Inject;", 122 "", 123 "public abstract class Parent {", 124 " @Inject Dep dep;", 125 "}"); 126 JavaFileObject depFile = JavaFileObjects.forSourceLines("test.Dep", 127 "package test;", 128 "", 129 "import javax.inject.Inject;", 130 "", 131 "final class Dep {", 132 " @Inject Dep() {}", 133 "}"); 134 JavaFileObject componentFile = JavaFileObjects.forSourceLines("test.TestComponent", 135 "package test;", 136 "", 137 "import dagger.Component;", 138 "", 139 "@Component", 140 "interface TestComponent {", 141 " Child child();", 142 "}"); 143 JavaFileObject generatedComponent = 144 JavaFileObjects.forSourceLines( 145 "test.DaggerTestComponent", 146 "package test;", 147 "", 148 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 149 "", 150 GENERATED_ANNOTATION, 151 "final class DaggerTestComponent implements TestComponent {", 152 " @Override", 153 " public Child child() {", 154 " return injectChild(Child_Factory.newInstance());", 155 " }", 156 "", 157 " @CanIgnoreReturnValue", 158 " private Child injectChild(Child instance) {", 159 " Parent_MembersInjector.injectDep(instance, new Dep());", 160 " return instance;", 161 " }", 162 "}"); 163 Compilation compilation = 164 daggerCompiler() 165 .withOptions(compilerMode.javacopts()) 166 .compile(childFile, parentFile, depFile, componentFile); 167 168 assertThat(compilation).succeeded(); 169 assertThat(compilation) 170 .generatedSourceFile("test.DaggerTestComponent") 171 .containsElementsIn(generatedComponent); 172 } 173 fieldAndMethodGenerics()174 @Test public void fieldAndMethodGenerics() { 175 JavaFileObject file = JavaFileObjects.forSourceLines("test.GenericClass", 176 "package test;", 177 "", 178 "import javax.inject.Inject;", 179 "", 180 "class GenericClass<A, B> {", 181 " @Inject A a;", 182 "", 183 " @Inject GenericClass() {}", 184 "", 185 " @Inject void register(B b) {}", 186 "}"); 187 JavaFileObject expected = JavaFileObjects.forSourceLines( 188 "test.GenericClass_MembersInjector", 189 "package test;", 190 "", 191 "import dagger.MembersInjector;", 192 IMPORT_GENERATED_ANNOTATION, 193 "import javax.inject.Provider;", 194 "", 195 GENERATED_ANNOTATION, 196 "public final class GenericClass_MembersInjector<A, B>", 197 " implements MembersInjector<GenericClass<A, B>> {", 198 " private final Provider<A> aProvider;", 199 " private final Provider<B> bProvider;", 200 "", 201 " public GenericClass_MembersInjector(Provider<A> aProvider, Provider<B> bProvider) {", 202 " this.aProvider = aProvider;", 203 " this.bProvider = bProvider;", 204 " }", 205 "", 206 " public static <A, B> MembersInjector<GenericClass<A, B>> create(", 207 " Provider<A> aProvider, Provider<B> bProvider) {", 208 " return new GenericClass_MembersInjector<A, B>(aProvider, bProvider);", 209 " }", 210 "", 211 " @Override", 212 " public void injectMembers(GenericClass<A, B> instance) {", 213 " injectA(instance, aProvider.get());", 214 " injectRegister(instance, bProvider.get());", 215 " }", 216 "", 217 " public static <A, B> void injectA(Object instance, A a) {", 218 " ((GenericClass<A, B>) instance).a = a;", 219 " }", 220 "", 221 " public static <A, B> void injectRegister(Object instance, B b) {", 222 " ((GenericClass<A, B>) instance).register(b);", 223 " }", 224 "}"); 225 assertAbout(javaSource()) 226 .that(file) 227 .withCompilerOptions(compilerMode.javacopts()) 228 .processedWith(new ComponentProcessor()) 229 .compilesWithoutError() 230 .and() 231 .generatesSources(expected); 232 } 233 subclassedGenericMembersInjectors()234 @Test public void subclassedGenericMembersInjectors() { 235 JavaFileObject a = JavaFileObjects.forSourceLines("test.A", 236 "package test;", 237 "", 238 "import javax.inject.Inject;", 239 "", 240 "final class A {", 241 " @Inject A() {}", 242 "}"); 243 JavaFileObject a2 = JavaFileObjects.forSourceLines("test.A2", 244 "package test;", 245 "", 246 "import javax.inject.Inject;", 247 "", 248 "final class A2 {", 249 " @Inject A2() {}", 250 "}"); 251 JavaFileObject parent = JavaFileObjects.forSourceLines("test.Parent", 252 "package test;", 253 "", 254 "import javax.inject.Inject;", 255 "", 256 "class Parent<X, Y> {", 257 " @Inject X x;", 258 " @Inject Y y;", 259 " @Inject A2 a2;", 260 "", 261 " @Inject Parent() {}", 262 "}"); 263 JavaFileObject child = JavaFileObjects.forSourceLines("test.Child", 264 "package test;", 265 "", 266 "import javax.inject.Inject;", 267 "", 268 "class Child<T> extends Parent<T, A> {", 269 " @Inject A a;", 270 " @Inject T t;", 271 "", 272 " @Inject Child() {}", 273 "}"); 274 JavaFileObject expected = JavaFileObjects.forSourceLines( 275 "test.Child_MembersInjector", 276 "package test;", 277 "", 278 "import dagger.MembersInjector;", 279 IMPORT_GENERATED_ANNOTATION, 280 "import javax.inject.Provider;", 281 "", 282 GENERATED_ANNOTATION, 283 "public final class Child_MembersInjector<T>", 284 " implements MembersInjector<Child<T>> {", 285 " private final Provider<T> tAndXProvider;", 286 " private final Provider<A> aAndYProvider;", 287 " private final Provider<A2> a2Provider;", 288 "", 289 " public Child_MembersInjector(", 290 " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {", 291 " this.tAndXProvider = tAndXProvider;", 292 " this.aAndYProvider = aAndYProvider;", 293 " this.a2Provider = a2Provider;", 294 " }", 295 "", 296 " public static <T> MembersInjector<Child<T>> create(", 297 " Provider<T> tAndXProvider, Provider<A> aAndYProvider, Provider<A2> a2Provider) {", 298 " return new Child_MembersInjector<T>(tAndXProvider, aAndYProvider, a2Provider);", 299 " }", 300 "", 301 " @Override", 302 " public void injectMembers(Child<T> instance) {", 303 " Parent_MembersInjector.injectX(instance, tAndXProvider.get());", 304 " Parent_MembersInjector.injectY(instance, aAndYProvider.get());", 305 " Parent_MembersInjector.injectA2(instance, a2Provider.get());", 306 " injectA(instance, aAndYProvider.get());", 307 " injectT(instance, tAndXProvider.get());", 308 " }", 309 "", 310 " public static <T> void injectA(Object instance, Object a) {", 311 " ((Child<T>) instance).a = (A) a;", 312 " }", 313 "", 314 " public static <T> void injectT(Object instance, T t) {", 315 " ((Child<T>) instance).t = t;", 316 " }", 317 "}"); 318 assertAbout(javaSources()) 319 .that(ImmutableList.of(a, a2, parent, child)) 320 .withCompilerOptions(compilerMode.javacopts()) 321 .processedWith(new ComponentProcessor()) 322 .compilesWithoutError() 323 .and() 324 .generatesSources(expected); 325 } 326 fieldInjection()327 @Test public void fieldInjection() { 328 JavaFileObject file = JavaFileObjects.forSourceLines("test.FieldInjection", 329 "package test;", 330 "", 331 "import dagger.Lazy;", 332 "import javax.inject.Inject;", 333 "import javax.inject.Provider;", 334 "", 335 "class FieldInjection {", 336 " @Inject String string;", 337 " @Inject Lazy<String> lazyString;", 338 " @Inject Provider<String> stringProvider;", 339 "}"); 340 JavaFileObject expected = 341 JavaFileObjects.forSourceLines( 342 "test.FieldInjection_MembersInjector", 343 "package test;", 344 "", 345 "import dagger.Lazy;", 346 "import dagger.MembersInjector;", 347 "import dagger.internal.DoubleCheck;", 348 IMPORT_GENERATED_ANNOTATION, 349 "import javax.inject.Provider;", 350 "", 351 GENERATED_ANNOTATION, 352 "public final class FieldInjection_MembersInjector", 353 " implements MembersInjector<FieldInjection> {", 354 " private final Provider<String> stringProvider;", 355 "", 356 " public FieldInjection_MembersInjector(Provider<String> stringProvider) {", 357 " this.stringProvider = stringProvider;", 358 " }", 359 "", 360 " public static MembersInjector<FieldInjection> create(", 361 " Provider<String> stringProvider) {", 362 " return new FieldInjection_MembersInjector(stringProvider);", 363 " }", 364 "", 365 " @Override", 366 " public void injectMembers(FieldInjection instance) {", 367 " injectString(instance, stringProvider.get());", 368 " injectLazyString(instance, DoubleCheck.lazy(stringProvider));", 369 " injectStringProvider(instance, stringProvider);", 370 " }", 371 "", 372 " public static void injectString(Object instance, String string) {", 373 " ((FieldInjection) instance).string = string;", 374 " }", 375 "", 376 " public static void injectLazyString(Object instance, Lazy<String> lazyString) {", 377 " ((FieldInjection) instance).lazyString = lazyString;", 378 " }", 379 "", 380 " public static void injectStringProvider(", 381 " Object instance, Provider<String> stringProvider) {", 382 " ((FieldInjection) instance).stringProvider = stringProvider;", 383 " }", 384 "}"); 385 assertAbout(javaSource()) 386 .that(file) 387 .withCompilerOptions(compilerMode.javacopts()) 388 .processedWith(new ComponentProcessor()) 389 .compilesWithoutError() 390 .and() 391 .generatesSources(expected); 392 } 393 methodInjection()394 @Test public void methodInjection() { 395 JavaFileObject file = JavaFileObjects.forSourceLines("test.MethodInjection", 396 "package test;", 397 "", 398 "import dagger.Lazy;", 399 "import javax.inject.Inject;", 400 "import javax.inject.Provider;", 401 "", 402 "class MethodInjection {", 403 " @Inject void noArgs() {}", 404 " @Inject void oneArg(String string) {}", 405 " @Inject void manyArgs(", 406 " String string, Lazy<String> lazyString, Provider<String> stringProvider) {}", 407 "}"); 408 JavaFileObject expected = 409 JavaFileObjects.forSourceLines( 410 "test.MethodInjection_MembersInjector", 411 "package test;", 412 "", 413 "import dagger.Lazy;", 414 "import dagger.MembersInjector;", 415 "import dagger.internal.DoubleCheck;", 416 IMPORT_GENERATED_ANNOTATION, 417 "import javax.inject.Provider;", 418 "", 419 GENERATED_ANNOTATION, 420 "public final class MethodInjection_MembersInjector", 421 " implements MembersInjector<MethodInjection> {", 422 "", 423 " private final Provider<String> stringProvider;", 424 "", 425 " public MethodInjection_MembersInjector(Provider<String> stringProvider) {", 426 " this.stringProvider = stringProvider;", 427 " }", 428 "", 429 " public static MembersInjector<MethodInjection> create(", 430 " Provider<String> stringProvider) {", 431 " return new MethodInjection_MembersInjector(stringProvider);", 432 " }", 433 "", 434 " @Override", 435 " public void injectMembers(MethodInjection instance) {", 436 " injectNoArgs(instance);", 437 " injectOneArg(instance, stringProvider.get());", 438 " injectManyArgs(", 439 " instance,", 440 " stringProvider.get(),", 441 " DoubleCheck.lazy(stringProvider),", 442 " stringProvider);", 443 " }", 444 "", 445 " public static void injectNoArgs(Object instance) {", 446 " ((MethodInjection) instance).noArgs();", 447 " }", 448 "", 449 " public static void injectOneArg(Object instance, String string) {", 450 " ((MethodInjection) instance).oneArg(string);", 451 " }", 452 "", 453 " public static void injectManyArgs(", 454 " Object instance,", 455 " String string,", 456 " Lazy<String> lazyString,", 457 " Provider<String> stringProvider) {", 458 " ((MethodInjection) instance).manyArgs(string, lazyString, stringProvider);", 459 " }", 460 "}"); 461 assertAbout(javaSource()) 462 .that(file) 463 .withCompilerOptions(compilerMode.javacopts()) 464 .processedWith(new ComponentProcessor()) 465 .compilesWithoutError() 466 .and() 467 .generatesSources(expected); 468 } 469 470 @Test mixedMemberInjection()471 public void mixedMemberInjection() { 472 JavaFileObject file = JavaFileObjects.forSourceLines( 473 "test.MixedMemberInjection", 474 "package test;", 475 "", 476 "import dagger.Lazy;", 477 "import javax.inject.Inject;", 478 "import javax.inject.Provider;", 479 "", 480 "class MixedMemberInjection {", 481 " @Inject String string;", 482 " @Inject void setString(String s) {}", 483 " @Inject Object object;", 484 " @Inject void setObject(Object o) {}", 485 "}"); 486 JavaFileObject expected = JavaFileObjects.forSourceLines( 487 "test.MixedMemberInjection_MembersInjector", 488 "package test;", 489 "", 490 "import dagger.MembersInjector;", 491 IMPORT_GENERATED_ANNOTATION, 492 "import javax.inject.Provider;", 493 "", 494 GENERATED_ANNOTATION, 495 "public final class MixedMemberInjection_MembersInjector", 496 " implements MembersInjector<MixedMemberInjection> {", 497 "", 498 " private final Provider<String> stringAndSProvider;", 499 " private final Provider<Object> objectAndOProvider;", 500 "", 501 " public MixedMemberInjection_MembersInjector(", 502 " Provider<String> stringAndSProvider,", 503 " Provider<Object> objectAndOProvider) {", 504 " this.stringAndSProvider = stringAndSProvider;", 505 " this.objectAndOProvider = objectAndOProvider;", 506 " }", 507 "", 508 " public static MembersInjector<MixedMemberInjection> create(", 509 " Provider<String> stringAndSProvider,", 510 " Provider<Object> objectAndOProvider) {", 511 " return new MixedMemberInjection_MembersInjector(", 512 " stringAndSProvider, objectAndOProvider);", 513 " }", 514 "", 515 " @Override", 516 " public void injectMembers(MixedMemberInjection instance) {", 517 " injectString(instance, stringAndSProvider.get());", 518 " injectObject(instance, objectAndOProvider.get());", 519 " injectSetString(instance, stringAndSProvider.get());", 520 " injectSetObject(instance, objectAndOProvider.get());", 521 " }", 522 "", 523 " public static void injectString(Object instance, String string) {", 524 " ((MixedMemberInjection) instance).string = string;", 525 " }", 526 "", 527 " public static void injectObject(Object instance, Object object) {", 528 " ((MixedMemberInjection) instance).object = object;", 529 " }", 530 "", 531 " public static void injectSetString(Object instance, String s) {", 532 " ((MixedMemberInjection) instance).setString(s);", 533 " }", 534 "", 535 " public static void injectSetObject(Object instance, Object o) {", 536 " ((MixedMemberInjection) instance).setObject(o);", 537 " }", 538 "}"); 539 assertAbout(javaSource()) 540 .that(file) 541 .withCompilerOptions(compilerMode.javacopts()) 542 .processedWith(new ComponentProcessor()) 543 .compilesWithoutError() 544 .and() 545 .generatesSources(expected); 546 } 547 injectConstructorAndMembersInjection()548 @Test public void injectConstructorAndMembersInjection() { 549 JavaFileObject file = JavaFileObjects.forSourceLines("test.AllInjections", 550 "package test;", 551 "", 552 "import javax.inject.Inject;", 553 "", 554 "class AllInjections {", 555 " @Inject String s;", 556 " @Inject AllInjections(String s) {}", 557 " @Inject void s(String s) {}", 558 "}"); 559 JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines( 560 "test.AllInjections_MembersInjector", 561 "package test;", 562 "", 563 "import dagger.MembersInjector;", 564 IMPORT_GENERATED_ANNOTATION, 565 "import javax.inject.Provider;", 566 "", 567 GENERATED_ANNOTATION, 568 "public final class AllInjections_MembersInjector ", 569 " implements MembersInjector<AllInjections> {", 570 "", 571 " private final Provider<String> sProvider;", 572 "", 573 " public AllInjections_MembersInjector(Provider<String> sProvider) {", 574 " this.sProvider = sProvider;", 575 " }", 576 "", 577 " public static MembersInjector<AllInjections> create(Provider<String> sProvider) {", 578 " return new AllInjections_MembersInjector(sProvider);", 579 " }", 580 "", 581 " @Override", 582 " public void injectMembers(AllInjections instance) {", 583 " injectS(instance, sProvider.get());", 584 " injectS2(instance, sProvider.get());", 585 " }", 586 "", 587 // TODO(b/64477506): now that these all take "object", it would be nice to rename "instance" 588 // to the type name 589 " public static void injectS(Object instance, String s) {", 590 " ((AllInjections) instance).s = s;", 591 " }", 592 "", 593 " public static void injectS2(Object instance, String s) {", 594 " ((AllInjections) instance).s(s);", 595 " }", 596 "", 597 "}"); 598 assertAbout(javaSource()) 599 .that(file) 600 .withCompilerOptions(compilerMode.javacopts()) 601 .processedWith(new ComponentProcessor()) 602 .compilesWithoutError() 603 .and() 604 .generatesSources(expectedMembersInjector); 605 } 606 supertypeMembersInjection()607 @Test public void supertypeMembersInjection() { 608 JavaFileObject aFile = JavaFileObjects.forSourceLines("test.A", 609 "package test;", 610 "", 611 "class A {}"); 612 JavaFileObject bFile = JavaFileObjects.forSourceLines("test.B", 613 "package test;", 614 "", 615 "import javax.inject.Inject;", 616 "", 617 "class B extends A {", 618 " @Inject String s;", 619 "}"); 620 JavaFileObject expectedMembersInjector = JavaFileObjects.forSourceLines( 621 "test.AllInjections_MembersInjector", 622 "package test;", 623 "", 624 "import dagger.MembersInjector;", 625 IMPORT_GENERATED_ANNOTATION, 626 "import javax.inject.Provider;", 627 "", 628 GENERATED_ANNOTATION, 629 "public final class B_MembersInjector implements MembersInjector<B> {", 630 " private final Provider<String> sProvider;", 631 "", 632 " public B_MembersInjector(Provider<String> sProvider) {", 633 " this.sProvider = sProvider;", 634 " }", 635 "", 636 " public static MembersInjector<B> create(Provider<String> sProvider) {", 637 " return new B_MembersInjector(sProvider);", 638 " }", 639 "", 640 " @Override", 641 " public void injectMembers(B instance) {", 642 " injectS(instance, sProvider.get());", 643 " }", 644 "", 645 " public static void injectS(Object instance, String s) {", 646 " ((B) instance).s = s;", 647 " }", 648 "}"); 649 assertAbout(javaSources()) 650 .that(ImmutableList.of(aFile, bFile)) 651 .withCompilerOptions(compilerMode.javacopts()) 652 .processedWith(new ComponentProcessor()) 653 .compilesWithoutError() 654 .and() 655 .generatesSources(expectedMembersInjector); 656 } 657 658 @Test simpleComponentWithNesting()659 public void simpleComponentWithNesting() { 660 JavaFileObject nestedTypesFile = JavaFileObjects.forSourceLines( 661 "test.OuterType", 662 "package test;", 663 "", 664 "import dagger.Component;", 665 "import javax.inject.Inject;", 666 "", 667 "final class OuterType {", 668 " static class A {", 669 " @Inject A() {}", 670 " }", 671 " static class B {", 672 " @Inject A a;", 673 " }", 674 " @Component interface SimpleComponent {", 675 " A a();", 676 " void inject(B b);", 677 " }", 678 "}"); 679 JavaFileObject bMembersInjector = JavaFileObjects.forSourceLines( 680 "test.OuterType_B_MembersInjector", 681 "package test;", 682 "", 683 "import dagger.MembersInjector;", 684 IMPORT_GENERATED_ANNOTATION, 685 "import javax.inject.Provider;", 686 "", 687 GENERATED_ANNOTATION, 688 "public final class OuterType_B_MembersInjector", 689 " implements MembersInjector<OuterType.B> {", 690 " private final Provider<OuterType.A> aProvider;", 691 "", 692 " public OuterType_B_MembersInjector(Provider<OuterType.A> aProvider) {", 693 " this.aProvider = aProvider;", 694 " }", 695 "", 696 " public static MembersInjector<OuterType.B> create(Provider<OuterType.A> aProvider) {", 697 " return new OuterType_B_MembersInjector(aProvider);", 698 " }", 699 "", 700 " @Override", 701 " public void injectMembers(OuterType.B instance) {", 702 " injectA(instance, aProvider.get());", 703 " }", 704 "", 705 " public static void injectA(Object instance, Object a) {", 706 " ((OuterType.B) instance).a = (OuterType.A) a;", 707 " }", 708 "}"); 709 assertAbout(javaSources()) 710 .that(ImmutableList.of(nestedTypesFile)) 711 .withCompilerOptions(compilerMode.javacopts()) 712 .processedWith(new ComponentProcessor()) 713 .compilesWithoutError() 714 .and() 715 .generatesSources(bMembersInjector); 716 } 717 718 @Test componentWithNestingAndGeneratedType()719 public void componentWithNestingAndGeneratedType() { 720 JavaFileObject nestedTypesFile = 721 JavaFileObjects.forSourceLines( 722 "test.OuterType", 723 "package test;", 724 "", 725 "import dagger.Component;", 726 "import javax.inject.Inject;", 727 "", 728 "final class OuterType {", 729 " @Inject GeneratedType generated;", 730 " static class A {", 731 " @Inject A() {}", 732 " }", 733 " static class B {", 734 " @Inject A a;", 735 " }", 736 " @Component interface SimpleComponent {", 737 " A a();", 738 " void inject(B b);", 739 " }", 740 "}"); 741 JavaFileObject bMembersInjector = 742 JavaFileObjects.forSourceLines( 743 "test.OuterType_B_MembersInjector", 744 "package test;", 745 "", 746 "import dagger.MembersInjector;", 747 IMPORT_GENERATED_ANNOTATION, 748 "import javax.inject.Provider;", 749 "", 750 GENERATED_ANNOTATION, 751 "public final class OuterType_B_MembersInjector", 752 " implements MembersInjector<OuterType.B> {", 753 " private final Provider<OuterType.A> aProvider;", 754 "", 755 " public OuterType_B_MembersInjector(Provider<OuterType.A> aProvider) {", 756 " this.aProvider = aProvider;", 757 " }", 758 "", 759 " public static MembersInjector<OuterType.B> create(", 760 " Provider<OuterType.A> aProvider) {", 761 " return new OuterType_B_MembersInjector(aProvider);", 762 " }", 763 "", 764 " @Override", 765 " public void injectMembers(OuterType.B instance) {", 766 " injectA(instance, aProvider.get());", 767 " }", 768 "", 769 " public static void injectA(Object instance, Object a) {", 770 " ((OuterType.B) instance).a = (OuterType.A) a;", 771 " }", 772 "}"); 773 assertAbout(javaSource()) 774 .that(nestedTypesFile) 775 .withCompilerOptions(compilerMode.javacopts()) 776 .processedWith( 777 new ComponentProcessor(), 778 new AbstractProcessor() { 779 private boolean done; 780 781 @Override 782 public Set<String> getSupportedAnnotationTypes() { 783 return ImmutableSet.of("*"); 784 } 785 786 @Override 787 public boolean process( 788 Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 789 if (!done) { 790 done = true; 791 try (Writer writer = 792 processingEnv 793 .getFiler() 794 .createSourceFile("test.GeneratedType") 795 .openWriter()) { 796 writer.write( 797 Joiner.on('\n') 798 .join( 799 "package test;", 800 "", 801 "import javax.inject.Inject;", 802 "", 803 "class GeneratedType {", 804 " @Inject GeneratedType() {}", 805 "}")); 806 } catch (IOException e) { 807 throw new RuntimeException(e); 808 } 809 } 810 return false; 811 } 812 }) 813 .compilesWithoutError() 814 .and() 815 .generatesSources(bMembersInjector); 816 } 817 818 @Test lowerCaseNamedMembersInjector_forLowerCaseType()819 public void lowerCaseNamedMembersInjector_forLowerCaseType() { 820 JavaFileObject foo = 821 JavaFileObjects.forSourceLines( 822 "test.foo", 823 "package test;", 824 "", 825 "import javax.inject.Inject;", 826 "", 827 "class foo {", 828 " @Inject String string;", 829 "}"); 830 JavaFileObject fooModule = 831 JavaFileObjects.forSourceLines( 832 "test.fooModule", 833 "package test;", 834 "", 835 "import dagger.Module;", 836 "import dagger.Provides;", 837 "", 838 "@Module", 839 "class fooModule {", 840 " @Provides String string() { return \"foo\"; }", 841 "}"); 842 JavaFileObject fooComponent = 843 JavaFileObjects.forSourceLines( 844 "test.fooComponent", 845 "package test;", 846 "", 847 "import dagger.Component;", 848 "", 849 "@Component(modules = fooModule.class)", 850 "interface fooComponent {", 851 " void inject(foo target);", 852 "}"); 853 854 Compilation compilation = 855 daggerCompiler() 856 .withOptions(compilerMode.javacopts()) 857 .compile(foo, fooModule, fooComponent); 858 assertThat(compilation).succeeded(); 859 assertThat(compilation).generatedFile(CLASS_OUTPUT, "test", "foo_MembersInjector.class"); 860 } 861 862 @Test fieldInjectionForShadowedMember()863 public void fieldInjectionForShadowedMember() { 864 JavaFileObject foo = 865 JavaFileObjects.forSourceLines( 866 "test.Foo", 867 "package test;", 868 "", 869 "import javax.inject.Inject;", 870 "", 871 "class Foo {", 872 " @Inject Foo() {}", 873 "}"); 874 JavaFileObject bar = 875 JavaFileObjects.forSourceLines( 876 "test.Bar", 877 "package test;", 878 "", 879 "import javax.inject.Inject;", 880 "", 881 "class Bar {", 882 " @Inject Bar() {}", 883 "}"); 884 JavaFileObject parent = 885 JavaFileObjects.forSourceLines( 886 "test.Parent", 887 "package test;", 888 "", 889 "import javax.inject.Inject;", 890 "", 891 "class Parent { ", 892 " @Inject Foo object;", 893 "}"); 894 JavaFileObject child = 895 JavaFileObjects.forSourceLines( 896 "test.Child", 897 "package test;", 898 "", 899 "import javax.inject.Inject;", 900 "", 901 "class Child extends Parent { ", 902 " @Inject Bar object;", 903 "}"); 904 JavaFileObject component = 905 JavaFileObjects.forSourceLines( 906 "test.C", 907 "package test;", 908 "", 909 "import dagger.Component;", 910 "", 911 "@Component", 912 "interface C { ", 913 " void inject(Child child);", 914 "}"); 915 916 JavaFileObject expectedMembersInjector = 917 JavaFileObjects.forSourceLines( 918 "test.Child_MembersInjector", 919 "package test;", 920 "", 921 "import dagger.MembersInjector;", 922 IMPORT_GENERATED_ANNOTATION, 923 "import javax.inject.Provider;", 924 "", 925 GENERATED_ANNOTATION, 926 "public final class Child_MembersInjector implements MembersInjector<Child> {", 927 " private final Provider<Foo> objectProvider;", 928 " private final Provider<Bar> objectProvider2;", 929 "", 930 " public Child_MembersInjector(", 931 " Provider<Foo> objectProvider, Provider<Bar> objectProvider2) {", 932 " this.objectProvider = objectProvider;", 933 " this.objectProvider2 = objectProvider2;", 934 " }", 935 "", 936 " public static MembersInjector<Child> create(", 937 " Provider<Foo> objectProvider, Provider<Bar> objectProvider2) {", 938 " return new Child_MembersInjector(objectProvider, objectProvider2);", 939 " }", 940 "", 941 " @Override", 942 " public void injectMembers(Child instance) {", 943 " Parent_MembersInjector.injectObject(instance, objectProvider.get());", 944 " injectObject(instance, objectProvider2.get());", 945 " }", 946 "", 947 " public static void injectObject(Object instance, Object object) {", 948 " ((Child) instance).object = (Bar) object;", 949 " }", 950 "}"); 951 952 assertAbout(javaSources()) 953 .that(ImmutableList.of(foo, bar, parent, child, component)) 954 .withCompilerOptions(compilerMode.javacopts()) 955 .processedWith(new ComponentProcessor()) 956 .compilesWithoutError() 957 .and() 958 .generatesSources(expectedMembersInjector); 959 } 960 privateNestedClassError()961 @Test public void privateNestedClassError() { 962 JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass", 963 "package test;", 964 "", 965 "import javax.inject.Inject;", 966 "", 967 "final class OuterClass {", 968 " private static final class InnerClass {", 969 " @Inject int field;", 970 " }", 971 "}"); 972 Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file); 973 assertThat(compilation).failed(); 974 assertThat(compilation) 975 .hadErrorContaining("Dagger does not support injection into private classes") 976 .inFile(file) 977 .onLine(6); 978 } 979 privateNestedClassWarning()980 @Test public void privateNestedClassWarning() { 981 JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass", 982 "package test;", 983 "", 984 "import javax.inject.Inject;", 985 "", 986 "final class OuterClass {", 987 " private static final class InnerClass {", 988 " @Inject int field;", 989 " }", 990 "}"); 991 Compilation compilation = 992 daggerCompiler() 993 .withOptions( 994 compilerMode.javacopts().append("-Adagger.privateMemberValidation=WARNING")) 995 .compile(file); 996 assertThat(compilation).succeeded(); 997 assertThat(compilation) 998 .hadWarningContaining("Dagger does not support injection into private classes") 999 .inFile(file) 1000 .onLine(6); 1001 } 1002 privateSuperclassIsOkIfNotInjectedInto()1003 @Test public void privateSuperclassIsOkIfNotInjectedInto() { 1004 JavaFileObject file = JavaFileObjects.forSourceLines("test.OuterClass", 1005 "package test;", 1006 "", 1007 "import javax.inject.Inject;", 1008 "", 1009 "final class OuterClass {", 1010 " private static class BaseClass {}", 1011 "", 1012 " static final class DerivedClass extends BaseClass {", 1013 " @Inject int field;", 1014 " }", 1015 "}"); 1016 Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file); 1017 assertThat(compilation).succeeded(); 1018 } 1019 1020 @Test rawFrameworkTypeField()1021 public void rawFrameworkTypeField() { 1022 JavaFileObject file = 1023 JavaFileObjects.forSourceLines( 1024 "test.RawFrameworkTypes", 1025 "package test;", 1026 "", 1027 "import dagger.Component;", 1028 "import javax.inject.Inject;", 1029 "import javax.inject.Provider;", 1030 "", 1031 "class RawProviderField {", 1032 " @Inject Provider fieldWithRawProvider;", 1033 "}", 1034 "", 1035 "@Component", 1036 "interface C {", 1037 " void inject(RawProviderField rawProviderField);", 1038 "}"); 1039 1040 Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file); 1041 assertThat(compilation).failed(); 1042 assertThat(compilation) 1043 .hadErrorContaining("javax.inject.Provider cannot be provided") 1044 .inFile(file) 1045 .onLineContaining("interface C"); 1046 } 1047 1048 @Test rawFrameworkTypeParameter()1049 public void rawFrameworkTypeParameter() { 1050 JavaFileObject file = 1051 JavaFileObjects.forSourceLines( 1052 "test.RawFrameworkTypes", 1053 "package test;", 1054 "", 1055 "import dagger.Component;", 1056 "import javax.inject.Inject;", 1057 "import javax.inject.Provider;", 1058 "", 1059 "class RawProviderParameter {", 1060 " @Inject void methodInjection(Provider rawProviderParameter) {}", 1061 "}", 1062 "", 1063 "@Component", 1064 "interface C {", 1065 " void inject(RawProviderParameter rawProviderParameter);", 1066 "}"); 1067 1068 Compilation compilation = daggerCompiler().withOptions(compilerMode.javacopts()).compile(file); 1069 assertThat(compilation).failed(); 1070 assertThat(compilation) 1071 .hadErrorContaining("javax.inject.Provider cannot be provided") 1072 .inFile(file) 1073 .onLineContaining("interface C"); 1074 } 1075 1076 @Test injectsPrimitive()1077 public void injectsPrimitive() { 1078 JavaFileObject injectedType = 1079 JavaFileObjects.forSourceLines( 1080 "test.InjectedType", 1081 "package test;", 1082 "", 1083 "import javax.inject.Inject;", 1084 "", 1085 "class InjectedType {", 1086 " @Inject InjectedType() {}", 1087 "", 1088 " @Inject int primitiveInt;", 1089 " @Inject Integer boxedInt;", 1090 "}"); 1091 JavaFileObject membersInjector = 1092 JavaFileObjects.forSourceLines( 1093 "test.InjectedType_MembersInjector", 1094 "package test;", 1095 "", 1096 "import dagger.MembersInjector;", 1097 IMPORT_GENERATED_ANNOTATION, 1098 "import javax.inject.Provider;", 1099 "", 1100 GENERATED_ANNOTATION, 1101 "public final class InjectedType_MembersInjector ", 1102 " implements MembersInjector<InjectedType> {", 1103 " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;", 1104 "", 1105 " public InjectedType_MembersInjector(", 1106 " Provider<Integer> boxedIntAndPrimitiveIntProvider) {", 1107 " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;", 1108 " }", 1109 "", 1110 " public static MembersInjector<InjectedType> create(", 1111 " Provider<Integer> boxedIntAndPrimitiveIntProvider) {", 1112 " return new InjectedType_MembersInjector(boxedIntAndPrimitiveIntProvider);", 1113 " }", 1114 "", 1115 " @Override", 1116 " public void injectMembers(InjectedType instance) {", 1117 " injectPrimitiveInt(instance, boxedIntAndPrimitiveIntProvider.get());", 1118 " injectBoxedInt(instance, boxedIntAndPrimitiveIntProvider.get());", 1119 " }", 1120 "", 1121 " public static void injectPrimitiveInt(Object instance, int primitiveInt) {", 1122 " ((InjectedType) instance).primitiveInt = primitiveInt;", 1123 " }", 1124 "", 1125 " public static void injectBoxedInt(Object instance, Integer boxedInt) {", 1126 " ((InjectedType) instance).boxedInt = boxedInt;", 1127 " }", 1128 "}"); 1129 JavaFileObject factory = 1130 JavaFileObjects.forSourceLines( 1131 "test.InjectedType_Factory", 1132 "package test;", 1133 "", 1134 "import dagger.internal.Factory;", 1135 IMPORT_GENERATED_ANNOTATION, 1136 "import javax.inject.Provider;", 1137 "", 1138 GENERATED_ANNOTATION, 1139 "public final class InjectedType_Factory implements Factory<InjectedType> {", 1140 " private final Provider<Integer> boxedIntAndPrimitiveIntProvider;", 1141 "", 1142 " public InjectedType_Factory(Provider<Integer> boxedIntAndPrimitiveIntProvider) {", 1143 " this.boxedIntAndPrimitiveIntProvider = boxedIntAndPrimitiveIntProvider;", 1144 " }", 1145 "", 1146 " @Override", 1147 " public InjectedType get() {", 1148 " InjectedType instance = new InjectedType();", 1149 " InjectedType_MembersInjector.injectPrimitiveInt(", 1150 " instance, boxedIntAndPrimitiveIntProvider.get());", 1151 " InjectedType_MembersInjector.injectBoxedInt(", 1152 " instance, boxedIntAndPrimitiveIntProvider.get());", 1153 " return instance;", 1154 " }", 1155 "", 1156 " public static InjectedType_Factory create(", 1157 " Provider<Integer> boxedIntAndPrimitiveIntProvider) {", 1158 " return new InjectedType_Factory(boxedIntAndPrimitiveIntProvider);", 1159 " }", 1160 "", 1161 " public static InjectedType newInstance() {", 1162 " return new InjectedType();", 1163 " }", 1164 "}"); 1165 Compilation compilation = 1166 daggerCompiler().withOptions(compilerMode.javacopts()).compile(injectedType); 1167 assertThat(compilation).succeeded(); 1168 assertThat(compilation) 1169 .generatedSourceFile("test.InjectedType_MembersInjector") 1170 .hasSourceEquivalentTo(membersInjector); 1171 assertThat(compilation) 1172 .generatedSourceFile("test.InjectedType_Factory") 1173 .hasSourceEquivalentTo(factory); 1174 } 1175 1176 @Test accessibility()1177 public void accessibility() { 1178 JavaFileObject foo = 1179 JavaFileObjects.forSourceLines( 1180 "other.Foo", 1181 "package other;", 1182 "", 1183 "import javax.inject.Inject;", 1184 "", 1185 "class Foo {", 1186 " @Inject Foo() {}", 1187 "}"); 1188 JavaFileObject inaccessible = 1189 JavaFileObjects.forSourceLines( 1190 "other.Inaccessible", 1191 "package other;", 1192 "", 1193 "import javax.inject.Inject;", 1194 "", 1195 "class Inaccessible {", 1196 " @Inject Inaccessible() {}", 1197 " @Inject Foo foo;", 1198 " @Inject void method(Foo foo) {}", 1199 "}"); 1200 JavaFileObject usesInaccessible = 1201 JavaFileObjects.forSourceLines( 1202 "other.UsesInaccessible", 1203 "package other;", 1204 "", 1205 "import javax.inject.Inject;", 1206 "", 1207 "public class UsesInaccessible {", 1208 " @Inject UsesInaccessible(Inaccessible inaccessible) {}", 1209 "}"); 1210 JavaFileObject component = 1211 JavaFileObjects.forSourceLines( 1212 "test.TestComponent", 1213 "package test;", 1214 "", 1215 "import dagger.Component;", 1216 "import other.UsesInaccessible;", 1217 "", 1218 "@Component", 1219 "interface TestComponent {", 1220 " UsesInaccessible usesInaccessible();", 1221 "}"); 1222 1223 Compilation compilation = 1224 daggerCompiler() 1225 .withOptions(compilerMode.javacopts()) 1226 .compile(foo, inaccessible, usesInaccessible, component); 1227 assertThat(compilation).succeeded(); 1228 assertThat(compilation) 1229 .generatedSourceFile("other.Inaccessible_MembersInjector") 1230 .hasSourceEquivalentTo( 1231 JavaFileObjects.forSourceLines( 1232 "other.Inaccessible_MembersInjector", 1233 "package other;", 1234 "", 1235 "import dagger.MembersInjector;", 1236 IMPORT_GENERATED_ANNOTATION, 1237 "import javax.inject.Provider;", 1238 "", 1239 GENERATED_ANNOTATION, 1240 "public final class Inaccessible_MembersInjector", 1241 " implements MembersInjector<Inaccessible> {", 1242 " private final Provider<Foo> fooProvider;", 1243 "", 1244 " public Inaccessible_MembersInjector(Provider<Foo> fooProvider) {", 1245 " this.fooProvider = fooProvider;", 1246 " }", 1247 "", 1248 " public static MembersInjector<Inaccessible> create(Provider<Foo> fooProvider) {", 1249 " return new Inaccessible_MembersInjector(fooProvider);", 1250 " }", 1251 "", 1252 " @Override", 1253 " public void injectMembers(Inaccessible instance) {", 1254 " injectFoo(instance, fooProvider.get());", 1255 " injectMethod(instance, fooProvider.get());", 1256 " }", 1257 "", 1258 " public static void injectFoo(Object instance, Object foo) {", 1259 " ((Inaccessible) instance).foo = (Foo) foo;", 1260 " }", 1261 "", 1262 " public static void injectMethod(Object instance, Object foo) {", 1263 " ((Inaccessible) instance).method((Foo) foo);", 1264 " }", 1265 "}")); 1266 JavaFileObject generatedComponent = 1267 JavaFileObjects.forSourceLines( 1268 "test.DaggerTestComponent", 1269 "package test;", 1270 "", 1271 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 1272 IMPORT_GENERATED_ANNOTATION, 1273 "import other.Foo_Factory;", 1274 "import other.Inaccessible_Factory;", 1275 "import other.Inaccessible_MembersInjector;", 1276 "import other.UsesInaccessible;", 1277 "import other.UsesInaccessible_Factory;", 1278 "", 1279 GENERATED_ANNOTATION, 1280 "final class DaggerTestComponent implements TestComponent {", 1281 " private Object getInaccessible() {", 1282 " return injectInaccessible(Inaccessible_Factory.newInstance());", 1283 " }", 1284 "", 1285 " @Override", 1286 " public UsesInaccessible usesInaccessible() {", 1287 " return UsesInaccessible_Factory.newInstance(", 1288 " getInaccessible());", 1289 " }", 1290 "", 1291 // TODO(ronshapiro): if possible, it would be great to rename "instance", but we 1292 // need to make sure that this doesn't conflict with any framework field in this or 1293 // any parent component 1294 " @CanIgnoreReturnValue", 1295 " private Object injectInaccessible(Object instance) {", 1296 " Inaccessible_MembersInjector.injectFoo(instance, Foo_Factory.newInstance());", 1297 " Inaccessible_MembersInjector.injectMethod(instance, Foo_Factory.newInstance());", 1298 " return instance;", 1299 " }", 1300 "}"); 1301 assertThat(compilation) 1302 .generatedSourceFile("test.DaggerTestComponent") 1303 .containsElementsIn(generatedComponent); 1304 } 1305 1306 @Test accessibleRawType_ofInaccessibleType()1307 public void accessibleRawType_ofInaccessibleType() { 1308 JavaFileObject inaccessible = 1309 JavaFileObjects.forSourceLines( 1310 "other.Inaccessible", 1311 "package other;", 1312 "", 1313 "class Inaccessible {}"); 1314 JavaFileObject inaccessiblesModule = 1315 JavaFileObjects.forSourceLines( 1316 "other.InaccessiblesModule", 1317 "package other;", 1318 "", 1319 "import dagger.Module;", 1320 "import dagger.Provides;", 1321 "import java.util.ArrayList;", 1322 "import java.util.List;", 1323 "import javax.inject.Provider;", 1324 "import javax.inject.Singleton;", 1325 "", 1326 "@Module", 1327 "public class InaccessiblesModule {", 1328 // force Provider initialization 1329 " @Provides @Singleton static List<Inaccessible> inaccessibles() {", 1330 " return new ArrayList<>();", 1331 " }", 1332 "}"); 1333 JavaFileObject usesInaccessibles = 1334 JavaFileObjects.forSourceLines( 1335 "other.UsesInaccessibles", 1336 "package other;", 1337 "", 1338 "import java.util.List;", 1339 "import javax.inject.Inject;", 1340 "", 1341 "public class UsesInaccessibles {", 1342 " @Inject UsesInaccessibles() {}", 1343 " @Inject List<Inaccessible> inaccessibles;", 1344 "}"); 1345 JavaFileObject component = 1346 JavaFileObjects.forSourceLines( 1347 "test.TestComponent", 1348 "package test;", 1349 "", 1350 "import dagger.Component;", 1351 "import javax.inject.Singleton;", 1352 "import other.UsesInaccessibles;", 1353 "", 1354 "@Singleton", 1355 "@Component(modules = other.InaccessiblesModule.class)", 1356 "interface TestComponent {", 1357 " UsesInaccessibles usesInaccessibles();", 1358 "}"); 1359 1360 Compilation compilation = 1361 daggerCompiler() 1362 .withOptions(compilerMode.javacopts()) 1363 .compile(inaccessible, inaccessiblesModule, usesInaccessibles, component); 1364 assertThat(compilation).succeeded(); 1365 JavaFileObject generatedComponent = 1366 compilerMode 1367 .javaFileBuilder("test.DaggerTestComponent") 1368 .addLines( 1369 "package test;", 1370 "", 1371 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 1372 "import other.InaccessiblesModule;", 1373 "import other.InaccessiblesModule_InaccessiblesFactory;", 1374 "import other.UsesInaccessibles;", 1375 "import other.UsesInaccessibles_Factory;", 1376 "import other.UsesInaccessibles_MembersInjector;", 1377 "", 1378 GENERATED_ANNOTATION, 1379 "final class DaggerTestComponent implements TestComponent {") 1380 .addLinesIn( 1381 FAST_INIT_MODE, 1382 " private volatile Object listOfInaccessible = new MemoizedSentinel();", 1383 "", 1384 " private List getListOfInaccessible() {", 1385 " Object local = listOfInaccessible;", 1386 " if (local instanceof MemoizedSentinel) {", 1387 " synchronized (local) {", 1388 " local = listOfInaccessible;", 1389 " if (local instanceof MemoizedSentinel) {", 1390 " local = InaccessiblesModule_InaccessiblesFactory.inaccessibles();", 1391 " listOfInaccessible =", 1392 " DoubleCheck.reentrantCheck(listOfInaccessible, local);", 1393 " }", 1394 " }", 1395 " }", 1396 " return (List) local;", 1397 " }") 1398 .addLinesIn( 1399 DEFAULT_MODE, 1400 " @SuppressWarnings(\"rawtypes\")", 1401 " private Provider inaccessiblesProvider;", 1402 "", 1403 " @SuppressWarnings(\"unchecked\")", 1404 " private void initialize() {", 1405 " this.inaccessiblesProvider =", 1406 " DoubleCheck.provider(InaccessiblesModule_InaccessiblesFactory.create());", 1407 " }") 1408 .addLines( 1409 "", 1410 " @Override", 1411 " public UsesInaccessibles usesInaccessibles() {", 1412 " return injectUsesInaccessibles(", 1413 " UsesInaccessibles_Factory.newInstance());", 1414 " }", 1415 "", 1416 " @CanIgnoreReturnValue", 1417 " private UsesInaccessibles injectUsesInaccessibles(", 1418 " UsesInaccessibles instance) {", 1419 " UsesInaccessibles_MembersInjector.injectInaccessibles(") 1420 .addLinesIn( 1421 FAST_INIT_MODE, 1422 " instance, (List) getListOfInaccessible());") 1423 .addLinesIn( 1424 DEFAULT_MODE, 1425 " instance, (List) inaccessiblesProvider.get());") 1426 .addLines( 1427 " return instance;", 1428 " }", 1429 "}") 1430 .build(); 1431 assertThat(compilation) 1432 .generatedSourceFile("test.DaggerTestComponent") 1433 .containsElementsIn(generatedComponent); 1434 } 1435 1436 @Test publicSupertypeHiddenSubtype()1437 public void publicSupertypeHiddenSubtype() { 1438 JavaFileObject foo = 1439 JavaFileObjects.forSourceLines( 1440 "other.Foo", 1441 "package other;", 1442 "", 1443 "import javax.inject.Inject;", 1444 "", 1445 "class Foo {", 1446 " @Inject Foo() {}", 1447 "}"); 1448 JavaFileObject supertype = 1449 JavaFileObjects.forSourceLines( 1450 "other.Supertype", 1451 "package other;", 1452 "", 1453 "import javax.inject.Inject;", 1454 "", 1455 "public class Supertype<T> {", 1456 " @Inject T t;", 1457 "}"); 1458 JavaFileObject subtype = 1459 JavaFileObjects.forSourceLines( 1460 "other.Subtype", 1461 "package other;", 1462 "", 1463 "import javax.inject.Inject;", 1464 "", 1465 "class Subtype extends Supertype<Foo> {", 1466 " @Inject Subtype() {}", 1467 "}"); 1468 JavaFileObject injectsSubtype = 1469 JavaFileObjects.forSourceLines( 1470 "other.InjectsSubtype", 1471 "package other;", 1472 "", 1473 "import javax.inject.Inject;", 1474 "", 1475 "public class InjectsSubtype {", 1476 " @Inject InjectsSubtype(Subtype s) {}", 1477 "}"); 1478 JavaFileObject component = 1479 JavaFileObjects.forSourceLines( 1480 "test.TestComponent", 1481 "package test;", 1482 "", 1483 "import dagger.Component;", 1484 "", 1485 "@Component", 1486 "interface TestComponent {", 1487 " other.InjectsSubtype injectsSubtype();", 1488 "}"); 1489 1490 Compilation compilation = 1491 daggerCompiler() 1492 .withOptions(compilerMode.javacopts()) 1493 .compile(foo, supertype, subtype, injectsSubtype, component); 1494 assertThat(compilation).succeeded(); 1495 JavaFileObject generatedComponent = 1496 JavaFileObjects.forSourceLines( 1497 "test.DaggerTestComponent", 1498 "package test;", 1499 "", 1500 "import com.google.errorprone.annotations.CanIgnoreReturnValue;", 1501 "import other.Foo_Factory;", 1502 "import other.InjectsSubtype;", 1503 "import other.InjectsSubtype_Factory;", 1504 "import other.Subtype_Factory;", 1505 "import other.Supertype;", 1506 "import other.Supertype_MembersInjector;", 1507 "", 1508 GENERATED_ANNOTATION, 1509 "final class DaggerTestComponent implements TestComponent {", 1510 " private Object getSubtype() {", 1511 " return injectSubtype(Subtype_Factory.newInstance());", 1512 " }", 1513 "", 1514 " @Override", 1515 " public InjectsSubtype injectsSubtype() {", 1516 " return InjectsSubtype_Factory.newInstance(getSubtype());", 1517 " }", 1518 "", 1519 " @CanIgnoreReturnValue", 1520 " private Object injectSubtype(Object instance) {", 1521 " Supertype_MembersInjector.injectT(", 1522 " (Supertype) instance, Foo_Factory.newInstance());", 1523 " return instance;", 1524 " }", 1525 "}"); 1526 1527 assertThat(compilation) 1528 .generatedSourceFile("test.DaggerTestComponent") 1529 .containsElementsIn(generatedComponent); 1530 } 1531 } 1532