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 androidx.room.compiler.processing.XProcessingEnv; 20 import androidx.room.compiler.processing.util.Source; 21 import com.google.common.collect.ImmutableList; 22 import com.google.common.collect.ImmutableMap; 23 import com.squareup.javapoet.MethodSpec; 24 import com.squareup.javapoet.TypeSpec; 25 import dagger.internal.codegen.javapoet.TypeNames; 26 import dagger.testing.compile.CompilerTests; 27 import dagger.testing.golden.GoldenFileRule; 28 import org.junit.Rule; 29 import org.junit.Test; 30 import org.junit.runner.RunWith; 31 import org.junit.runners.Parameterized; 32 import org.junit.runners.Parameterized.Parameters; 33 34 @RunWith(Parameterized.class) 35 public class MembersInjectionTest { 36 37 private static final Source TYPE_USE_NULLABLE = 38 CompilerTests.javaSource( 39 "test.Nullable", // force one-string-per-line format 40 "package test;", 41 "import static java.lang.annotation.ElementType.TYPE_USE;", 42 "import java.lang.annotation.Target;", 43 "", 44 "@Target(TYPE_USE)", 45 "public @interface Nullable {}"); 46 private static final Source NON_TYPE_USE_NULLABLE = 47 CompilerTests.javaSource( 48 "test.Nullable", // force one-string-per-line format 49 "package test;", 50 "", 51 "public @interface Nullable {}"); 52 53 @Parameters(name = "{0}") parameters()54 public static ImmutableList<Object[]> parameters() { 55 return CompilerMode.TEST_PARAMETERS; 56 } 57 58 @Rule public GoldenFileRule goldenFileRule = new GoldenFileRule(); 59 60 private final CompilerMode compilerMode; 61 MembersInjectionTest(CompilerMode compilerMode)62 public MembersInjectionTest(CompilerMode compilerMode) { 63 this.compilerMode = compilerMode; 64 } 65 66 @Test injectKotlinProtectField_fails()67 public void injectKotlinProtectField_fails() { 68 Source injectFieldSrc = 69 CompilerTests.kotlinSource( 70 "MyClass.kt", 71 "package test", 72 "", 73 "import javax.inject.Inject", 74 "", 75 "class MyClass @Inject constructor() {", 76 " @Inject protected lateinit var protectedField: String", 77 "}"); 78 Source moduleSrc = 79 CompilerTests.kotlinSource( 80 "MyModule.kt", 81 "package test", 82 "", 83 "import dagger.Module", 84 "import dagger.Provides", 85 "", 86 "@Module", 87 "object MyModule {", 88 " @Provides", 89 " fun providesString() = \"hello\"", 90 "}"); 91 Source componentSrc = 92 CompilerTests.kotlinSource( 93 "MyComponent.kt", 94 "package test", 95 "", 96 "import dagger.Component", 97 "@Component(modules = [MyModule::class])", 98 "interface MyComponent {}"); 99 CompilerTests.daggerCompiler(injectFieldSrc, moduleSrc, componentSrc) 100 .withProcessingOptions(compilerMode.processorOptions()) 101 .compile( 102 subject -> { 103 subject.hasErrorCount(1); 104 subject.hasErrorContaining( 105 "Dagger injector does not have access to kotlin protected fields"); 106 }); 107 } 108 109 @Test injectJavaProtectField_succeeds()110 public void injectJavaProtectField_succeeds() { 111 Source injectFieldSrc = 112 CompilerTests.javaSource( 113 "test.MyClass", 114 "package test;", 115 "", 116 "import javax.inject.Inject;", 117 "", 118 "public final class MyClass {", 119 " @Inject MyClass() {}", 120 " @Inject protected String protectedField;", 121 "}"); 122 Source moduleSrc = 123 CompilerTests.kotlinSource( 124 "MyModule.kt", 125 "package test", 126 "", 127 "import dagger.Module", 128 "import dagger.Provides", 129 "", 130 "@Module", 131 "object MyModule {", 132 " @Provides", 133 " fun providesString() = \"hello\"", 134 "}"); 135 Source componentSrc = 136 CompilerTests.kotlinSource( 137 "MyComponent.kt", 138 "package test", 139 "", 140 "import dagger.Component", 141 "@Component(modules = [MyModule::class])", 142 "interface MyComponent {}"); 143 CompilerTests.daggerCompiler(injectFieldSrc, moduleSrc, componentSrc) 144 .withProcessingOptions(compilerMode.processorOptions()) 145 .compile(subject -> subject.hasErrorCount(0)); 146 } 147 148 @Test parentClass_noInjectedMembers()149 public void parentClass_noInjectedMembers() throws Exception { 150 Source childFile = 151 CompilerTests.javaSource( 152 "test.Child", 153 "package test;", 154 "", 155 "import javax.inject.Inject;", 156 "", 157 "public final class Child extends Parent {", 158 " @Inject Child() {}", 159 "}"); 160 Source parentFile = 161 CompilerTests.javaSource( 162 "test.Parent", 163 "package test;", 164 "", 165 "public abstract class Parent {}"); 166 167 Source componentFile = 168 CompilerTests.javaSource( 169 "test.TestComponent", 170 "package test;", 171 "", 172 "import dagger.Component;", 173 "", 174 "@Component", 175 "interface TestComponent {", 176 " Child child();", 177 "}"); 178 179 CompilerTests.daggerCompiler(childFile, parentFile, componentFile) 180 .withProcessingOptions(compilerMode.processorOptions()) 181 .compile( 182 subject -> { 183 subject.hasErrorCount(0); 184 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 185 }); 186 } 187 188 @Test parentClass_injectedMembersInSupertype()189 public void parentClass_injectedMembersInSupertype() throws Exception { 190 Source childFile = 191 CompilerTests.javaSource( 192 "test.Child", 193 "package test;", 194 "", 195 "import javax.inject.Inject;", 196 "", 197 "public final class Child extends Parent {", 198 " @Inject Child() {}", 199 "}"); 200 Source parentFile = 201 CompilerTests.javaSource( 202 "test.Parent", 203 "package test;", 204 "", 205 "import javax.inject.Inject;", 206 "", 207 "public abstract class Parent {", 208 " @Inject Dep dep;", 209 "}"); 210 Source depFile = 211 CompilerTests.javaSource( 212 "test.Dep", 213 "package test;", 214 "", 215 "import javax.inject.Inject;", 216 "", 217 "final class Dep {", 218 " @Inject Dep() {}", 219 "}"); 220 Source componentFile = 221 CompilerTests.javaSource( 222 "test.TestComponent", 223 "package test;", 224 "", 225 "import dagger.Component;", 226 "", 227 "@Component", 228 "interface TestComponent {", 229 " Child child();", 230 "}"); 231 232 CompilerTests.daggerCompiler(childFile, parentFile, depFile, componentFile) 233 .withProcessingOptions(compilerMode.processorOptions()) 234 .compile( 235 subject -> { 236 subject.hasErrorCount(0); 237 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 238 }); 239 } 240 fieldAndMethodGenerics()241 @Test public void fieldAndMethodGenerics() { 242 Source file = 243 CompilerTests.javaSource( 244 "test.GenericClass", 245 "package test;", 246 "", 247 "import javax.inject.Inject;", 248 "", 249 "class GenericClass<A, B> {", 250 " @Inject A a;", 251 "", 252 " @Inject GenericClass() {}", 253 "", 254 " @Inject void register(B b) {}", 255 "}"); 256 257 CompilerTests.daggerCompiler(file) 258 .withProcessingOptions(compilerMode.processorOptions()) 259 .compile( 260 subject -> { 261 subject.hasErrorCount(0); 262 subject.generatedSource( 263 goldenFileRule.goldenSource("test/GenericClass_MembersInjector")); 264 }); 265 } 266 subclassedGenericMembersInjectors()267 @Test public void subclassedGenericMembersInjectors() { 268 Source a = 269 CompilerTests.javaSource( 270 "test.A", 271 "package test;", 272 "", 273 "import javax.inject.Inject;", 274 "", 275 "final class A {", 276 " @Inject A() {}", 277 "}"); 278 Source a2 = 279 CompilerTests.javaSource( 280 "test.A2", 281 "package test;", 282 "", 283 "import javax.inject.Inject;", 284 "", 285 "final class A2 {", 286 " @Inject A2() {}", 287 "}"); 288 Source parent = 289 CompilerTests.javaSource( 290 "test.Parent", 291 "package test;", 292 "", 293 "import javax.inject.Inject;", 294 "", 295 "class Parent<X, Y> {", 296 " @Inject X x;", 297 " @Inject Y y;", 298 " @Inject A2 a2;", 299 "", 300 " @Inject Parent() {}", 301 "}"); 302 Source child = 303 CompilerTests.javaSource( 304 "test.Child", 305 "package test;", 306 "", 307 "import javax.inject.Inject;", 308 "", 309 "class Child<T> extends Parent<T, A> {", 310 " @Inject A a;", 311 " @Inject T t;", 312 "", 313 " @Inject Child() {}", 314 "}"); 315 CompilerTests.daggerCompiler(a, a2, parent, child) 316 .withProcessingOptions(compilerMode.processorOptions()) 317 .compile( 318 subject -> { 319 subject.hasErrorCount(0); 320 subject.generatedSource(goldenFileRule.goldenSource("test/Child_MembersInjector")); 321 }); 322 } 323 fieldInjection()324 @Test public void fieldInjection() { 325 Source file = 326 CompilerTests.javaSource( 327 "test.FieldInjection", 328 "package test;", 329 "", 330 "import dagger.Lazy;", 331 "import javax.inject.Inject;", 332 "import javax.inject.Provider;", 333 "", 334 "class FieldInjection {", 335 " @Inject String string;", 336 " @Inject Lazy<String> lazyString;", 337 " @Inject Provider<String> stringProvider;", 338 "}"); 339 CompilerTests.daggerCompiler(file) 340 .withProcessingOptions(compilerMode.processorOptions()) 341 .compile( 342 subject -> { 343 subject.hasErrorCount(0); 344 subject.generatedSource( 345 goldenFileRule.goldenSource("test/FieldInjection_MembersInjector")); 346 }); 347 } 348 349 @Test typeUseNullableFieldInjection()350 public void typeUseNullableFieldInjection() { 351 Source file = 352 CompilerTests.javaSource( 353 "test.FieldInjection", 354 "package test;", 355 "", 356 "import dagger.Lazy;", 357 "import javax.inject.Inject;", 358 "import javax.inject.Provider;", 359 "", 360 "class FieldInjection {", 361 " @Inject @Nullable String string;", 362 "}"); 363 CompilerTests.daggerCompiler(file, TYPE_USE_NULLABLE) 364 .withProcessingOptions(compilerMode.processorOptions()) 365 .compile( 366 subject -> { 367 subject.hasErrorCount(0); 368 subject.generatedSource( 369 goldenFileRule.goldenSource("test/FieldInjection_MembersInjector")); 370 }); 371 } 372 373 @Test nonTypeUseNullableFieldInjection()374 public void nonTypeUseNullableFieldInjection() { 375 Source file = 376 CompilerTests.javaSource( 377 "test.FieldInjection", 378 "package test;", 379 "", 380 "import dagger.Lazy;", 381 "import javax.inject.Inject;", 382 "import javax.inject.Provider;", 383 "", 384 "class FieldInjection {", 385 " @Inject @Nullable String string;", 386 "}"); 387 CompilerTests.daggerCompiler(file, NON_TYPE_USE_NULLABLE) 388 .withProcessingOptions(compilerMode.processorOptions()) 389 .compile( 390 subject -> { 391 subject.hasErrorCount(0); 392 subject.generatedSource( 393 goldenFileRule.goldenSource("test/FieldInjection_MembersInjector")); 394 }); 395 } 396 397 @Test fieldInjectionWithQualifier()398 public void fieldInjectionWithQualifier() { 399 Source file = 400 CompilerTests.javaSource( 401 "test.FieldInjectionWithQualifier", 402 "package test;", 403 "", 404 "import dagger.Lazy;", 405 "import javax.inject.Inject;", 406 "import javax.inject.Named;", 407 "import javax.inject.Provider;", 408 "", 409 "class FieldInjectionWithQualifier {", 410 " @Inject @Named(\"A\") String a;", 411 " @Inject @Named(\"B\") String b;", 412 "}"); 413 CompilerTests.daggerCompiler(file) 414 .withProcessingOptions(compilerMode.processorOptions()) 415 .compile( 416 subject -> { 417 subject.hasErrorCount(0); 418 subject.generatedSource( 419 goldenFileRule.goldenSource("test/FieldInjectionWithQualifier_MembersInjector")); 420 }); 421 } 422 methodInjection()423 @Test public void methodInjection() { 424 Source file = 425 CompilerTests.javaSource( 426 "test.MethodInjection", 427 "package test;", 428 "", 429 "import dagger.Lazy;", 430 "import javax.inject.Inject;", 431 "import javax.inject.Provider;", 432 "", 433 "class MethodInjection {", 434 " @Inject void noArgs() {}", 435 " @Inject void oneArg(String string) {}", 436 " @Inject void manyArgs(", 437 " String string, Lazy<String> lazyString, Provider<String> stringProvider) {}", 438 "}"); 439 CompilerTests.daggerCompiler(file) 440 .withProcessingOptions(compilerMode.processorOptions()) 441 .compile( 442 subject -> { 443 subject.hasErrorCount(0); 444 subject.generatedSource( 445 goldenFileRule.goldenSource("test/MethodInjection_MembersInjector")); 446 }); 447 } 448 449 @Test mixedMemberInjection()450 public void mixedMemberInjection() { 451 Source file = 452 CompilerTests.javaSource( 453 "test.MixedMemberInjection", 454 "package test;", 455 "", 456 "import dagger.Lazy;", 457 "import javax.inject.Inject;", 458 "import javax.inject.Provider;", 459 "", 460 "class MixedMemberInjection {", 461 " @Inject String string;", 462 " @Inject void setString(String s) {}", 463 " @Inject Object object;", 464 " @Inject void setObject(Object o) {}", 465 "}"); 466 CompilerTests.daggerCompiler(file) 467 .withProcessingOptions(compilerMode.processorOptions()) 468 .compile( 469 subject -> { 470 subject.hasErrorCount(0); 471 subject.generatedSource( 472 goldenFileRule.goldenSource("test/MixedMemberInjection_MembersInjector")); 473 }); 474 } 475 injectConstructorAndMembersInjection()476 @Test public void injectConstructorAndMembersInjection() { 477 Source file = 478 CompilerTests.javaSource( 479 "test.AllInjections", 480 "package test;", 481 "", 482 "import javax.inject.Inject;", 483 "", 484 "class AllInjections {", 485 " @Inject String s;", 486 " @Inject AllInjections(String s) {}", 487 " @Inject void s(String s) {}", 488 "}"); 489 CompilerTests.daggerCompiler(file) 490 .withProcessingOptions(compilerMode.processorOptions()) 491 .compile( 492 subject -> { 493 subject.hasErrorCount(0); 494 subject.generatedSource( 495 goldenFileRule.goldenSource("test/AllInjections_MembersInjector")); 496 }); 497 } 498 supertypeMembersInjection()499 @Test public void supertypeMembersInjection() { 500 Source aFile = 501 CompilerTests.javaSource( 502 "test.A", 503 "package test;", 504 "", 505 "class A {}"); 506 Source bFile = 507 CompilerTests.javaSource( 508 "test.B", 509 "package test;", 510 "", 511 "import javax.inject.Inject;", 512 "", 513 "class B extends A {", 514 " @Inject String s;", 515 "}"); 516 CompilerTests.daggerCompiler(aFile, bFile) 517 .withProcessingOptions(compilerMode.processorOptions()) 518 .compile( 519 subject -> { 520 subject.hasErrorCount(0); 521 subject.generatedSource(goldenFileRule.goldenSource("test/B_MembersInjector")); 522 }); 523 } 524 525 @Test simpleComponentWithNesting()526 public void simpleComponentWithNesting() { 527 Source nestedTypesFile = 528 CompilerTests.javaSource( 529 "test.OuterType", 530 "package test;", 531 "", 532 "import dagger.Component;", 533 "import javax.inject.Inject;", 534 "", 535 "final class OuterType {", 536 " static class A {", 537 " @Inject A() {}", 538 " }", 539 " static class B {", 540 " @Inject A a;", 541 " }", 542 " @Component interface SimpleComponent {", 543 " A a();", 544 " void inject(B b);", 545 " }", 546 "}"); 547 CompilerTests.daggerCompiler(nestedTypesFile) 548 .withProcessingOptions(compilerMode.processorOptions()) 549 .compile( 550 subject -> { 551 subject.hasErrorCount(0); 552 subject.generatedSource( 553 goldenFileRule.goldenSource("test/OuterType_B_MembersInjector")); 554 }); 555 } 556 557 @Test componentWithNestingAndGeneratedType()558 public void componentWithNestingAndGeneratedType() { 559 Source nestedTypesFile = 560 CompilerTests.javaSource( 561 "test.OuterType", 562 "package test;", 563 "", 564 "import dagger.Component;", 565 "import javax.inject.Inject;", 566 "", 567 "final class OuterType {", 568 " @Inject GeneratedInjectType generated;", 569 " static class A {", 570 " @Inject A() {}", 571 " }", 572 " static class B {", 573 " @Inject A a;", 574 " }", 575 " @Component interface SimpleComponent {", 576 " A a();", 577 " void inject(B b);", 578 " }", 579 "}"); 580 TypeSpec generatedInjectType = 581 TypeSpec.classBuilder("GeneratedInjectType") 582 .addMethod( 583 MethodSpec.constructorBuilder() 584 .addAnnotation(TypeNames.INJECT_JAVAX) 585 .build()) 586 .build(); 587 588 CompilerTests.daggerCompiler(nestedTypesFile) 589 .withProcessingOptions(compilerMode.processorOptions()) 590 .withProcessingSteps(() -> new GeneratingProcessingStep("test", generatedInjectType)) 591 .compile( 592 subject -> { 593 subject.hasErrorCount(0); 594 subject.generatedSource( 595 goldenFileRule.goldenSource("test/OuterType_B_MembersInjector")); 596 }); 597 } 598 599 @Test lowerCaseNamedMembersInjector_forLowerCaseType()600 public void lowerCaseNamedMembersInjector_forLowerCaseType() { 601 Source foo = 602 CompilerTests.javaSource( 603 "test.foo", 604 "package test;", 605 "", 606 "import javax.inject.Inject;", 607 "", 608 "class foo {", 609 " @Inject String string;", 610 "}"); 611 Source fooModule = 612 CompilerTests.javaSource( 613 "test.fooModule", 614 "package test;", 615 "", 616 "import dagger.Module;", 617 "import dagger.Provides;", 618 "", 619 "@Module", 620 "class fooModule {", 621 " @Provides String string() { return \"foo\"; }", 622 "}"); 623 Source fooComponent = 624 CompilerTests.javaSource( 625 "test.fooComponent", 626 "package test;", 627 "", 628 "import dagger.Component;", 629 "", 630 "@Component(modules = fooModule.class)", 631 "interface fooComponent {", 632 " void inject(foo target);", 633 "}"); 634 635 CompilerTests.daggerCompiler(foo, fooModule, fooComponent) 636 .withProcessingOptions(compilerMode.processorOptions()) 637 .compile( 638 subject -> { 639 subject.hasErrorCount(0); 640 subject.generatedSourceFileWithPath("test/foo_MembersInjector.java"); 641 }); 642 } 643 644 @Test fieldInjectionForShadowedMember()645 public void fieldInjectionForShadowedMember() { 646 Source foo = 647 CompilerTests.javaSource( 648 "test.Foo", 649 "package test;", 650 "", 651 "import javax.inject.Inject;", 652 "", 653 "class Foo {", 654 " @Inject Foo() {}", 655 "}"); 656 Source bar = 657 CompilerTests.javaSource( 658 "test.Bar", 659 "package test;", 660 "", 661 "import javax.inject.Inject;", 662 "", 663 "class Bar {", 664 " @Inject Bar() {}", 665 "}"); 666 Source parent = 667 CompilerTests.javaSource( 668 "test.Parent", 669 "package test;", 670 "", 671 "import javax.inject.Inject;", 672 "", 673 "class Parent { ", 674 " @Inject Foo object;", 675 "}"); 676 Source child = 677 CompilerTests.javaSource( 678 "test.Child", 679 "package test;", 680 "", 681 "import javax.inject.Inject;", 682 "", 683 "class Child extends Parent { ", 684 " @Inject Bar object;", 685 "}"); 686 Source component = 687 CompilerTests.javaSource( 688 "test.C", 689 "package test;", 690 "", 691 "import dagger.Component;", 692 "", 693 "@Component", 694 "interface C { ", 695 " void inject(Child child);", 696 "}"); 697 698 CompilerTests.daggerCompiler(foo, bar, parent, child, component) 699 .withProcessingOptions(compilerMode.processorOptions()) 700 .compile( 701 subject -> { 702 subject.hasErrorCount(0); 703 subject.generatedSource( 704 goldenFileRule.goldenSource("test/Child_MembersInjector")); 705 }); 706 } 707 privateNestedClassError()708 @Test public void privateNestedClassError() { 709 Source file = 710 CompilerTests.javaSource( 711 "test.OuterClass", 712 "package test;", 713 "", 714 "import javax.inject.Inject;", 715 "", 716 "final class OuterClass {", 717 " private static final class InnerClass {", 718 " @Inject int field;", 719 " }", 720 "}"); 721 CompilerTests.daggerCompiler(file) 722 .withProcessingOptions(compilerMode.processorOptions()) 723 .compile( 724 subject -> { 725 subject.hasErrorCount(1); 726 subject.hasErrorContaining("Dagger does not support injection into private classes") 727 .onSource(file) 728 .onLine(6); 729 }); 730 } 731 privateNestedClassWarning()732 @Test public void privateNestedClassWarning() { 733 Source file = 734 CompilerTests.javaSource( 735 "test.OuterClass", 736 "package test;", 737 "", 738 "import javax.inject.Inject;", 739 "", 740 "final class OuterClass {", 741 " private static final class InnerClass {", 742 " @Inject int field;", 743 " }", 744 "}"); 745 CompilerTests.daggerCompiler(file) 746 .withProcessingOptions( 747 ImmutableMap.<String, String>builder() 748 .putAll(compilerMode.processorOptions()) 749 .put("dagger.privateMemberValidation", "WARNING") 750 .buildOrThrow()) 751 .compile( 752 subject -> { 753 subject.hasErrorCount(0); 754 subject.hasWarningCount(1); 755 subject.hasWarningContaining("Dagger does not support injection into private classes") 756 .onSource(file) 757 .onLine(6); 758 }); 759 } 760 privateSuperclassIsOkIfNotInjectedInto()761 @Test public void privateSuperclassIsOkIfNotInjectedInto() { 762 Source file = 763 CompilerTests.javaSource( 764 "test.OuterClass", 765 "package test;", 766 "", 767 "import javax.inject.Inject;", 768 "", 769 "final class OuterClass {", 770 " private static class BaseClass {}", 771 "", 772 " static final class DerivedClass extends BaseClass {", 773 " @Inject int field;", 774 " }", 775 "}"); 776 CompilerTests.daggerCompiler(file) 777 .withProcessingOptions(compilerMode.processorOptions()) 778 .compile(subject -> subject.hasErrorCount(0)); 779 } 780 781 @Test throwExceptionInjectedMethod()782 public void throwExceptionInjectedMethod() { 783 Source file = 784 CompilerTests.javaSource( 785 "test.", 786 "package test;", 787 "", 788 "import javax.inject.Inject;", 789 "class SomeClass {", 790 "@Inject void inject() throws Exception {}", 791 "}"); 792 793 CompilerTests.daggerCompiler(file) 794 .withProcessingOptions(compilerMode.processorOptions()) 795 .compile( 796 subject -> { 797 subject.hasErrorCount(1); 798 subject.hasErrorContaining( 799 "Methods with @Inject may not throw checked exceptions. " 800 + "Please wrap your exceptions in a RuntimeException instead.") 801 .onSource(file) 802 .onLineContaining("throws Exception"); 803 }); 804 } 805 806 @Test rawFrameworkTypeField()807 public void rawFrameworkTypeField() { 808 Source file = 809 CompilerTests.javaSource( 810 "test.RawProviderField", 811 "package test;", 812 "", 813 "import javax.inject.Inject;", 814 "import javax.inject.Provider;", 815 "", 816 "class RawProviderField {", 817 " @Inject", 818 " Provider fieldWithRawProvider;", 819 "}"); 820 821 CompilerTests.daggerCompiler(file) 822 .withProcessingOptions(compilerMode.processorOptions()) 823 .compile( 824 subject -> { 825 subject.hasErrorCount(1); 826 subject.hasErrorContaining( 827 "Dagger does not support injecting raw type: javax.inject.Provider") 828 .onSource(file) 829 .onLineContaining("Provider fieldWithRawProvider"); 830 }); 831 } 832 833 @Test rawFrameworkMethodTypeParameter()834 public void rawFrameworkMethodTypeParameter() { 835 Source file = 836 CompilerTests.javaSource( 837 "test.RawProviderParameter", 838 "package test;", 839 "", 840 "import javax.inject.Inject;", 841 "import javax.inject.Provider;", 842 "", 843 "class RawProviderParameter {", 844 " @Inject", 845 " void methodInjection(", 846 " Provider rawProviderParameter) {}", 847 "}"); 848 849 CompilerTests.daggerCompiler(file) 850 .withProcessingOptions(compilerMode.processorOptions()) 851 .compile( 852 subject -> { 853 subject.hasErrorCount(1); 854 subject.hasErrorContaining( 855 "Dagger does not support injecting raw type: javax.inject.Provider") 856 .onSource(file) 857 .onLineContaining("Provider rawProviderParameter"); 858 }); 859 } 860 861 @Test rawFrameworkConstructorTypeParameter()862 public void rawFrameworkConstructorTypeParameter() { 863 Source file = 864 CompilerTests.javaSource( 865 "test.RawProviderParameter", 866 "package test;", 867 "", 868 "import dagger.Component;", 869 "import javax.inject.Inject;", 870 "import javax.inject.Provider;", 871 "", 872 "class RawProviderParameter {", 873 " @Inject", 874 " RawProviderParameter(", 875 " Provider rawProviderParameter) {}", 876 "}"); 877 878 CompilerTests.daggerCompiler(file) 879 .withProcessingOptions(compilerMode.processorOptions()) 880 .compile( 881 subject -> { 882 subject.hasErrorCount(1); 883 subject.hasErrorContaining( 884 "Dagger does not support injecting raw type: javax.inject.Provider") 885 .onSource(file) 886 .onLineContaining("Provider rawProviderParameter"); 887 }); 888 } 889 890 @Test rawMapFrameworkConstructorTypeParameter()891 public void rawMapFrameworkConstructorTypeParameter() { 892 Source file = 893 CompilerTests.javaSource( 894 "test.RawMapProviderParameter", 895 "package test;", 896 "", 897 "import dagger.Component;", 898 "import javax.inject.Inject;", 899 "import javax.inject.Provider;", 900 "import java.util.Map;", 901 "", 902 "class RawMapProviderParameter {", 903 " @Inject", 904 " RawMapProviderParameter(", 905 " Map<String, Provider> rawProviderParameter) {}", 906 "}"); 907 908 CompilerTests.daggerCompiler(file) 909 .withProcessingOptions(compilerMode.processorOptions()) 910 .compile( 911 subject -> { 912 subject.hasErrorCount(1); 913 subject.hasErrorContaining( 914 "Dagger does not support injecting maps of raw framework types: " 915 + "java.util.Map<java.lang.String,javax.inject.Provider>") 916 .onSource(file) 917 .onLineContaining("Map<String, Provider> rawProviderParameter"); 918 }); 919 } 920 921 @Test daggerProviderField()922 public void daggerProviderField() { 923 Source file = 924 CompilerTests.javaSource( 925 "test.DaggerProviderField", 926 "package test;", 927 "", 928 "import dagger.internal.Provider;", 929 "import javax.inject.Inject;", 930 "", 931 "class DaggerProviderField {", 932 " @Inject", 933 " Provider<String> fieldWithDaggerProvider;", 934 "}"); 935 936 CompilerTests.daggerCompiler(file) 937 .withProcessingOptions(compilerMode.processorOptions()) 938 .compile( 939 subject -> { 940 subject.hasErrorCount(1); 941 subject.hasErrorContaining( 942 "Dagger disallows injecting the type: " 943 + "dagger.internal.Provider<java.lang.String>") 944 .onSource(file) 945 .onLineContaining("Provider<String> fieldWithDaggerProvider"); 946 }); 947 } 948 949 @Test daggerProviderMethodTypeParameter()950 public void daggerProviderMethodTypeParameter() { 951 Source file = 952 CompilerTests.javaSource( 953 "test.DaggerProviderParameter", 954 "package test;", 955 "", 956 "import dagger.internal.Provider;", 957 "import javax.inject.Inject;", 958 "", 959 "class DaggerProviderParameter {", 960 " @Inject", 961 " void methodInjection(", 962 " Provider<String> daggerProviderParameter) {}", 963 "}"); 964 965 CompilerTests.daggerCompiler(file) 966 .withProcessingOptions(compilerMode.processorOptions()) 967 .compile( 968 subject -> { 969 subject.hasErrorCount(1); 970 subject.hasErrorContaining( 971 "Dagger disallows injecting the type: " 972 + "dagger.internal.Provider<java.lang.String>") 973 .onSource(file) 974 .onLineContaining("Provider<String> daggerProviderParameter"); 975 }); 976 } 977 978 @Test daggerProviderConstructorTypeParameter()979 public void daggerProviderConstructorTypeParameter() { 980 Source file = 981 CompilerTests.javaSource( 982 "test.DaggerProviderParameter", 983 "package test;", 984 "", 985 "import dagger.Component;", 986 "import dagger.internal.Provider;", 987 "import javax.inject.Inject;", 988 "", 989 "class DaggerProviderParameter {", 990 " @Inject", 991 " DaggerProviderParameter(", 992 " Provider<String> daggerProviderParameter) {}", 993 "}"); 994 995 CompilerTests.daggerCompiler(file) 996 .withProcessingOptions(compilerMode.processorOptions()) 997 .compile( 998 subject -> { 999 subject.hasErrorCount(1); 1000 subject.hasErrorContaining( 1001 "Dagger disallows injecting the type: " 1002 + "dagger.internal.Provider<java.lang.String>") 1003 .onSource(file) 1004 .onLineContaining("Provider<String> daggerProviderParameter"); 1005 }); 1006 } 1007 1008 @Test rawDaggerProviderConstructorTypeParameter()1009 public void rawDaggerProviderConstructorTypeParameter() { 1010 Source file = 1011 CompilerTests.javaSource( 1012 "test.RawDaggerProviderParameter", 1013 "package test;", 1014 "", 1015 "import dagger.Component;", 1016 "import dagger.internal.Provider;", 1017 "import javax.inject.Inject;", 1018 "", 1019 "class RawDaggerProviderParameter {", 1020 " @Inject", 1021 " RawDaggerProviderParameter(", 1022 " Provider rawDaggerProviderParameter) {}", 1023 "}"); 1024 1025 CompilerTests.daggerCompiler(file) 1026 .withProcessingOptions(compilerMode.processorOptions()) 1027 .compile( 1028 subject -> { 1029 subject.hasErrorCount(1); 1030 subject.hasErrorContaining( 1031 "Dagger disallows injecting the type: dagger.internal.Provider") 1032 .onSource(file) 1033 .onLineContaining("Provider rawDaggerProviderParameter"); 1034 }); 1035 } 1036 1037 @Test daggerMapProviderField()1038 public void daggerMapProviderField() { 1039 Source file = 1040 CompilerTests.javaSource( 1041 "test.DaggerMapProviderField", 1042 "package test;", 1043 "", 1044 "import dagger.internal.Provider;", 1045 "import javax.inject.Inject;", 1046 "import java.util.Map;", 1047 "", 1048 "class DaggerMapProviderField {", 1049 " @Inject", 1050 " Map<String, Provider<Long>> fieldWithDaggerMapProvider;", 1051 "}"); 1052 1053 CompilerTests.daggerCompiler(file) 1054 .withProcessingOptions(compilerMode.processorOptions()) 1055 .compile( 1056 subject -> { 1057 subject.hasErrorCount(1); 1058 subject.hasErrorContaining( 1059 "Dagger does not support injecting maps of disallowed types: " 1060 + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>") 1061 .onSource(file) 1062 .onLineContaining("Map<String, Provider<Long>> fieldWithDaggerMapProvider"); 1063 }); 1064 } 1065 1066 @Test daggerMapProviderMethodTypeParameter()1067 public void daggerMapProviderMethodTypeParameter() { 1068 Source file = 1069 CompilerTests.javaSource( 1070 "test.DaggerMapProviderParameter", 1071 "package test;", 1072 "", 1073 "import dagger.internal.Provider;", 1074 "import javax.inject.Inject;", 1075 "import java.util.Map;", 1076 "", 1077 "class DaggerMapProviderParameter {", 1078 " @Inject", 1079 " void methodInjection(", 1080 " Map<String, Provider<Long>> daggerMapProviderParameter) {}", 1081 "}"); 1082 1083 CompilerTests.daggerCompiler(file) 1084 .withProcessingOptions(compilerMode.processorOptions()) 1085 .compile( 1086 subject -> { 1087 subject.hasErrorCount(1); 1088 subject.hasErrorContaining( 1089 "Dagger does not support injecting maps of disallowed types: " 1090 + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>") 1091 .onSource(file) 1092 .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter"); 1093 }); 1094 } 1095 1096 @Test daggerMapProviderConstructorTypeParameter()1097 public void daggerMapProviderConstructorTypeParameter() { 1098 Source file = 1099 CompilerTests.javaSource( 1100 "test.DaggerMapProviderParameter", 1101 "package test;", 1102 "", 1103 "import dagger.Component;", 1104 "import dagger.internal.Provider;", 1105 "import javax.inject.Inject;", 1106 "import java.util.Map;", 1107 "", 1108 "class DaggerMapProviderParameter {", 1109 " @Inject", 1110 " DaggerMapProviderParameter(", 1111 " Map<String, Provider<Long>> daggerMapProviderParameter) {}", 1112 "}"); 1113 1114 CompilerTests.daggerCompiler(file) 1115 .withProcessingOptions(compilerMode.processorOptions()) 1116 .compile( 1117 subject -> { 1118 subject.hasErrorCount(1); 1119 subject.hasErrorContaining( 1120 "Dagger does not support injecting maps of disallowed types: " 1121 + "java.util.Map<java.lang.String,dagger.internal.Provider<java.lang.Long>>") 1122 .onSource(file) 1123 .onLineContaining("Map<String, Provider<Long>> daggerMapProviderParameter"); 1124 }); 1125 } 1126 1127 @Test rawDaggerMapProviderConstructorTypeParameter()1128 public void rawDaggerMapProviderConstructorTypeParameter() { 1129 Source file = 1130 CompilerTests.javaSource( 1131 "test.RawDaggerMapProviderParameter", 1132 "package test;", 1133 "", 1134 "import dagger.Component;", 1135 "import dagger.internal.Provider;", 1136 "import javax.inject.Inject;", 1137 "import java.util.Map;", 1138 "", 1139 "class RawDaggerMapProviderParameter {", 1140 " @Inject", 1141 " RawDaggerMapProviderParameter(", 1142 " Map<String, Provider> rawDaggerMapProviderParameter) {}", 1143 "}"); 1144 1145 CompilerTests.daggerCompiler(file) 1146 .withProcessingOptions(compilerMode.processorOptions()) 1147 .compile( 1148 subject -> { 1149 subject.hasErrorCount(1); 1150 subject.hasErrorContaining( 1151 "Dagger does not support injecting maps of disallowed types: " 1152 + "java.util.Map<java.lang.String,dagger.internal.Provider>") 1153 .onSource(file) 1154 .onLineContaining("Map<String, Provider> rawDaggerMapProviderParameter"); 1155 }); 1156 } 1157 1158 @Test injectsPrimitive()1159 public void injectsPrimitive() throws Exception { 1160 Source injectedType = 1161 CompilerTests.javaSource( 1162 "test.InjectedType", 1163 "package test;", 1164 "", 1165 "import javax.inject.Inject;", 1166 "", 1167 "class InjectedType {", 1168 " @Inject InjectedType() {}", 1169 "", 1170 " @Inject int primitiveInt;", 1171 " @Inject Integer boxedInt;", 1172 "}"); 1173 1174 CompilerTests.daggerCompiler(injectedType) 1175 .withProcessingOptions(compilerMode.processorOptions()) 1176 .compile( 1177 subject -> { 1178 subject.hasErrorCount(0); 1179 subject.generatedSource( 1180 goldenFileRule.goldenSource("test/InjectedType_MembersInjector")); 1181 subject.generatedSource( 1182 goldenFileRule.goldenSource("test/InjectedType_Factory")); 1183 }); 1184 } 1185 1186 @Test accessibility()1187 public void accessibility() throws Exception { 1188 Source foo = 1189 CompilerTests.javaSource( 1190 "other.Foo", 1191 "package other;", 1192 "", 1193 "import javax.inject.Inject;", 1194 "", 1195 "class Foo {", 1196 " @Inject Foo() {}", 1197 "}"); 1198 Source inaccessible = 1199 CompilerTests.javaSource( 1200 "other.Inaccessible", 1201 "package other;", 1202 "", 1203 "import javax.inject.Inject;", 1204 "", 1205 "class Inaccessible {", 1206 " @Inject Inaccessible() {}", 1207 " @Inject Foo foo;", 1208 " @Inject void method(Foo foo) {}", 1209 "}"); 1210 Source usesInaccessible = 1211 CompilerTests.javaSource( 1212 "other.UsesInaccessible", 1213 "package other;", 1214 "", 1215 "import javax.inject.Inject;", 1216 "", 1217 "public class UsesInaccessible {", 1218 " @Inject UsesInaccessible(Inaccessible inaccessible) {}", 1219 "}"); 1220 Source component = 1221 CompilerTests.javaSource( 1222 "test.TestComponent", 1223 "package test;", 1224 "", 1225 "import dagger.Component;", 1226 "import other.UsesInaccessible;", 1227 "", 1228 "@Component", 1229 "interface TestComponent {", 1230 " UsesInaccessible usesInaccessible();", 1231 "}"); 1232 1233 CompilerTests.daggerCompiler(foo, inaccessible, usesInaccessible, component) 1234 .withProcessingOptions(compilerMode.processorOptions()) 1235 .compile( 1236 subject -> { 1237 subject.hasErrorCount(0); 1238 subject.generatedSource( 1239 goldenFileRule.goldenSource("other/Inaccessible_MembersInjector")); 1240 subject.generatedSource( 1241 goldenFileRule.goldenSource("test/DaggerTestComponent")); 1242 }); 1243 } 1244 1245 @Test accessibleRawType_ofInaccessibleType()1246 public void accessibleRawType_ofInaccessibleType() throws Exception { 1247 Source inaccessible = 1248 CompilerTests.javaSource( 1249 "other.Inaccessible", 1250 "package other;", 1251 "", 1252 "class Inaccessible {}"); 1253 Source inaccessiblesModule = 1254 CompilerTests.javaSource( 1255 "other.InaccessiblesModule", 1256 "package other;", 1257 "", 1258 "import dagger.Module;", 1259 "import dagger.Provides;", 1260 "import java.util.ArrayList;", 1261 "import java.util.List;", 1262 "import javax.inject.Provider;", 1263 "import javax.inject.Singleton;", 1264 "", 1265 "@Module", 1266 "public class InaccessiblesModule {", 1267 // force Provider initialization 1268 " @Provides @Singleton static List<Inaccessible> inaccessibles() {", 1269 " return new ArrayList<>();", 1270 " }", 1271 "}"); 1272 Source usesInaccessibles = 1273 CompilerTests.javaSource( 1274 "other.UsesInaccessibles", 1275 "package other;", 1276 "", 1277 "import java.util.List;", 1278 "import javax.inject.Inject;", 1279 "", 1280 "public class UsesInaccessibles {", 1281 " @Inject UsesInaccessibles() {}", 1282 " @Inject List<Inaccessible> inaccessibles;", 1283 "}"); 1284 Source component = 1285 CompilerTests.javaSource( 1286 "test.TestComponent", 1287 "package test;", 1288 "", 1289 "import dagger.Component;", 1290 "import javax.inject.Singleton;", 1291 "import other.UsesInaccessibles;", 1292 "", 1293 "@Singleton", 1294 "@Component(modules = other.InaccessiblesModule.class)", 1295 "interface TestComponent {", 1296 " UsesInaccessibles usesInaccessibles();", 1297 "}"); 1298 1299 CompilerTests.daggerCompiler(inaccessible, inaccessiblesModule, usesInaccessibles, component) 1300 .withProcessingOptions(compilerMode.processorOptions()) 1301 .compile( 1302 subject -> { 1303 subject.hasErrorCount(0); 1304 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 1305 }); 1306 } 1307 1308 @Test publicSupertypeHiddenSubtype()1309 public void publicSupertypeHiddenSubtype() throws Exception { 1310 Source foo = 1311 CompilerTests.javaSource( 1312 "other.Foo", 1313 "package other;", 1314 "", 1315 "import javax.inject.Inject;", 1316 "", 1317 "class Foo {", 1318 " @Inject Foo() {}", 1319 "}"); 1320 Source supertype = 1321 CompilerTests.javaSource( 1322 "other.Supertype", 1323 "package other;", 1324 "", 1325 "import javax.inject.Inject;", 1326 "", 1327 "public class Supertype<T> {", 1328 " @Inject T t;", 1329 "}"); 1330 Source subtype = 1331 CompilerTests.javaSource( 1332 "other.Subtype", 1333 "package other;", 1334 "", 1335 "import javax.inject.Inject;", 1336 "", 1337 "class Subtype extends Supertype<Foo> {", 1338 " @Inject Subtype() {}", 1339 "}"); 1340 Source injectsSubtype = 1341 CompilerTests.javaSource( 1342 "other.InjectsSubtype", 1343 "package other;", 1344 "", 1345 "import javax.inject.Inject;", 1346 "", 1347 "public class InjectsSubtype {", 1348 " @Inject InjectsSubtype(Subtype s) {}", 1349 "}"); 1350 Source component = 1351 CompilerTests.javaSource( 1352 "test.TestComponent", 1353 "package test;", 1354 "", 1355 "import dagger.Component;", 1356 "", 1357 "@Component", 1358 "interface TestComponent {", 1359 " other.InjectsSubtype injectsSubtype();", 1360 "}"); 1361 1362 CompilerTests.daggerCompiler(foo, supertype, subtype, injectsSubtype, component) 1363 .withProcessingOptions(compilerMode.processorOptions()) 1364 .compile( 1365 subject -> { 1366 subject.hasErrorCount(0); 1367 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerTestComponent")); 1368 }); 1369 } 1370 1371 // Shows that we shouldn't create a members injector for a type that doesn't have 1372 // @Inject fields or @Inject constructor even if it extends and is extended by types that do. 1373 @Test middleClassNoFieldInjection()1374 public void middleClassNoFieldInjection() throws Exception { 1375 Source classA = 1376 CompilerTests.javaSource( 1377 "test.A", 1378 "package test;", 1379 "", 1380 "import javax.inject.Inject;", 1381 "", 1382 "class A extends B {", 1383 " @Inject String valueA;", 1384 "}"); 1385 Source classB = 1386 CompilerTests.javaSource( 1387 "test.B", 1388 "package test;", 1389 "", 1390 "class B extends C {", 1391 "}"); 1392 Source classC = 1393 CompilerTests.javaSource( 1394 "test.C", 1395 "package test;", 1396 "", 1397 "import javax.inject.Inject;", 1398 "", 1399 "class C { ", 1400 " @Inject String valueC;", 1401 "}"); 1402 1403 CompilerTests.daggerCompiler(classA, classB, classC) 1404 .withProcessingOptions(compilerMode.processorOptions()) 1405 .compile( 1406 subject -> { 1407 subject.hasErrorCount(0); 1408 subject.generatedSource(goldenFileRule.goldenSource("test/A_MembersInjector")); 1409 subject.generatedSource(goldenFileRule.goldenSource("test/C_MembersInjector")); 1410 1411 try { 1412 subject.generatedSourceFileWithPath("test/B_MembersInjector"); 1413 // Can't throw an assertion error since it would be caught. 1414 throw new IllegalStateException("Test generated a B_MembersInjector"); 1415 } catch (AssertionError expected) {} 1416 }); 1417 } 1418 1419 // Shows that we do generate a MembersInjector for a type that has an @Inject 1420 // constructor and that extends a type with @Inject fields, even if it has no local field 1421 // injection sites 1422 // TODO(erichang): Are these even used anymore? 1423 @Test testConstructorInjectedFieldInjection()1424 public void testConstructorInjectedFieldInjection() throws Exception { 1425 Source classA = 1426 CompilerTests.javaSource( 1427 "test.A", 1428 "package test;", 1429 "", 1430 "import javax.inject.Inject;", 1431 "", 1432 "class A extends B {", 1433 " @Inject A() {}", 1434 "}"); 1435 Source classB = 1436 CompilerTests.javaSource( 1437 "test.B", 1438 "package test;", 1439 "", 1440 "import javax.inject.Inject;", 1441 "", 1442 "class B { ", 1443 " @Inject String valueB;", 1444 "}"); 1445 1446 CompilerTests.daggerCompiler(classA, classB) 1447 .withProcessingOptions(compilerMode.processorOptions()) 1448 .compile( 1449 subject -> { 1450 subject.hasErrorCount(0); 1451 subject.generatedSource(goldenFileRule.goldenSource("test/A_MembersInjector")); 1452 subject.generatedSource(goldenFileRule.goldenSource("test/B_MembersInjector")); 1453 }); 1454 } 1455 1456 // Regression test for https://github.com/google/dagger/issues/3143 1457 @Test testMembersInjectionBindingExistsInParentComponent()1458 public void testMembersInjectionBindingExistsInParentComponent() throws Exception { 1459 Source component = 1460 CompilerTests.javaSource( 1461 "test.MyComponent", 1462 "package test;", 1463 "", 1464 "import dagger.Component;", 1465 "", 1466 "@Component(modules = MyComponentModule.class)", 1467 "public interface MyComponent {", 1468 " void inject(Bar bar);", 1469 "", 1470 " MySubcomponent subcomponent();", 1471 "}"); 1472 1473 Source subcomponent = 1474 CompilerTests.javaSource( 1475 "test.MySubcomponent", 1476 "package test;", 1477 "", 1478 "import dagger.Subcomponent;", 1479 "", 1480 "@Subcomponent(modules = MySubcomponentModule.class)", 1481 "interface MySubcomponent {", 1482 " Foo foo();", 1483 "}"); 1484 1485 Source foo = 1486 CompilerTests.javaSource( 1487 "test.Foo", 1488 "package test;", 1489 "", 1490 "import javax.inject.Inject;", 1491 "", 1492 "class Foo {", 1493 " @Inject Foo(Bar bar) {}", 1494 "}"); 1495 1496 Source bar = 1497 CompilerTests.javaSource( 1498 "test.Bar", 1499 "package test;", 1500 "", 1501 "import java.util.Set;", 1502 "import javax.inject.Inject;", 1503 "", 1504 "class Bar {", 1505 " @Inject Set<String> multibindingStrings;", 1506 " @Inject Bar() {}", 1507 "}"); 1508 1509 Source componentModule = 1510 CompilerTests.javaSource( 1511 "test.MyComponentModule", 1512 "package test;", 1513 "", 1514 "import dagger.Module;", 1515 "import dagger.Provides;", 1516 "import dagger.multibindings.IntoSet;", 1517 "", 1518 "@Module", 1519 "interface MyComponentModule {", 1520 " @Provides", 1521 " @IntoSet", 1522 " static String provideString() {", 1523 " return \"\";", 1524 " }", 1525 "}"); 1526 1527 Source subcomponentModule = 1528 CompilerTests.javaSource( 1529 "test.MySubcomponentModule", 1530 "package test;", 1531 "", 1532 "import dagger.Module;", 1533 "import dagger.Provides;", 1534 "import dagger.multibindings.IntoSet;", 1535 "", 1536 "@Module", 1537 "interface MySubcomponentModule {", 1538 " @Provides", 1539 " @IntoSet", 1540 " static String provideString() {", 1541 " return \"\";", 1542 " }", 1543 "}"); 1544 1545 CompilerTests.daggerCompiler( 1546 component, subcomponent, foo, bar, componentModule, subcomponentModule) 1547 .withProcessingOptions(compilerMode.processorOptions()) 1548 .compile( 1549 subject -> { 1550 subject.hasErrorCount(0); 1551 // Check that the injectBar() method is not shared across components. 1552 // We avoid sharing them in general because they may be different (e.g. in this case 1553 // we inject multibindings that are different across components). 1554 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent")); 1555 }); 1556 1557 } 1558 1559 // Test that if both a MembersInjectionBinding and ProvisionBinding both exist in the same 1560 // component they share the same inject methods rather than generating their own. 1561 @Test testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding()1562 public void testMembersInjectionBindingSharesInjectMethodsWithProvisionBinding() 1563 throws Exception { 1564 Source component = 1565 CompilerTests.javaSource( 1566 "test.MyComponent", 1567 "package test;", 1568 "", 1569 "import dagger.Component;", 1570 "", 1571 "@Component", 1572 "public interface MyComponent {", 1573 " Foo foo();", 1574 "", 1575 " void inject(Foo foo);", 1576 "}"); 1577 1578 Source foo = 1579 CompilerTests.javaSource( 1580 "test.Foo", 1581 "package test;", 1582 "", 1583 "import javax.inject.Inject;", 1584 "", 1585 "class Foo {", 1586 " @Inject Bar bar;", 1587 " @Inject Foo() {}", 1588 "}"); 1589 1590 Source bar = 1591 CompilerTests.javaSource( 1592 "test.Bar", 1593 "package test;", 1594 "", 1595 "import javax.inject.Inject;", 1596 "", 1597 "class Bar {", 1598 " @Inject Bar() {}", 1599 "}"); 1600 CompilerTests.daggerCompiler(component, foo, bar) 1601 .withProcessingOptions(compilerMode.processorOptions()) 1602 .compile( 1603 subject -> { 1604 subject.hasErrorCount(0); 1605 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent")); 1606 }); 1607 } 1608 1609 @Test kotlinNullableFieldInjection()1610 public void kotlinNullableFieldInjection() { 1611 Source file = 1612 CompilerTests.kotlinSource( 1613 "MyClass.kt", 1614 "package test;", 1615 "", 1616 "import javax.inject.Inject;", 1617 "", 1618 "class MyClass @Inject constructor() {", 1619 " @JvmField @Inject var nullableString: String? = null", 1620 " @JvmField @Inject var nullableObject: Any? = null", 1621 "}"); 1622 CompilerTests.daggerCompiler(file) 1623 .withProcessingOptions(compilerMode.processorOptions()) 1624 .compile( 1625 subject -> { 1626 subject.hasErrorCount(0); 1627 Source expectedSource = goldenFileRule.goldenSource("test/MyClass_MembersInjector"); 1628 subject.generatedSource( 1629 CompilerTests.backend(subject) == XProcessingEnv.Backend.KSP 1630 ? stripJetbrainsNullable(expectedSource) 1631 : expectedSource); 1632 }); 1633 } 1634 1635 @Test testMembersInjectionBindingWithNoInjectionSites()1636 public void testMembersInjectionBindingWithNoInjectionSites() throws Exception { 1637 Source component = 1638 CompilerTests.javaSource( 1639 "test.MyComponent", 1640 "package test;", 1641 "", 1642 "import dagger.Component;", 1643 "", 1644 "@Component", 1645 "public interface MyComponent {", 1646 " void inject(Foo foo);", 1647 "", 1648 " Foo injectAndReturn(Foo foo);", 1649 "}"); 1650 1651 Source foo = 1652 CompilerTests.javaSource( 1653 "test.Foo", 1654 "package test;", 1655 "", 1656 "class Foo {}"); 1657 1658 CompilerTests.daggerCompiler(component, foo) 1659 .withProcessingOptions(compilerMode.processorOptions()) 1660 .compile( 1661 subject -> { 1662 subject.hasErrorCount(0); 1663 subject.generatedSource(goldenFileRule.goldenSource("test/DaggerMyComponent")); 1664 }); 1665 } 1666 stripJetbrainsNullable(Source source)1667 private Source stripJetbrainsNullable(Source source) { 1668 return CompilerTests.javaSource( 1669 ((Source.JavaSource) source).getQName(), 1670 source 1671 .getContents() 1672 .replace("@Nullable ", "") 1673 .replace("import org.jetbrains.annotations.Nullable;\n", "")); 1674 } 1675 } 1676