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