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