001/***************************************************************************** 002 * Copyright (c) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant * 009 *****************************************************************************/ 010package org.picocontainer; 011 012import org.junit.Test; 013import org.picocontainer.behaviors.Caching; 014import org.picocontainer.containers.EmptyPicoContainer; 015import org.picocontainer.injectors.AbstractInjector; 016import org.picocontainer.injectors.ConstructorInjection; 017import org.picocontainer.injectors.ConstructorInjector; 018import org.picocontainer.monitors.NullComponentMonitor; 019import org.picocontainer.monitors.WriterComponentMonitor; 020import org.picocontainer.parameters.ConstantParameter; 021import org.picocontainer.tck.AbstractPicoContainerTest; 022import org.picocontainer.testmodel.DecoratedTouchable; 023import org.picocontainer.testmodel.DependsOnTouchable; 024import org.picocontainer.testmodel.SimpleTouchable; 025import org.picocontainer.testmodel.Touchable; 026 027import java.io.Serializable; 028import java.io.StringWriter; 029import java.lang.reflect.Constructor; 030import java.lang.reflect.Member; 031import java.lang.reflect.Type; 032import java.util.ArrayList; 033import java.util.Collection; 034import java.util.HashMap; 035import java.util.HashSet; 036import java.util.LinkedList; 037import java.util.List; 038import java.util.Map; 039import java.util.Properties; 040 041import static org.junit.Assert.assertEquals; 042import static org.junit.Assert.assertNotNull; 043import static org.junit.Assert.assertNotSame; 044import static org.junit.Assert.assertSame; 045import static org.junit.Assert.assertTrue; 046import static org.junit.Assert.fail; 047import static org.picocontainer.Characteristics.CDI; 048import static org.picocontainer.Characteristics.SDI; 049 050/** 051 * @author Aslak Hellesøp;y 052 * @author Paul Hammant 053 * @author Ward Cunningham 054 * @author Mauro Talevi 055 */ 056@SuppressWarnings("serial") 057public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTest { 058 059 protected MutablePicoContainer createPicoContainer(PicoContainer parent) { 060 return new DefaultPicoContainer(parent); 061 } 062 063 protected Properties[] getProperties() { 064 return new Properties[0]; 065 } 066 067 @Test public void testInstantiationWithNullComponentFactory() { 068 try { 069 new DefaultPicoContainer((ComponentFactory) null, null); 070 fail("NPE expected"); 071 } catch (NullPointerException e) { 072 // expected 073 } 074 } 075 076 @Test public void testUpDownDependenciesCannotBeFollowed() { 077 MutablePicoContainer parent = createPicoContainer(null); 078 parent.setName("parent"); 079 MutablePicoContainer child = createPicoContainer(parent); 080 child.setName("child"); 081 082 // ComponentF -> ComponentA -> ComponentB+C 083 child.addComponent(ComponentF.class); 084 parent.addComponent(ComponentA.class); 085 child.addComponent(new ComponentB()); 086 child.addComponent(new ComponentC()); 087 088 try { 089 Object f = child.getComponent(ComponentF.class); 090 fail("Thrown " 091 + AbstractInjector.UnsatisfiableDependenciesException.class 092 .getName() + " expected"); 093 } catch (final AbstractInjector.UnsatisfiableDependenciesException e) { 094 assertEquals("A has unsatisfied dependency 'class C' for constructor 'public A(B,C)' from parent:1<|", e.getMessage().replace("org.picocontainer.tck.AbstractPicoContainerTest$Component","")); 095 } 096 097 } 098 099 @Test public void testComponentsCanBeRemovedByInstance() { 100 MutablePicoContainer pico = createPicoContainer(null); 101 pico.addComponent(HashMap.class); 102 pico.addComponent(ArrayList.class); 103 List list = pico.getComponent(List.class); 104 pico.removeComponentByInstance(list); 105 assertEquals(1, pico.getComponentAdapters().size()); 106 assertEquals(1, pico.getComponents().size()); 107 assertEquals(HashMap.class, pico.getComponent(Serializable.class) 108 .getClass()); 109 } 110 111 @Test public void testComponentInstancesListIsReturnedForNullType() { 112 MutablePicoContainer pico = createPicoContainer(null); 113 List componentInstances = pico.getComponents(null); 114 assertNotNull(componentInstances); 115 assertEquals(0, componentInstances.size()); 116 } 117 118 @Test public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() { 119 MutablePicoContainer pico = createPicoContainer(null); 120 pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO); 121 pico.addComponent(ArrayList.class, ArrayList.class, Parameter.ZERO); 122 assertEquals(ArrayList.class, pico 123 .getComponent((Class) ArrayList.class).getClass()); 124 } 125 126 127 /* 128 * When pico tries to resolve DecoratedTouchable it find as dependency 129 * itself and SimpleTouchable. Problem is basically the same as above. Pico 130 * should not consider self as solution. 131 * 132 * JS fixed it ( PICO-222 ) KP 133 */ 134 @Test public void testUnambiguouSelfDependency() { 135 MutablePicoContainer pico = createPicoContainer(null); 136 pico.addComponent(SimpleTouchable.class); 137 pico.addComponent(DecoratedTouchable.class); 138 Touchable t = (Touchable) pico 139 .getComponent((Object) DecoratedTouchable.class); 140 assertNotNull(t); 141 } 142 143 @Test public void testPicoUsedInBuilderStyle() { 144 MutablePicoContainer pico = createPicoContainer(null); 145 Touchable t = pico.change(Characteristics.CACHE).addComponent( 146 SimpleTouchable.class).addComponent(DecoratedTouchable.class) 147 .getComponent(DecoratedTouchable.class); 148 SimpleTouchable t2 = pico.getComponent(SimpleTouchable.class); 149 assertNotNull(t); 150 assertNotNull(t2); 151 t.touch(); 152 assertTrue(t2.wasTouched); 153 } 154 155 public static class Thingie { 156 public Thingie(List c) { 157 assertNotNull(c); 158 } 159 } 160 161 @Test public void testThangCanBeInstantiatedWithArrayList() { 162 MutablePicoContainer pico = new DefaultPicoContainer(); 163 pico.addComponent(Thingie.class); 164 pico.addComponent(ArrayList.class); 165 assertNotNull(pico.getComponent(Thingie.class)); 166 } 167 168 @Test public void testGetComponentAdaptersOfTypeNullReturnsEmptyList() { 169 DefaultPicoContainer pico = new DefaultPicoContainer(); 170 List adapters = pico.getComponentAdapters(null); 171 assertNotNull(adapters); 172 assertEquals(0, adapters.size()); 173 } 174 175 public static class Service { 176 } 177 178 public static final class TransientComponent { 179 private final Service service; 180 181 public TransientComponent(Service service) { 182 this.service = service; 183 } 184 } 185 186 @Test public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() { 187 188 DefaultPicoContainer picoContainer = new DefaultPicoContainer( 189 new Caching().wrap(new ConstructorInjection())); 190 191 picoContainer.addComponent(Service.class); 192 picoContainer.as(Characteristics.NO_CACHE).addAdapter( 193 new ConstructorInjector(TransientComponent.class, 194 TransientComponent.class, null, 195 new NullComponentMonitor(), false)); 196 TransientComponent c1 = picoContainer 197 .getComponent(TransientComponent.class); 198 TransientComponent c2 = picoContainer 199 .getComponent(TransientComponent.class); 200 assertNotSame(c1, c2); 201 assertSame(c1.service, c2.service); 202 } 203 204 public static class DependsOnCollection { 205 public DependsOnCollection(Collection c) { 206 } 207 } 208 209 @Test public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() { 210 MutablePicoContainer pico = this.createPicoContainer(null); 211 pico.addComponent(new ArrayList()); 212 pico.addComponent(new LinkedList()); 213 pico.addComponent(DependsOnCollection.class); 214 try { 215 pico.getComponent(DependsOnCollection.class); 216 fail(); 217 } catch (AbstractInjector.AmbiguousComponentResolutionException expected) { 218 String doc = DependsOnCollection.class.getName(); 219 assertEquals( 220 "ConstructorInjector-class " 221 + doc 222 + " needs a 'java.util.Collection' injected via 'public org.picocontainer.DefaultPicoContainerTestCase$DependsOnCollection(java.util.Collection)', but there are too many choices to inject. These:[Instance-of java.util.ArrayList, Instance-of java.util.LinkedList], refer http://picocontainer.org/ambiguous-injectable-help.html", 223 expected.getMessage()); 224 } 225 } 226 227 @Test public void testInstantiationWithMonitorAndParent() { 228 StringWriter writer = new StringWriter(); 229 ComponentMonitor monitor = new WriterComponentMonitor(writer); 230 DefaultPicoContainer parent = new DefaultPicoContainer(); 231 DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent); 232 parent.addComponent("st", SimpleTouchable.class); 233 child.addComponent("dot", DependsOnTouchable.class); 234 DependsOnTouchable dot = (DependsOnTouchable) child.getComponent("dot"); 235 assertNotNull(dot); 236 assertTrue("writer not empty", writer.toString().length() > 0); 237 238 } 239 240 @Test 241 public void testRepresentationOfContainerTree() { 242 StringWriter writer = new StringWriter(); 243 DefaultPicoContainer parent = new DefaultPicoContainer(); 244 parent.setName("parent"); 245 DefaultPicoContainer child = new DefaultPicoContainer(parent); 246 child.setName("child"); 247 parent.addComponent("st", SimpleTouchable.class); 248 child.addComponent("dot", DependsOnTouchable.class); 249 assertEquals("child:1<[Immutable]:parent:1<|", child.toString()); 250 } 251 252 @SuppressWarnings("serial") 253 @Test public void testStartCapturedByMonitor() { 254 final StringBuffer sb = new StringBuffer(); 255 DefaultPicoContainer dpc = new DefaultPicoContainer( 256 new NullComponentMonitor() { 257 public Object invoking(PicoContainer container, 258 ComponentAdapter componentAdapter, Member member, 259 Object instance, Object[] args) { 260 sb.append(member.toString()); 261 return null; 262 } 263 }); 264 dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class); 265 dpc.start(); 266 assertEquals( 267 "ComponentMonitor should have been notified that the component had been started", 268 "public abstract void org.picocontainer.Startable.start()", sb 269 .toString()); 270 } 271 272 public static class StartableClazz implements Startable { 273 private MutablePicoContainer _pico; 274 275 public void start() { 276 List<SimpleTouchable> cps = _pico 277 .getComponents(SimpleTouchable.class); 278 assertNotNull(cps); 279 } 280 281 public void stop() { 282 } 283 284 } 285 286 @Test public void testListComponentsOnStart() { 287 288 // This is really discouraged. Breaks basic principals of IoC - 289 // components should not refer 290 // to their containers 291 // 292 // Might be deleted in due coure, along with adaptersClone stuff in DPC 293 294 DefaultPicoContainer dpc = new DefaultPicoContainer(); 295 dpc.addComponent(SimpleTouchable.class); 296 StartableClazz cl = new StartableClazz(); 297 cl._pico = dpc; 298 dpc.addComponent(cl); 299 dpc.start(); 300 } 301 302 @Test public void testCanChangeMonitor() { 303 StringWriter writer1 = new StringWriter(); 304 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1); 305 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1); 306 pico.addComponent("t1", SimpleTouchable.class); 307 pico.addComponent("t3", SimpleTouchable.class); 308 Touchable t1 = (Touchable) pico.getComponent("t1"); 309 assertNotNull(t1); 310 final String s = writer1.toString(); 311 assertTrue("writer not empty", s.length() > 0); 312 StringWriter writer2 = new StringWriter(); 313 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2); 314 pico.changeMonitor(monitor2); 315 pico.addComponent("t2", SimpleTouchable.class); 316 Touchable t2 = (Touchable) pico.getComponent("t2"); 317 assertNotNull(t2); 318 final String s2 = writer2.toString(); 319 assertTrue("writer not empty", s2.length() > 0); 320 assertTrue("writers of same length", 321 writer1.toString().length() == writer2.toString().length()); 322 Touchable t3 = (Touchable) pico.getComponent("t3"); 323 assertNotNull(t3); 324 assertTrue("old writer was used", writer1.toString().length() < writer2 325 .toString().length()); 326 } 327 328 @Test public void testCanChangeMonitorOfChildContainers() { 329 StringWriter writer1 = new StringWriter(); 330 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1); 331 DefaultPicoContainer parent = new DefaultPicoContainer(); 332 DefaultPicoContainer child = new DefaultPicoContainer(monitor1); 333 parent.addChildContainer(child); 334 child.addComponent("t1", SimpleTouchable.class); 335 child.addComponent("t3", SimpleTouchable.class); 336 Touchable t1 = (Touchable) child.getComponent("t1"); 337 assertNotNull(t1); 338 assertTrue("writer not empty", writer1.toString().length() > 0); 339 StringWriter writer2 = new StringWriter(); 340 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2); 341 parent.changeMonitor(monitor2); 342 child.addComponent("t2", SimpleTouchable.class); 343 Touchable t2 = (Touchable) child.getComponent("t2"); 344 assertNotNull(t2); 345 assertTrue("writer not empty", writer2.toString().length() > 0); 346 String s1 = writer1.toString(); 347 String s2 = writer2.toString(); 348 assertTrue("writers of same length", s1.length() == s2.length()); 349 Touchable t3 = (Touchable) child.getComponent("t3"); 350 assertNotNull(t3); 351 assertTrue("old writer was used", writer1.toString().length() < writer2 352 .toString().length()); 353 } 354 355 @Test public void testChangeMonitorIsIgnoredIfNotSupportingStrategy() { 356 StringWriter writer = new StringWriter(); 357 ComponentMonitor monitor = new WriterComponentMonitor(writer); 358 DefaultPicoContainer parent = new DefaultPicoContainer( 359 new ComponentFactoryWithNoMonitor( 360 new ComponentAdapterWithNoMonitor(new SimpleTouchable()))); 361 parent.addChildContainer(new EmptyPicoContainer()); 362 parent.addComponent("t1", SimpleTouchable.class); 363 parent.changeMonitor(monitor); 364 assertTrue("writer empty", writer.toString().length() == 0); 365 } 366 367 @Test public void testCanReturnCurrentMonitorFromComponentFactory() { 368 StringWriter writer1 = new StringWriter(); 369 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1); 370 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1); 371 assertEquals(monitor1, pico.currentMonitor()); 372 StringWriter writer2 = new StringWriter(); 373 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2); 374 pico.changeMonitor(monitor2); 375 assertEquals(monitor2, pico.currentMonitor()); 376 } 377 378 private static final class ComponentFactoryWithNoMonitor implements ComponentFactory { 379 private final ComponentAdapter adapter; 380 381 public ComponentFactoryWithNoMonitor(ComponentAdapter adapter) { 382 this.adapter = adapter; 383 } 384 385 public ComponentAdapter createComponentAdapter( 386 ComponentMonitor componentMonitor, 387 LifecycleStrategy lifecycleStrategy, 388 Properties componentProperties, Object componentKey, 389 Class componentImplementation, Parameter... parameters) 390 throws PicoCompositionException { 391 return adapter; 392 } 393 394 public void verify(PicoContainer container) { 395 } 396 397 public void accept(PicoVisitor visitor) { 398 visitor.visitComponentFactory(this); 399 } 400 } 401 402 private static final class ComponentAdapterWithNoMonitor implements 403 ComponentAdapter { 404 private final Object instance; 405 406 public ComponentAdapterWithNoMonitor(Object instance) { 407 this.instance = instance; 408 } 409 410 public Object getComponentKey() { 411 return instance.getClass(); 412 } 413 414 public Class getComponentImplementation() { 415 return instance.getClass(); 416 } 417 418 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException { 419 return getComponentInstance(container, null); 420 } 421 422 public Object getComponentInstance(PicoContainer container, Type into) 423 throws PicoCompositionException { 424 return instance; 425 } 426 427 public void verify(PicoContainer container) 428 throws PicoCompositionException { 429 } 430 431 public void accept(PicoVisitor visitor) { 432 } 433 434 public ComponentAdapter getDelegate() { 435 return null; 436 } 437 438 public ComponentAdapter findAdapterOfType(Class adapterType) { 439 return null; 440 } 441 442 public String getDescriptor() { 443 return null; 444 } 445 446 } 447 448 @Test public void testMakeChildContainer() { 449 MutablePicoContainer parent = new DefaultPicoContainer(); 450 parent.addComponent("t1", SimpleTouchable.class); 451 MutablePicoContainer child = parent.makeChildContainer(); 452 Object t1 = child.getParent().getComponent("t1"); 453 assertNotNull(t1); 454 assertTrue(t1 instanceof SimpleTouchable); 455 } 456 457 @Test public void testMakeChildContainerPassesMonitorFromParentToChild() { 458 final StringBuilder sb = new StringBuilder(); 459 ComponentMonitor cm = new NullComponentMonitor() { 460 public <T> void instantiated(PicoContainer container, ComponentAdapter<T> componentAdapter, 461 Constructor<T> constructor, 462 Object instantiated, 463 Object[] injected, 464 long duration) { 465 sb.append(instantiated.getClass().getName()).append(","); 466 } 467 468 }; 469 MutablePicoContainer parent = new DefaultPicoContainer(cm); 470 MutablePicoContainer child = parent.makeChildContainer(); 471 child.addComponent("t1", SimpleTouchable.class); 472 Object t1 = child.getComponent("t1"); 473 assertNotNull(t1); 474 assertTrue(t1 instanceof SimpleTouchable); 475 assertEquals("org.picocontainer.testmodel.SimpleTouchable,", sb.toString()); 476 } 477 478 479 480 @Test public void testCanUseCustomLifecycleStrategyForClassRegistrations() { 481 DefaultPicoContainer dpc = new DefaultPicoContainer( 482 new FailingLifecycleStrategy(), null); 483 dpc.as(Characteristics.CACHE).addComponent(Startable.class, 484 MyStartable.class); 485 try { 486 dpc.start(); 487 fail("should have barfed"); 488 } catch (RuntimeException e) { 489 assertEquals("foo", e.getMessage()); 490 } 491 } 492 493 @Test public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() { 494 DefaultPicoContainer dpc = new DefaultPicoContainer( 495 new FailingLifecycleStrategy(), null); 496 Startable myStartable = new MyStartable(); 497 dpc.addComponent(Startable.class, myStartable); 498 try { 499 dpc.start(); 500 fail("should have barfed"); 501 } catch (RuntimeException e) { 502 assertEquals("foo", e.getMessage()); 503 } 504 } 505 506 public static class FailingLifecycleStrategy implements LifecycleStrategy { 507 public void start(Object component) { 508 throw new RuntimeException("foo"); 509 } 510 511 public void stop(Object component) { 512 } 513 514 public void dispose(Object component) { 515 } 516 517 public boolean hasLifecycle(Class type) { 518 return true; 519 } 520 521 public boolean isLazy(ComponentAdapter<?> adapter) { 522 return false; 523 } 524 } 525 526 public static class MyStartable implements Startable { 527 public MyStartable() { 528 } 529 530 public void start() { 531 } 532 533 public void stop() { 534 } 535 } 536 537 public static interface A { 538 539 } 540 541 public static class SimpleA implements A { 542 543 } 544 545 public static class WrappingA implements A { 546 private final A wrapped; 547 548 public WrappingA(A wrapped) { 549 this.wrapped = wrapped; 550 } 551 } 552 553 @Test public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey() 554 throws Exception { 555 MutablePicoContainer container = createPicoContainer(null); 556 557 container.addComponent(SimpleA.class); 558 container.addComponent(A.class, WrappingA.class); 559 560 container.start(); 561 562 assertEquals(WrappingA.class, container.getComponent(A.class) 563 .getClass()); 564 } 565 566 @Test public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey() 567 throws Exception { 568 MutablePicoContainer container = createPicoContainer(null); 569 570 container.addComponent(SimpleA.class); 571 container.addComponent("A", SimpleA.class); 572 573 container.start(); 574 575 assertNotNull(container.getComponent("A")); 576 assertNotNull(container.getComponent(SimpleA.class)); 577 assertNotSame(container.getComponent("A"), container 578 .getComponent(SimpleA.class)); 579 } 580 581 @Test public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() { 582 MutablePicoContainer mpc = createPicoContainer(null); 583 mpc.addComponent("greeting", "1"); 584 mpc.addComponent("message", "2"); 585 mpc.as(Characteristics.USE_NAMES).addComponent( 586 PicoCompositionException.class, PicoCompositionException.class); 587 assertEquals("2", mpc.getComponent(PicoCompositionException.class) 588 .getMessage()); 589 } 590 591 @Test public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() { 592 MutablePicoContainer mpc = createPicoContainer(null); 593 Horse dobbin = new Horse(); 594 Horse redRum = new Horse(); 595 mpc.addComponent("dobbin", dobbin); 596 mpc.addComponent("horse", redRum); 597 mpc.as(Characteristics.USE_NAMES).addComponent(CdiTurtle.class); 598 assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse); 599 } 600 601 @Test public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() { 602 MutablePicoContainer mpc = createPicoContainer(null); 603 mpc.addComponent("one", 1); 604 mpc.addComponent("two", 2); 605 mpc.as(Characteristics.USE_NAMES).addComponent(NeedsTwo.class); 606 assertEquals(2, mpc.getComponent(NeedsTwo.class).two); 607 } 608 609 public static class ListComponentsInStartClass implements Startable { 610 private MutablePicoContainer _pico; 611 612 public void start() { 613 List<SimpleTouchable> cps = _pico 614 .getComponents(SimpleTouchable.class); 615 assertNotNull(cps); 616 } 617 618 public void stop() { 619 } 620 621 } 622 623 /** 624 * JIRA: PICO-295 reported by Erik Putrycz 625 */ 626 @Test public void testListComponentsInStart() { 627 DefaultPicoContainer dpc = new DefaultPicoContainer(); 628 dpc.addComponent(SimpleTouchable.class); 629 ListComponentsInStartClass cl = new ListComponentsInStartClass(); 630 cl._pico = dpc; 631 dpc.addComponent(cl); 632 dpc.start(); 633 } 634 635 public static class NeedsTwo { 636 private final int two; 637 638 public NeedsTwo(Integer two) { 639 this.two = two; 640 } 641 } 642 643 public static class Horse { 644 } 645 646 public static class CdiTurtle { 647 public final Horse horse; 648 649 public CdiTurtle(Horse horse) { 650 this.horse = horse; 651 } 652 } 653 654 public static class SdiDonkey { 655 public Horse horse; 656 657 public void setHorse(Horse horse) { 658 this.horse = horse; 659 } 660 } 661 662 public static class SdiRabbit { 663 public Horse horse; 664 665 public void setHorse(Horse horse) { 666 this.horse = horse; 667 } 668 } 669 670 @Test public void testMixingOfSDIandCDI() { 671 672 MutablePicoContainer container = createPicoContainer(null).change( 673 Characteristics.CACHE); 674 container.addComponent(Horse.class); 675 container.change(SDI); 676 container.addComponent(SdiDonkey.class); 677 container.addComponent(SdiRabbit.class); 678 container.change(CDI); 679 container.addComponent(CdiTurtle.class); 680 681 SdiDonkey donkey = container.getComponent(SdiDonkey.class); 682 SdiRabbit rabbit = container.getComponent(SdiRabbit.class); 683 CdiTurtle turtle = container.getComponent(CdiTurtle.class); 684 685 assertions(donkey, rabbit, turtle); 686 } 687 688 @Test public void testMixingOfSDIandCDIDifferently() { 689 690 MutablePicoContainer container = createPicoContainer(null).change( 691 Characteristics.CACHE); 692 container.addComponent(Horse.class); 693 container.addComponent(CdiTurtle.class); 694 container.change(SDI); 695 container.addComponent(SdiDonkey.class); 696 container.addComponent(SdiRabbit.class); 697 698 SdiDonkey donkey = container.getComponent(SdiDonkey.class); 699 SdiRabbit rabbit = container.getComponent(SdiRabbit.class); 700 CdiTurtle turtle = container.getComponent(CdiTurtle.class); 701 702 assertions(donkey, rabbit, turtle); 703 } 704 705 @Test public void testMixingOfSDIandCDIInBuilderStyle() { 706 707 MutablePicoContainer container = createPicoContainer(null).change( 708 Characteristics.CACHE); 709 container.addComponent(Horse.class).change(SDI).addComponent( 710 SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI) 711 .addComponent(CdiTurtle.class); 712 713 SdiDonkey donkey = container.getComponent(SdiDonkey.class); 714 SdiRabbit rabbit = container.getComponent(SdiRabbit.class); 715 CdiTurtle turtle = container.getComponent(CdiTurtle.class); 716 717 assertions(donkey, rabbit, turtle); 718 } 719 720 private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) { 721 assertNotNull(rabbit); 722 assertNotNull(donkey); 723 assertNotNull(turtle); 724 assertNotNull(turtle.horse); 725 assertNotNull(donkey.horse); 726 assertNotNull(rabbit.horse); 727 assertSame(donkey.horse, turtle.horse); 728 assertSame(rabbit.horse, turtle.horse); 729 } 730 731 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizations() { 732 733 MutablePicoContainer container = createPicoContainer(null).change( 734 Characteristics.CACHE); 735 container.addComponent(Horse.class); 736 container.addComponent(CdiTurtle.class); 737 container.as(SDI).addComponent(SdiDonkey.class); 738 container.as(SDI).addComponent(SdiRabbit.class); 739 740 SdiDonkey donkey = container.getComponent(SdiDonkey.class); 741 SdiRabbit rabbit = container.getComponent(SdiRabbit.class); 742 CdiTurtle turtle = container.getComponent(CdiTurtle.class); 743 744 assertions(donkey, rabbit, turtle); 745 } 746 747 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() { 748 749 MutablePicoContainer container = createPicoContainer(null).change( 750 Characteristics.CACHE); 751 container.as(SDI).addComponent(SdiDonkey.class); 752 container.as(SDI).addComponent(SdiRabbit.class); 753 container.addComponent(Horse.class); 754 container.addComponent(CdiTurtle.class); 755 756 SdiDonkey donkey = container.getComponent(SdiDonkey.class); 757 SdiRabbit rabbit = container.getComponent(SdiRabbit.class); 758 CdiTurtle turtle = container.getComponent(CdiTurtle.class); 759 760 assertions(donkey, rabbit, turtle); 761 } 762 763 @Test public void testChainingOfTemporaryCharacterizationsIsNotAllowed() { 764 765 MutablePicoContainer container = createPicoContainer(null); 766 try { 767 container.as(Characteristics.CACHE).as(SDI).addComponent(HashMap.class); 768 fail("shoulf barf"); 769 } catch (PicoCompositionException e) { 770 assertTrue(e.getMessage().contains("as(FOO).as(BAR)")); 771 } 772 } 773 774 public static class NeedsString { 775 String string; 776 777 public NeedsString(String string) { 778 this.string = string; 779 } 780 } 781 782 @SuppressWarnings("serial") 783 @Test public void testNoComponentIsMonitoredAndPotentiallyLateProvided() { 784 final Class[] missingKey = new Class[1]; 785 786 DefaultPicoContainer container = new DefaultPicoContainer( 787 new NullComponentMonitor() { 788 public Object noComponentFound( 789 MutablePicoContainer container, Object componentKey) { 790 missingKey[0] = (Class) componentKey; 791 return "foo"; 792 } 793 }); 794 container.addComponent(NeedsString.class); 795 NeedsString needsString = container.getComponent(NeedsString.class); 796 797 assertNotNull(missingKey[0]); 798 assertEquals(String.class, missingKey[0]); 799 assertNotNull(needsString); 800 assertEquals("foo", needsString.string); 801 802 } 803 804 @Test public void testThatComponentCannotBeRemovedFromStartedContainer() { 805 MutablePicoContainer container = createPicoContainer(null); 806 container.addComponent(Map.class, HashMap.class); 807 container.start(); 808 try { 809 container.removeComponent(Map.class); 810 fail("should have barfed"); 811 } catch (PicoCompositionException e) { 812 } 813 } 814 815 @Test public void testThatSimpleStringComponentIsAddedOnlyOnce() { 816 MutablePicoContainer container = createPicoContainer(null); 817 container.addComponent("foo bar"); 818 assertEquals(1, container.getComponentAdapters().size()); 819 } 820 821 public static class ConstantParameterTestClass { 822 public ConstantParameterTestClass(Class<String> type) { 823 assert type != null; 824 } 825 } 826 827 828 @Test 829 public void testConstantParameterReferenceClass() { 830 MutablePicoContainer container = createPicoContainer(null); 831 container.addComponent(ConstantParameterTestClass.class, ConstantParameterTestClass.class, new ConstantParameter(String.class)); 832 833 assertNotNull(container.getComponent(ConstantParameterTestClass.class)); 834 835 } 836 837 838 @Test public void canInterceptImplementationViaNewInjectionFactoryMethodOnMonitor() { 839 DefaultPicoContainer dpc = new DefaultPicoContainer(new MyNullComponentMonitor()); 840 dpc.addComponent(Collection.class, HashSet.class); 841 dpc.addComponent(List.class, ArrayList.class); 842 assertNotNull(dpc.getComponent(List.class)); 843 assertEquals("doppleganger", dpc.getComponent(List.class).get(0)); 844 } 845 846 @SuppressWarnings({"serial", "unchecked"}) 847 private static class MyNullComponentMonitor extends NullComponentMonitor { 848 public Injector newInjector(Injector injector) { 849 if (injector.getComponentKey() == List.class) { 850 return new AbstractInjector(List.class, ArrayList.class, Parameter.DEFAULT, MyNullComponentMonitor.this, false) { 851 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException { 852 return getComponentInstance(container, null); 853 } 854 855 public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException { 856 ArrayList list = new ArrayList(); 857 list.add("doppleganger"); 858 return list; 859 } 860 }; 861 } else { 862 return injector; 863 } 864 } 865 866 public Behavior newBehavior(Behavior behavior) { 867 return behavior; 868 } 869 } 870 871 @Test public void testUnsatisfiableDependenciesExceptionGivesVerboseEnoughErrorMessage() { 872 super.testUnsatisfiableDependenciesExceptionGivesVerboseEnoughErrorMessage(); 873 } 874 875}