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