1 /* 2 * Copyright (C) 2007 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.inject.assistedinject; 18 19 import static com.google.inject.Asserts.assertContains; 20 21 import com.google.common.collect.ImmutableSet; 22 import com.google.inject.AbstractModule; 23 import com.google.inject.Binding; 24 import com.google.inject.ConfigurationException; 25 import com.google.inject.CreationException; 26 import com.google.inject.Guice; 27 import com.google.inject.Inject; 28 import com.google.inject.Injector; 29 import com.google.inject.Key; 30 import com.google.inject.Provider; 31 import com.google.inject.TypeLiteral; 32 import com.google.inject.assistedinject.FactoryProviderTest.Equals.ComparisonMethod; 33 import com.google.inject.assistedinject.FactoryProviderTest.Equals.Impl; 34 import com.google.inject.name.Named; 35 import com.google.inject.name.Names; 36 import com.google.inject.spi.Dependency; 37 import com.google.inject.spi.HasDependencies; 38 import java.util.Collection; 39 import java.util.Collections; 40 import java.util.Set; 41 import junit.framework.TestCase; 42 43 /** 44 * @author jmourits@google.com (Jerome Mourits) 45 * @author jessewilson@google.com (Jesse Wilson) 46 */ 47 @SuppressWarnings("deprecation") 48 public class FactoryProviderTest extends TestCase { 49 50 private enum Color { 51 BLUE, 52 GREEN, 53 RED, 54 GRAY, 55 BLACK, 56 ORANGE, 57 PINK 58 } 59 testAssistedFactory()60 public void testAssistedFactory() { 61 Injector injector = 62 Guice.createInjector( 63 new AbstractModule() { 64 @Override 65 protected void configure() { 66 bind(Double.class).toInstance(5.0d); 67 bind(ColoredCarFactory.class) 68 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 69 } 70 }); 71 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 72 73 Mustang blueMustang = (Mustang) carFactory.create(Color.BLUE); 74 assertEquals(Color.BLUE, blueMustang.color); 75 assertEquals(5.0d, blueMustang.engineSize, 0.0); 76 77 Mustang redMustang = (Mustang) carFactory.create(Color.RED); 78 assertEquals(Color.RED, redMustang.color); 79 assertEquals(5.0d, redMustang.engineSize, 0.0); 80 } 81 testFactoryBindingDependencies()82 public void testFactoryBindingDependencies() { 83 Injector injector = 84 Guice.createInjector( 85 new AbstractModule() { 86 @Override 87 protected void configure() { 88 bind(Double.class).toInstance(5.0d); 89 bind(ColoredCarFactory.class) 90 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 91 } 92 }); 93 94 Binding<?> binding = injector.getBinding(ColoredCarFactory.class); 95 HasDependencies hasDependencies = (HasDependencies) binding; 96 assertEquals( 97 ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(double.class))), 98 hasDependencies.getDependencies()); 99 } 100 testAssistedFactoryWithAnnotations()101 public void testAssistedFactoryWithAnnotations() { 102 Injector injector = 103 Guice.createInjector( 104 new AbstractModule() { 105 @Override 106 protected void configure() { 107 bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250); 108 bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984); 109 bind(ColoredCarFactory.class) 110 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Camaro.class)); 111 } 112 }); 113 114 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 115 116 Camaro blueCamaro = (Camaro) carFactory.create(Color.BLUE); 117 assertEquals(Color.BLUE, blueCamaro.color); 118 assertEquals(1984, blueCamaro.modelYear); 119 assertEquals(250, blueCamaro.horsePower); 120 121 Camaro redCamaro = (Camaro) carFactory.create(Color.RED); 122 assertEquals(Color.RED, redCamaro.color); 123 assertEquals(1984, redCamaro.modelYear); 124 assertEquals(250, redCamaro.horsePower); 125 } 126 127 interface Car {} 128 129 interface ColoredCarFactory { create(Color color)130 Car create(Color color); 131 } 132 133 public static class Mustang implements Car { 134 private final double engineSize; 135 private final Color color; 136 137 @AssistedInject Mustang(double engineSize, @Assisted Color color)138 public Mustang(double engineSize, @Assisted Color color) { 139 this.engineSize = engineSize; 140 this.color = color; 141 } 142 } 143 144 public static class Camaro implements Car { 145 private final int horsePower; 146 private final int modelYear; 147 private final Color color; 148 149 @AssistedInject Camaro( @amed"horsePower") int horsePower, @Named("modelYear") int modelYear, @Assisted Color color)150 public Camaro( 151 @Named("horsePower") int horsePower, 152 @Named("modelYear") int modelYear, 153 @Assisted Color color) { 154 this.horsePower = horsePower; 155 this.modelYear = modelYear; 156 this.color = color; 157 } 158 } 159 160 interface SummerCarFactory { create(Color color, boolean convertable)161 Car create(Color color, boolean convertable); 162 createConvertible(Color color)163 Car createConvertible(Color color); 164 } 165 testFactoryWithMultipleMethods()166 public void testFactoryWithMultipleMethods() { 167 Injector injector = 168 Guice.createInjector( 169 new AbstractModule() { 170 @Override 171 protected void configure() { 172 bind(float.class).toInstance(140f); 173 bind(SummerCarFactory.class) 174 .toProvider(FactoryProvider.newFactory(SummerCarFactory.class, Corvette.class)); 175 } 176 }); 177 178 SummerCarFactory carFactory = injector.getInstance(SummerCarFactory.class); 179 180 Corvette blueCorvette = (Corvette) carFactory.createConvertible(Color.BLUE); 181 assertEquals(Color.BLUE, blueCorvette.color); 182 assertEquals(100f, blueCorvette.maxMph, 0.0f); 183 assertTrue(blueCorvette.isConvertable); 184 185 Corvette redCorvette = (Corvette) carFactory.create(Color.RED, false); 186 assertEquals(Color.RED, redCorvette.color); 187 assertEquals(140f, redCorvette.maxMph, 0.0f); 188 assertFalse(redCorvette.isConvertable); 189 } 190 191 public static class Corvette implements Car { 192 private boolean isConvertable; 193 private Color color; 194 private float maxMph; 195 196 @AssistedInject Corvette(@ssisted Color color)197 public Corvette(@Assisted Color color) { 198 this(color, 100f, true); 199 } 200 201 @SuppressWarnings("unused") Corvette(@ssisted Color color, @Assisted boolean isConvertable)202 public Corvette(@Assisted Color color, @Assisted boolean isConvertable) { 203 throw new IllegalStateException("Not an @AssistedInject constructor"); 204 } 205 206 @AssistedInject Corvette(@ssisted Color color, Float maxMph, @Assisted boolean isConvertable)207 public Corvette(@Assisted Color color, Float maxMph, @Assisted boolean isConvertable) { 208 this.isConvertable = isConvertable; 209 this.color = color; 210 this.maxMph = maxMph; 211 } 212 } 213 testFactoryMethodsMismatch()214 public void testFactoryMethodsMismatch() { 215 try { 216 FactoryProvider.newFactory(SummerCarFactory.class, Beetle.class); 217 fail(); 218 } catch (ConfigurationException e) { 219 assertContains(e.getMessage(), "Constructor mismatch"); 220 } 221 } 222 223 public static class Beetle implements Car { 224 @AssistedInject 225 @SuppressWarnings("unused") Beetle(@ssisted Color color)226 public Beetle(@Assisted Color color) { 227 throw new IllegalStateException("Conflicting constructors"); 228 } 229 230 @AssistedInject 231 @SuppressWarnings("unused") Beetle(@ssisted Color color, @Assisted boolean isConvertable)232 public Beetle(@Assisted Color color, @Assisted boolean isConvertable) { 233 throw new IllegalStateException("Conflicting constructors"); 234 } 235 236 @AssistedInject 237 @SuppressWarnings("unused") Beetle(@ssisted Color color, @Assisted boolean isConvertable, float maxMph)238 public Beetle(@Assisted Color color, @Assisted boolean isConvertable, float maxMph) { 239 throw new IllegalStateException("Conflicting constructors"); 240 } 241 } 242 testMethodsAndFieldsGetInjected()243 public void testMethodsAndFieldsGetInjected() { 244 Injector injector = 245 Guice.createInjector( 246 new AbstractModule() { 247 @Override 248 protected void configure() { 249 bind(String.class).toInstance("turbo"); 250 bind(int.class).toInstance(911); 251 bind(double.class).toInstance(50000d); 252 bind(ColoredCarFactory.class) 253 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Porshe.class)); 254 } 255 }); 256 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 257 258 Porshe grayPorshe = (Porshe) carFactory.create(Color.GRAY); 259 assertEquals(Color.GRAY, grayPorshe.color); 260 assertEquals(50000d, grayPorshe.price, 0.0); 261 assertEquals(911, grayPorshe.model); 262 assertEquals("turbo", grayPorshe.name); 263 } 264 265 public static class Porshe implements Car { 266 private final Color color; 267 private final double price; 268 private @Inject String name; 269 private int model; 270 271 @AssistedInject Porshe(@ssisted Color color, double price)272 public Porshe(@Assisted Color color, double price) { 273 this.color = color; 274 this.price = price; 275 } 276 277 @Inject setModel(int model)278 void setModel(int model) { 279 this.model = model; 280 } 281 } 282 testProviderInjection()283 public void testProviderInjection() { 284 Injector injector = 285 Guice.createInjector( 286 new AbstractModule() { 287 @Override 288 protected void configure() { 289 bind(String.class).toInstance("trans am"); 290 bind(ColoredCarFactory.class) 291 .toProvider( 292 FactoryProvider.newFactory(ColoredCarFactory.class, Firebird.class)); 293 } 294 }); 295 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 296 297 Firebird blackFirebird = (Firebird) carFactory.create(Color.BLACK); 298 assertEquals(Color.BLACK, blackFirebird.color); 299 assertEquals("trans am", blackFirebird.modifiersProvider.get()); 300 } 301 302 public static class Firebird implements Car { 303 private final Provider<String> modifiersProvider; 304 private final Color color; 305 306 @AssistedInject Firebird(Provider<String> modifiersProvider, @Assisted Color color)307 public Firebird(Provider<String> modifiersProvider, @Assisted Color color) { 308 this.modifiersProvider = modifiersProvider; 309 this.color = color; 310 } 311 } 312 testTypeTokenInjection()313 public void testTypeTokenInjection() { 314 Injector injector = 315 Guice.createInjector( 316 new AbstractModule() { 317 @Override 318 protected void configure() { 319 bind(new TypeLiteral<Set<String>>() {}) 320 .toInstance(Collections.singleton("Flux Capacitor")); 321 bind(new TypeLiteral<Set<Integer>>() {}).toInstance(Collections.singleton(88)); 322 bind(ColoredCarFactory.class) 323 .toProvider( 324 FactoryProvider.newFactory(ColoredCarFactory.class, DeLorean.class)); 325 } 326 }); 327 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 328 329 DeLorean deLorean = (DeLorean) carFactory.create(Color.GRAY); 330 assertEquals(Color.GRAY, deLorean.color); 331 assertEquals("Flux Capacitor", deLorean.features.iterator().next()); 332 assertEquals(Integer.valueOf(88), deLorean.featureActivationSpeeds.iterator().next()); 333 } 334 335 public static class DeLorean implements Car { 336 private final Set<String> features; 337 private final Set<Integer> featureActivationSpeeds; 338 private final Color color; 339 340 @AssistedInject DeLorean( Set<String> extraFeatures, Set<Integer> featureActivationSpeeds, @Assisted Color color)341 public DeLorean( 342 Set<String> extraFeatures, Set<Integer> featureActivationSpeeds, @Assisted Color color) { 343 this.features = extraFeatures; 344 this.featureActivationSpeeds = featureActivationSpeeds; 345 this.color = color; 346 } 347 } 348 testTypeTokenProviderInjection()349 public void testTypeTokenProviderInjection() { 350 Injector injector = 351 Guice.createInjector( 352 new AbstractModule() { 353 @Override 354 protected void configure() { 355 bind(new TypeLiteral<Set<String>>() {}).toInstance(Collections.singleton("Datsun")); 356 bind(ColoredCarFactory.class) 357 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Z.class)); 358 } 359 }); 360 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 361 362 Z orangeZ = (Z) carFactory.create(Color.ORANGE); 363 assertEquals(Color.ORANGE, orangeZ.color); 364 assertEquals("Datsun", orangeZ.manufacturersProvider.get().iterator().next()); 365 } 366 367 public static class Z implements Car { 368 private final Provider<Set<String>> manufacturersProvider; 369 private final Color color; 370 371 @AssistedInject Z(Provider<Set<String>> manufacturersProvider, @Assisted Color color)372 public Z(Provider<Set<String>> manufacturersProvider, @Assisted Color color) { 373 this.manufacturersProvider = manufacturersProvider; 374 this.color = color; 375 } 376 } 377 378 public static class Prius implements Car { 379 @SuppressWarnings("unused") 380 private final Color color; 381 382 @AssistedInject Prius(@ssisted Color color)383 private Prius(@Assisted Color color) { 384 this.color = color; 385 } 386 } 387 testAssistInjectionInNonPublicConstructor()388 public void testAssistInjectionInNonPublicConstructor() { 389 Injector injector = 390 Guice.createInjector( 391 new AbstractModule() { 392 @Override 393 protected void configure() { 394 bind(ColoredCarFactory.class) 395 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Prius.class)); 396 } 397 }); 398 injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE); 399 } 400 401 public static class ExplodingCar implements Car { 402 @AssistedInject ExplodingCar(@uppressWarnings"unused") @ssisted Color color)403 public ExplodingCar(@SuppressWarnings("unused") @Assisted Color color) { 404 throw new IllegalStateException("kaboom!"); 405 } 406 } 407 testExceptionDuringConstruction()408 public void testExceptionDuringConstruction() { 409 Injector injector = 410 Guice.createInjector( 411 new AbstractModule() { 412 @Override 413 protected void configure() { 414 bind(ColoredCarFactory.class) 415 .toProvider( 416 FactoryProvider.newFactory(ColoredCarFactory.class, ExplodingCar.class)); 417 } 418 }); 419 try { 420 injector.getInstance(ColoredCarFactory.class).create(Color.ORANGE); 421 fail(); 422 } catch (IllegalStateException e) { 423 assertEquals("kaboom!", e.getMessage()); 424 } 425 } 426 427 public static class DefectiveCar implements Car { 428 @AssistedInject DefectiveCar()429 public DefectiveCar() throws ExplosionException { 430 throw new ExplosionException(); 431 } 432 } 433 434 public static class ExplosionException extends Exception {} 435 436 public static class FireException extends Exception {} 437 438 public interface DefectiveCarFactoryWithNoExceptions { createCar()439 Car createCar(); 440 } 441 442 public interface DefectiveCarFactory { createCar()443 Car createCar() throws FireException; 444 } 445 testFactoryMethodMustDeclareAllConstructorExceptions()446 public void testFactoryMethodMustDeclareAllConstructorExceptions() { 447 try { 448 FactoryProvider.newFactory(DefectiveCarFactoryWithNoExceptions.class, DefectiveCar.class); 449 fail(); 450 } catch (ConfigurationException expected) { 451 assertContains(expected.getMessage(), "no compatible exception is thrown"); 452 } 453 } 454 455 public interface CorrectDefectiveCarFactory { createCar()456 Car createCar() throws FireException, ExplosionException; 457 } 458 testConstructorExceptionsAreThrownByFactory()459 public void testConstructorExceptionsAreThrownByFactory() { 460 Injector injector = 461 Guice.createInjector( 462 new AbstractModule() { 463 @Override 464 protected void configure() { 465 bind(CorrectDefectiveCarFactory.class) 466 .toProvider( 467 FactoryProvider.newFactory( 468 CorrectDefectiveCarFactory.class, DefectiveCar.class)); 469 } 470 }); 471 try { 472 injector.getInstance(CorrectDefectiveCarFactory.class).createCar(); 473 fail(); 474 } catch (FireException e) { 475 fail(); 476 } catch (ExplosionException expected) { 477 } 478 } 479 480 public static class MultipleConstructorDefectiveCar implements Car { 481 @AssistedInject MultipleConstructorDefectiveCar()482 public MultipleConstructorDefectiveCar() throws ExplosionException { 483 throw new ExplosionException(); 484 } 485 486 @AssistedInject MultipleConstructorDefectiveCar(@uppressWarnings"unused") @ssisted Color c)487 public MultipleConstructorDefectiveCar(@SuppressWarnings("unused") @Assisted Color c) 488 throws FireException { 489 throw new FireException(); 490 } 491 } 492 493 public interface MultipleConstructorDefectiveCarFactory { createCar()494 Car createCar() throws ExplosionException; 495 createCar(Color r)496 Car createCar(Color r) throws FireException; 497 } 498 testMultipleConstructorExceptionMatching()499 public void testMultipleConstructorExceptionMatching() { 500 Injector injector = 501 Guice.createInjector( 502 new AbstractModule() { 503 @Override 504 protected void configure() { 505 bind(MultipleConstructorDefectiveCarFactory.class) 506 .toProvider( 507 FactoryProvider.newFactory( 508 MultipleConstructorDefectiveCarFactory.class, 509 MultipleConstructorDefectiveCar.class)); 510 } 511 }); 512 MultipleConstructorDefectiveCarFactory factory = 513 injector.getInstance(MultipleConstructorDefectiveCarFactory.class); 514 try { 515 factory.createCar(); 516 fail(); 517 } catch (ExplosionException expected) { 518 } 519 520 try { 521 factory.createCar(Color.RED); 522 fail(); 523 } catch (FireException expected) { 524 } 525 } 526 527 public static class WildcardCollection { 528 529 public interface Factory { create(Collection<?> items)530 WildcardCollection create(Collection<?> items); 531 } 532 533 @AssistedInject WildcardCollection(@uppressWarnings"unused") @ssisted Collection<?> items)534 public WildcardCollection(@SuppressWarnings("unused") @Assisted Collection<?> items) {} 535 } 536 testWildcardGenerics()537 public void testWildcardGenerics() { 538 Injector injector = 539 Guice.createInjector( 540 new AbstractModule() { 541 @Override 542 protected void configure() { 543 bind(WildcardCollection.Factory.class) 544 .toProvider( 545 FactoryProvider.newFactory( 546 WildcardCollection.Factory.class, WildcardCollection.class)); 547 } 548 }); 549 WildcardCollection.Factory factory = injector.getInstance(WildcardCollection.Factory.class); 550 factory.create(Collections.emptyList()); 551 } 552 553 public static class SteeringWheel {} 554 555 public static class Fiat implements Car { 556 @SuppressWarnings("unused") 557 private final SteeringWheel steeringWheel; 558 559 @SuppressWarnings("unused") 560 private final Color color; 561 562 @AssistedInject Fiat(SteeringWheel steeringWheel, @Assisted Color color)563 public Fiat(SteeringWheel steeringWheel, @Assisted Color color) { 564 this.steeringWheel = steeringWheel; 565 this.color = color; 566 } 567 } 568 testFactoryWithImplicitBindings()569 public void testFactoryWithImplicitBindings() { 570 Injector injector = 571 Guice.createInjector( 572 new AbstractModule() { 573 @Override 574 protected void configure() { 575 bind(ColoredCarFactory.class) 576 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Fiat.class)); 577 } 578 }); 579 580 ColoredCarFactory coloredCarFactory = injector.getInstance(ColoredCarFactory.class); 581 Fiat fiat = (Fiat) coloredCarFactory.create(Color.GREEN); 582 assertEquals(Color.GREEN, fiat.color); 583 assertNotNull(fiat.steeringWheel); 584 } 585 testFactoryFailsWithMissingBinding()586 public void testFactoryFailsWithMissingBinding() { 587 try { 588 Guice.createInjector( 589 new AbstractModule() { 590 @Override 591 protected void configure() { 592 bind(ColoredCarFactory.class) 593 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 594 } 595 }); 596 fail(); 597 } catch (CreationException expected) { 598 assertContains( 599 expected.getMessage(), 600 "1) Parameter of type 'double' is not injectable or annotated with @Assisted"); 601 } 602 } 603 604 @SuppressWarnings("SelfEquals") testMethodsDeclaredInObject()605 public void testMethodsDeclaredInObject() { 606 Injector injector = 607 Guice.createInjector( 608 new AbstractModule() { 609 @Override 610 protected void configure() { 611 bind(Double.class).toInstance(5.0d); 612 bind(ColoredCarFactory.class) 613 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 614 } 615 }); 616 617 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 618 619 carFactory.equals(carFactory); 620 carFactory.hashCode(); 621 carFactory.toString(); 622 } 623 testAssistedInjectConstructorAndAssistedFactoryParameterMustNotMix()624 public void testAssistedInjectConstructorAndAssistedFactoryParameterMustNotMix() { 625 try { 626 Guice.createInjector( 627 new AbstractModule() { 628 @Override 629 protected void configure() { 630 bind(Double.class).toInstance(5.0d); 631 bind(AssistedParamsFactory.class) 632 .toProvider( 633 FactoryProvider.newFactory(AssistedParamsFactory.class, Mustang.class)); 634 } 635 }); 636 fail(); 637 } catch (CreationException expected) { 638 assertContains( 639 expected.getMessage(), 640 "Factory method " 641 + AssistedParamsFactory.class.getName() 642 + ".create() has an @Assisted parameter, which " 643 + "is incompatible with the deprecated @AssistedInject annotation."); 644 } 645 } 646 647 interface AssistedParamsFactory { create(@ssisted Color color)648 Car create(@Assisted Color color); 649 } 650 651 interface GenericColoredCarFactory<T extends Car> { create(Color color)652 T create(Color color); 653 } 654 testGenericAssistedFactory()655 public void testGenericAssistedFactory() { 656 final TypeLiteral<GenericColoredCarFactory<Mustang>> mustangTypeLiteral = 657 new TypeLiteral<GenericColoredCarFactory<Mustang>>() {}; 658 final TypeLiteral<GenericColoredCarFactory<Camaro>> camaroTypeLiteral = 659 new TypeLiteral<GenericColoredCarFactory<Camaro>>() {}; 660 661 Injector injector = 662 Guice.createInjector( 663 new AbstractModule() { 664 @Override 665 protected void configure() { 666 bind(Double.class).toInstance(5.0d); 667 bind(int.class).annotatedWith(Names.named("horsePower")).toInstance(250); 668 bind(int.class).annotatedWith(Names.named("modelYear")).toInstance(1984); 669 bind(mustangTypeLiteral) 670 .toProvider( 671 FactoryProvider.newFactory( 672 mustangTypeLiteral, TypeLiteral.get(Mustang.class))); 673 bind(camaroTypeLiteral) 674 .toProvider( 675 FactoryProvider.newFactory( 676 camaroTypeLiteral, TypeLiteral.get(Camaro.class))); 677 } 678 }); 679 680 GenericColoredCarFactory<Mustang> mustangFactory = 681 injector.getInstance(Key.get(mustangTypeLiteral)); 682 GenericColoredCarFactory<Camaro> camaroFactory = 683 injector.getInstance(Key.get(camaroTypeLiteral)); 684 685 Mustang blueMustang = mustangFactory.create(Color.BLUE); 686 assertEquals(Color.BLUE, blueMustang.color); 687 assertEquals(5.0d, blueMustang.engineSize, 0.0); 688 689 Camaro redCamaro = camaroFactory.create(Color.RED); 690 assertEquals(Color.RED, redCamaro.color); 691 assertEquals(1984, redCamaro.modelYear); 692 assertEquals(250, redCamaro.horsePower); 693 } 694 695 @SuppressWarnings("unused") 696 public interface Insurance<T extends Car> {} 697 698 public static class MustangInsurance implements Insurance<Mustang> { 699 private final double premium; 700 private final double limit; 701 702 @SuppressWarnings("unused") 703 private Mustang car; 704 705 @AssistedInject MustangInsurance( @amed"lowLimit") double limit, @Assisted Mustang car, @Assisted double premium)706 public MustangInsurance( 707 @Named("lowLimit") double limit, @Assisted Mustang car, @Assisted double premium) { 708 this.premium = premium; 709 this.limit = limit; 710 this.car = car; 711 } 712 sell()713 public void sell() {} 714 } 715 716 public static class CamaroInsurance implements Insurance<Camaro> { 717 private final double premium; 718 private final double limit; 719 720 @SuppressWarnings("unused") 721 private Camaro car; 722 723 @AssistedInject CamaroInsurance( @amed"highLimit") double limit, @Assisted Camaro car, @Assisted double premium)724 public CamaroInsurance( 725 @Named("highLimit") double limit, @Assisted Camaro car, @Assisted double premium) { 726 this.premium = premium; 727 this.limit = limit; 728 this.car = car; 729 } 730 sell()731 public void sell() {} 732 } 733 734 public interface MustangInsuranceFactory { create(Mustang car, double premium)735 public Insurance<Mustang> create(Mustang car, double premium); 736 } 737 738 public interface CamaroInsuranceFactory { create(Camaro car, double premium)739 public Insurance<Camaro> create(Camaro car, double premium); 740 } 741 testAssistedFactoryForConcreteType()742 public void testAssistedFactoryForConcreteType() { 743 744 Injector injector = 745 Guice.createInjector( 746 new AbstractModule() { 747 @Override 748 protected void configure() { 749 bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d); 750 bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d); 751 bind(MustangInsuranceFactory.class) 752 .toProvider( 753 FactoryProvider.newFactory( 754 MustangInsuranceFactory.class, MustangInsurance.class)); 755 bind(CamaroInsuranceFactory.class) 756 .toProvider( 757 FactoryProvider.newFactory( 758 CamaroInsuranceFactory.class, CamaroInsurance.class)); 759 } 760 }); 761 762 MustangInsuranceFactory mustangInsuranceFactory = 763 injector.getInstance(MustangInsuranceFactory.class); 764 CamaroInsuranceFactory camaroInsuranceFactory = 765 injector.getInstance(CamaroInsuranceFactory.class); 766 767 Mustang mustang = new Mustang(5000d, Color.BLACK); 768 MustangInsurance mustangPolicy = 769 (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d); 770 assertEquals(800.0d, mustangPolicy.premium, 0.0); 771 assertEquals(50000.0d, mustangPolicy.limit, 0.0); 772 773 Camaro camaro = new Camaro(3000, 1967, Color.BLUE); 774 CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d); 775 assertEquals(800.0d, camaroPolicy.premium, 0.0); 776 assertEquals(100000.0d, camaroPolicy.limit, 0.0); 777 } 778 779 public interface InsuranceFactory<T extends Car> { create(T car, double premium)780 public Insurance<T> create(T car, double premium); 781 } 782 testAssistedFactoryForParameterizedType()783 public void testAssistedFactoryForParameterizedType() { 784 final TypeLiteral<InsuranceFactory<Mustang>> mustangInsuranceFactoryType = 785 new TypeLiteral<InsuranceFactory<Mustang>>() {}; 786 final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType = 787 new TypeLiteral<InsuranceFactory<Camaro>>() {}; 788 789 Injector injector = 790 Guice.createInjector( 791 new AbstractModule() { 792 @Override 793 protected void configure() { 794 bind(Double.class).annotatedWith(Names.named("lowLimit")).toInstance(50000.0d); 795 bind(Double.class).annotatedWith(Names.named("highLimit")).toInstance(100000.0d); 796 bind(mustangInsuranceFactoryType) 797 .toProvider( 798 FactoryProvider.newFactory( 799 mustangInsuranceFactoryType, TypeLiteral.get(MustangInsurance.class))); 800 bind(camaroInsuranceFactoryType) 801 .toProvider( 802 FactoryProvider.newFactory( 803 camaroInsuranceFactoryType, TypeLiteral.get(CamaroInsurance.class))); 804 } 805 }); 806 807 InsuranceFactory<Mustang> mustangInsuranceFactory = 808 injector.getInstance(Key.get(mustangInsuranceFactoryType)); 809 InsuranceFactory<Camaro> camaroInsuranceFactory = 810 injector.getInstance(Key.get(camaroInsuranceFactoryType)); 811 812 Mustang mustang = new Mustang(5000d, Color.BLACK); 813 MustangInsurance mustangPolicy = 814 (MustangInsurance) mustangInsuranceFactory.create(mustang, 800.0d); 815 assertEquals(800.0d, mustangPolicy.premium, 0.0); 816 assertEquals(50000.0d, mustangPolicy.limit, 0.0); 817 818 Camaro camaro = new Camaro(3000, 1967, Color.BLUE); 819 CamaroInsurance camaroPolicy = (CamaroInsurance) camaroInsuranceFactory.create(camaro, 800.0d); 820 assertEquals(800.0d, camaroPolicy.premium, 0.0); 821 assertEquals(100000.0d, camaroPolicy.limit, 0.0); 822 } 823 824 public static class AutoInsurance<T extends Car> implements Insurance<T> { 825 private final double premium; 826 private final double limit; 827 private final T car; 828 829 @AssistedInject AutoInsurance(double limit, @Assisted T car, @Assisted double premium)830 public AutoInsurance(double limit, @Assisted T car, @Assisted double premium) { 831 this.limit = limit; 832 this.car = car; 833 this.premium = premium; 834 } 835 sell()836 public void sell() {} 837 } 838 testAssistedFactoryForTypeVariableParameters()839 public void testAssistedFactoryForTypeVariableParameters() { 840 final TypeLiteral<InsuranceFactory<Camaro>> camaroInsuranceFactoryType = 841 new TypeLiteral<InsuranceFactory<Camaro>>() {}; 842 843 Injector injector = 844 Guice.createInjector( 845 new AbstractModule() { 846 @Override 847 protected void configure() { 848 bind(Double.class).toInstance(50000.0d); 849 bind(camaroInsuranceFactoryType) 850 .toProvider( 851 FactoryProvider.newFactory( 852 camaroInsuranceFactoryType, 853 new TypeLiteral<AutoInsurance<Camaro>>() {})); 854 } 855 }); 856 857 InsuranceFactory<Camaro> camaroInsuranceFactory = 858 injector.getInstance(Key.get(camaroInsuranceFactoryType)); 859 860 Camaro camaro = new Camaro(3000, 1967, Color.BLUE); 861 AutoInsurance<?> camaroPolicy = 862 (AutoInsurance<?>) camaroInsuranceFactory.create(camaro, 800.0d); 863 assertEquals(800.0d, camaroPolicy.premium, 0.0); 864 assertEquals(50000.0d, camaroPolicy.limit, 0.0); 865 assertEquals(camaro, camaroPolicy.car); 866 } 867 testDuplicateAssistedFactoryBinding()868 public void testDuplicateAssistedFactoryBinding() { 869 Injector injector = 870 Guice.createInjector( 871 new AbstractModule() { 872 @Override 873 protected void configure() { 874 bind(Double.class).toInstance(5.0d); 875 bind(ColoredCarFactory.class) 876 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 877 bind(ColoredCarFactory.class) 878 .toProvider(FactoryProvider.newFactory(ColoredCarFactory.class, Mustang.class)); 879 } 880 }); 881 ColoredCarFactory carFactory = injector.getInstance(ColoredCarFactory.class); 882 883 Mustang blueMustang = (Mustang) carFactory.create(Color.BLUE); 884 assertEquals(Color.BLUE, blueMustang.color); 885 assertEquals(5.0d, blueMustang.engineSize, 0.0); 886 887 Mustang redMustang = (Mustang) carFactory.create(Color.RED); 888 assertEquals(Color.RED, redMustang.color); 889 assertEquals(5.0d, redMustang.engineSize, 0.0); 890 } 891 892 public interface Equals { 893 894 enum ComparisonMethod { 895 SHALLOW, 896 DEEP; 897 } 898 899 interface Factory { equals(Equals.ComparisonMethod comparisonMethod)900 Equals equals(Equals.ComparisonMethod comparisonMethod); 901 } 902 903 public static class Impl implements Equals { 904 private final double sigma; 905 private final ComparisonMethod comparisonMethod; 906 907 @Inject Impl(double sigma, @Assisted ComparisonMethod comparisonMethod)908 public Impl(double sigma, @Assisted ComparisonMethod comparisonMethod) { 909 this.sigma = sigma; 910 this.comparisonMethod = comparisonMethod; 911 } 912 } 913 } 914 testFactoryMethodCalledEquals()915 public void testFactoryMethodCalledEquals() { 916 Injector injector = 917 Guice.createInjector( 918 new AbstractModule() { 919 @Override 920 protected void configure() { 921 bind(Double.class).toInstance(0.01d); 922 bind(Equals.Factory.class) 923 .toProvider( 924 FactoryProvider.newFactory(Equals.Factory.class, Equals.Impl.class)); 925 } 926 }); 927 Equals.Factory equalsFactory = injector.getInstance(Equals.Factory.class); 928 Equals.Impl shallowEquals = (Impl) equalsFactory.equals(ComparisonMethod.SHALLOW); 929 assertEquals(ComparisonMethod.SHALLOW, shallowEquals.comparisonMethod); 930 assertEquals(0.01d, shallowEquals.sigma, 0.0); 931 } 932 } 933