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 org.picocontainer.ComponentAdapter;
013    import org.picocontainer.ComponentMonitor;
014    import org.picocontainer.MutablePicoContainer;
015    import org.picocontainer.Parameter;
016    import org.picocontainer.PicoContainer;
017    import org.picocontainer.PicoCompositionException;
018    import org.picocontainer.PicoVisitor;
019    import org.picocontainer.Startable;
020    import org.picocontainer.LifecycleStrategy;
021    import org.picocontainer.ComponentFactory;
022    import org.picocontainer.DefaultPicoContainer;
023    import org.picocontainer.injectors.AbstractInjector;
024    import org.picocontainer.injectors.ConstructorInjector;
025    import org.picocontainer.injectors.ConstructorInjectionFactory;
026    import org.picocontainer.lifecycle.NullLifecycleStrategy;
027    import org.picocontainer.containers.EmptyPicoContainer;
028    import org.picocontainer.adapters.InstanceAdapter;
029    import org.picocontainer.behaviors.SynchronizedBehavior;
030    import org.picocontainer.behaviors.CachingBehaviorFactory;
031    import org.picocontainer.monitors.WriterComponentMonitor;
032    import org.picocontainer.monitors.NullComponentMonitor;
033    import org.picocontainer.tck.AbstractPicoContainerTestCase;
034    import org.picocontainer.testmodel.DecoratedTouchable;
035    import org.picocontainer.testmodel.DependsOnTouchable;
036    import org.picocontainer.testmodel.SimpleTouchable;
037    import org.picocontainer.testmodel.Touchable;
038    import static org.picocontainer.Characteristics.CDI;
039    import static org.picocontainer.Characteristics.SDI;
040    
041    import java.io.Serializable;
042    import java.io.StringWriter;
043    import java.lang.reflect.Member;
044    import java.util.ArrayList;
045    import java.util.Collection;
046    import java.util.HashMap;
047    import java.util.LinkedList;
048    import java.util.List;
049    import java.util.Properties;
050    
051    /**
052     * @author Aslak Hellesøy
053     * @author Paul Hammant
054     * @author Ward Cunningham
055     * @author Mauro Talevi
056     * @version $Revision: 3714 $
057     */
058    public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTestCase {
059        protected MutablePicoContainer createPicoContainer(PicoContainer parent) {
060            return new DefaultPicoContainer(new CachingBehaviorFactory(), parent);
061        }
062    
063        public void testInstantiationWithNullComponentAdapterFactory(){
064            try {
065                new DefaultPicoContainer((ComponentFactory)null, null);
066                fail("NPE expected");
067            } catch (NullPointerException e) {
068                // expected
069            }
070        }
071        public void testUpDownDependenciesCannotBeFollowed() {
072            MutablePicoContainer parent = createPicoContainer(null);
073            MutablePicoContainer child = createPicoContainer(parent);
074    
075            // ComponentF -> ComponentA -> ComponentB+C
076            child.addComponent(ComponentF.class);
077            parent.addComponent(ComponentA.class);
078            child.addComponent(ComponentB.class);
079            child.addComponent(ComponentC.class);
080    
081            try {
082                child.getComponent(ComponentF.class);
083                fail("Thrown " + AbstractInjector.UnsatisfiableDependenciesException.class.getName() + " expected");
084            } catch (final AbstractInjector.UnsatisfiableDependenciesException e) {
085                assertEquals(ComponentB.class, e.getUnsatisfiedDependencyType());
086            }
087        }
088    
089    
090    
091        public void testComponentsCanBeRemovedByInstance() {
092            MutablePicoContainer pico = createPicoContainer(null);
093            pico.addComponent(HashMap.class);
094            pico.addComponent(ArrayList.class);
095            List list = pico.getComponent(List.class);
096            pico.removeComponentByInstance(list);
097            assertEquals(1, pico.getComponentAdapters().size());
098            assertEquals(1, pico.getComponents().size());
099            assertEquals(HashMap.class, pico.getComponent(Serializable.class).getClass());
100        }
101    
102        public void testComponentInstancesListIsReturnedForNullType(){
103            MutablePicoContainer pico = createPicoContainer(null);
104            List componentInstances = pico.getComponents(null);
105            assertNotNull(componentInstances);
106            assertEquals(0, componentInstances.size());
107        }
108        
109        public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() {
110            MutablePicoContainer pico = createPicoContainer(null);
111            pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO);
112            pico.addComponent(ArrayList.class);
113            assertEquals(ArrayList.class, pico.getComponent((Class) ArrayList.class).getClass());
114        }
115    
116        /*
117         When pico tries to resolve DecoratedTouchable it find as dependency itself and SimpleTouchable.
118         Problem is basically the same as above. Pico should not consider self as solution.
119         
120         JS
121         fixed it ( PICO-222 )
122         KP
123         */
124        public void testUnambiguouSelfDependency() {
125            MutablePicoContainer pico = createPicoContainer(null);
126            pico.addComponent(SimpleTouchable.class);
127            pico.addComponent(DecoratedTouchable.class);
128            Touchable t = (Touchable) pico.getComponent((Object) DecoratedTouchable.class);
129            assertNotNull(t);
130        }
131    
132    
133        public void testPicoUsedInBuilderStyle() {
134            MutablePicoContainer pico = createPicoContainer(null);
135            Touchable t = pico.addComponent(SimpleTouchable.class).addComponent(DecoratedTouchable.class).getComponent(DecoratedTouchable.class);
136            SimpleTouchable t2 = pico.getComponent(SimpleTouchable.class);
137            assertNotNull(t);
138            assertNotNull(t2);
139            t.touch();
140            assertTrue(t2.wasTouched);
141        }
142    
143        public static class Thingie {
144            public Thingie(List c) {
145                assertNotNull(c);
146            }
147        }
148    
149        public void testThangCanBeInstantiatedWithArrayList() {
150            MutablePicoContainer pico = new DefaultPicoContainer();
151            pico.addComponent(Thingie.class);
152            pico.addComponent(ArrayList.class);
153            assertNotNull(pico.getComponent(Thingie.class));
154        }
155    
156        public void testGetComponentAdaptersOfTypeNullReturnsEmptyList() {
157            DefaultPicoContainer pico = new DefaultPicoContainer();
158            List adapters = pico.getComponentAdapters(null);
159            assertNotNull(adapters);
160            assertEquals(0, adapters.size());
161        }
162        
163    
164        public static class Service {
165        }
166    
167        public static final class TransientComponent {
168            private final Service service;
169    
170            public TransientComponent(Service service) {
171                this.service = service;
172            }
173        }
174    
175        public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() {
176            DefaultPicoContainer picoContainer = new DefaultPicoContainer(new CachingBehaviorFactory().forThis(new ConstructorInjectionFactory()));
177            picoContainer.addComponent(Service.class);
178            picoContainer.addAdapter(new ConstructorInjector(TransientComponent.class, TransientComponent.class, null, new NullComponentMonitor(), new NullLifecycleStrategy()));
179            TransientComponent c1 = picoContainer.getComponent(TransientComponent.class);
180            TransientComponent c2 = picoContainer.getComponent(TransientComponent.class);
181            assertNotSame(c1, c2);
182            assertSame(c1.service, c2.service);
183        }
184    
185        public static class DependsOnCollection {
186            public DependsOnCollection(Collection c) {
187            }
188        }
189    
190        public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
191            MutablePicoContainer pico = this.createPicoContainer(null);
192            pico.addComponent(new ArrayList());
193            pico.addComponent(new LinkedList());
194            pico.addComponent(DependsOnCollection.class);
195            try {
196                pico.getComponent(DependsOnCollection.class);
197                fail();
198            } catch (AbstractInjector.AmbiguousComponentResolutionException expected) {
199                String doc = DependsOnCollection.class.getName();
200                assertEquals("class " + doc + " 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/ambiguous-injectable.html", expected.getMessage());
201            }
202        }
203    
204        public void testInstantiationWithMonitorAndParent() {
205            StringWriter writer = new StringWriter();
206            ComponentMonitor monitor = new WriterComponentMonitor(writer);
207            DefaultPicoContainer parent = new DefaultPicoContainer();
208            DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent);
209            parent.addComponent("st", SimpleTouchable.class);
210            child.addComponent("dot", DependsOnTouchable.class);
211            DependsOnTouchable dot = (DependsOnTouchable) child.getComponent("dot");
212            assertNotNull(dot);
213            assertTrue("writer not empty", writer.toString().length() > 0);
214        }
215        
216        public void testStartCapturedByMonitor() {
217            final StringBuffer sb = new StringBuffer();
218            DefaultPicoContainer dpc = new DefaultPicoContainer(new NullComponentMonitor() {
219                public void invoking(PicoContainer container,
220                                     ComponentAdapter componentAdapter,
221                                     Member member,
222                                     Object instance) {
223                    sb.append(member.toString());
224                }
225            });
226            dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class);
227            dpc.start();
228            assertEquals("ComponentMonitor should have been notified that the component had been started",
229                    "public abstract void org.picocontainer.Startable.start()", sb.toString());
230        }
231    
232        public void testCanChangeMonitor() {
233            StringWriter writer1 = new StringWriter();
234            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
235            DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
236            pico.addComponent("t1", SimpleTouchable.class);
237            pico.addComponent("t3", SimpleTouchable.class);
238            Touchable t1 = (Touchable) pico.getComponent("t1");
239            assertNotNull(t1);
240            final String s = writer1.toString();
241            assertTrue("writer not empty", s.length() > 0);
242            StringWriter writer2 = new StringWriter();
243            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
244            pico.changeMonitor(monitor2);
245            pico.addComponent("t2", SimpleTouchable.class);
246            Touchable t2 = (Touchable) pico.getComponent("t2");
247            assertNotNull(t2);
248            final String s2 = writer2.toString();
249            assertTrue("writer not empty", s2.length() > 0);
250            assertTrue("writers of same length", writer1.toString().length() == writer2.toString().length());
251            Touchable t3 = (Touchable) pico.getComponent("t3");
252            assertNotNull(t3);
253            assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
254        }
255    
256        public void testCanChangeMonitorOfChildContainers() {
257            StringWriter writer1 = new StringWriter();
258            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
259            DefaultPicoContainer parent = new DefaultPicoContainer();
260            DefaultPicoContainer child = new DefaultPicoContainer(monitor1);
261            parent.addChildContainer(child);
262            child.addComponent("t1", SimpleTouchable.class);
263            child.addComponent("t3", SimpleTouchable.class);
264            Touchable t1 = (Touchable) child.getComponent("t1");
265            assertNotNull(t1);
266            assertTrue("writer not empty", writer1.toString().length() > 0);
267            StringWriter writer2 = new StringWriter();
268            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
269            parent.changeMonitor(monitor2);
270            child.addComponent("t2", SimpleTouchable.class);
271            Touchable t2 = (Touchable) child.getComponent("t2");
272            assertNotNull(t2);
273            assertTrue("writer not empty", writer2.toString().length() > 0);
274            String s1 = writer1.toString();
275            String s2 = writer2.toString();
276            assertTrue("writers of same length", s1.length() == s2.length());
277            Touchable t3 = (Touchable) child.getComponent("t3");
278            assertNotNull(t3);
279            assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
280        }
281    
282        public void testChangeMonitorIsIgnoredIfNotSupportingStrategy(){
283            StringWriter writer = new StringWriter();
284            ComponentMonitor monitor = new WriterComponentMonitor(writer);
285            DefaultPicoContainer parent = new DefaultPicoContainer(new ComponentFactoryWithNoMonitor(new ComponentAdapterWithNoMonitor(new SimpleTouchable())));
286            parent.addChildContainer(new EmptyPicoContainer());
287            parent.addComponent("t1", SimpleTouchable.class);
288            parent.changeMonitor(monitor);
289            assertTrue("writer empty", writer.toString().length() == 0);
290        }
291        
292        public void testCanReturnCurrentMonitorFromComponentAdapterFactory() {
293            StringWriter writer1 = new StringWriter();
294            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
295            DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
296            assertEquals(monitor1, pico.currentMonitor());
297            StringWriter writer2 = new StringWriter();
298            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
299            pico.changeMonitor(monitor2);
300            assertEquals(monitor2, pico.currentMonitor());
301        }
302       
303        private static final class ComponentFactoryWithNoMonitor implements ComponentFactory {
304            private final ComponentAdapter adapter;
305            public ComponentFactoryWithNoMonitor(ComponentAdapter adapter){
306                this.adapter = adapter;
307            }
308            public ComponentAdapter createComponentAdapter(ComponentMonitor componentMonitor, LifecycleStrategy lifecycleStrategy, Properties componentProperties, Object componentKey, Class componentImplementation, Parameter... parameters) throws PicoCompositionException {
309                return adapter;
310            }        
311        }
312        
313        private static final class ComponentAdapterWithNoMonitor implements ComponentAdapter {
314            private final Object instance;
315            public ComponentAdapterWithNoMonitor(Object instance){
316                this.instance = instance;
317            }
318            public Object getComponentKey() {
319                return instance.getClass();
320            }
321            public Class getComponentImplementation() {
322                return instance.getClass();
323            }
324            public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
325                return instance;
326            }
327            public void verify(PicoContainer container) throws PicoCompositionException {
328            }
329            public void accept(PicoVisitor visitor) {
330            }
331        }
332        
333        public void testMakeChildContainer() {
334            MutablePicoContainer parent = new DefaultPicoContainer();
335            parent.addComponent("t1", SimpleTouchable.class);
336            MutablePicoContainer child = parent.makeChildContainer();
337            Object t1 = child.getParent().getComponent("t1");
338            assertNotNull(t1);
339            assertTrue(t1 instanceof SimpleTouchable);
340        }
341    
342        public void testCanUseCustomLifecycleStrategyForClassRegistrations() {
343            DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
344            dpc.as(Characteristics.CACHE).addComponent(Startable.class, MyStartable.class);
345            try {
346                dpc.start();
347                fail("should have barfed");
348            } catch (RuntimeException e) {
349                assertEquals("foo", e.getMessage());
350            }
351        }
352    
353        public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
354            DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
355            Startable myStartable = new MyStartable();
356            dpc.addComponent(Startable.class, myStartable);
357            try {
358                dpc.start();
359                fail("should have barfed");
360            } catch (RuntimeException e) {
361                assertEquals("foo", e.getMessage());
362            }
363        }
364    
365        public static class FailingLifecycleStrategy implements LifecycleStrategy {
366                public void start(Object component) {
367                    throw new RuntimeException("foo");
368                }
369    
370                public void stop(Object component) {
371                }
372    
373                public void dispose(Object component) {
374                }
375    
376                public boolean hasLifecycle(Class type) {
377                    return true;
378                }
379    
380        }
381        public static class MyStartable implements Startable {
382            public MyStartable() {
383            }
384    
385            public void start() {
386            }
387    
388            public void stop() {
389            }
390        }
391    
392        public static interface A {
393    
394        }
395    
396        public static class SimpleA implements A
397        {
398    
399        }
400    
401        public static class WrappingA implements A
402        {
403            private final A wrapped;
404    
405            public WrappingA(A wrapped) {
406                this.wrapped = wrapped;
407            }
408        }
409    
410        public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey() throws Exception {
411            MutablePicoContainer container = createPicoContainer(null);
412    
413            container.addComponent(SimpleA.class);
414            container.addComponent(A.class, WrappingA.class);
415    
416            container.start();
417    
418            assertEquals(WrappingA.class, container.getComponent(A.class).getClass());
419        }
420    
421        public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey() throws Exception {
422            MutablePicoContainer container = createPicoContainer(null);
423    
424            container.addComponent(SimpleA.class);
425            container.addComponent("A", SimpleA.class);
426    
427            container.start();
428    
429            assertNotNull(container.getComponent("A"));
430            assertNotNull(container.getComponent(SimpleA.class));
431            assertNotSame(container.getComponent("A"), container.getComponent(SimpleA.class));
432        }
433        
434        public static class MyPicoContainer extends DefaultPicoContainer {
435    
436            public MutablePicoContainer addAdapter(ComponentAdapter componentAdapter) {
437                return super.addAdapter(new SynchronizedBehavior(componentAdapter));
438            }
439            
440        }
441        
442        public void testDerivedPicoContainerCanOverloadRegisterComponentForAllCreatedComponentAdapters() {
443            MutablePicoContainer mpc = new MyPicoContainer();
444            InstanceAdapter instanceAdapter = new InstanceAdapter("foo", "bar", new NullLifecycleStrategy(),
445                                                                  new NullComponentMonitor());
446            assertEquals(SynchronizedBehavior.class, mpc.addAdapter(instanceAdapter).getComponentAdapter(instanceAdapter.getComponentKey()).getClass());
447            MutablePicoContainer container = mpc.addComponent("foobar");
448            assertEquals(SynchronizedBehavior.class, container.getComponentAdapter("foobar").getClass());
449            assertEquals(SynchronizedBehavior.class, mpc.addComponent(SimpleA.class).getComponentAdapter(SimpleA.class, null).getClass());
450        }
451    
452    
453        public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
454            MutablePicoContainer mpc = createPicoContainer(null);
455            mpc.addComponent("greeting", "1");
456            mpc.addComponent("message", "2");
457            mpc.addComponent(PicoCompositionException.class, PicoCompositionException.class);
458            assertEquals("2", mpc.getComponent(PicoCompositionException.class).getMessage());
459        }
460    
461        public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
462            MutablePicoContainer mpc = createPicoContainer(null);
463            Horse dobbin = new Horse();
464            Horse redRum = new Horse();
465            mpc.addComponent("dobbin", dobbin);
466            mpc.addComponent("horse", redRum);
467            mpc.addComponent(CdiTurtle.class);
468            assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
469        }
470    
471        public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
472            MutablePicoContainer mpc = createPicoContainer(null);
473            mpc.addComponent("one", 1);
474            mpc.addComponent("two", 2);
475            mpc.addComponent(NeedsTwo.class);
476            assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
477        }
478    
479        public static class NeedsTwo {
480            private final int two;
481            public NeedsTwo(Integer two) {
482                this.two = two;
483            }
484        }
485    
486        public static class Horse {}
487    
488        public static class CdiTurtle {
489            public final Horse horse;
490            public CdiTurtle(Horse horse) {
491                this.horse = horse;
492            }
493        }
494    
495        public static class SdiDonkey {
496            public Horse horse;
497            public void setHorse(Horse horse) {
498                this.horse = horse;
499            }
500        }
501    
502        public static class SdiRabbit {
503            public Horse horse;
504            public void setHorse(Horse horse) {
505                this.horse = horse;
506            }
507        }
508    
509        public void testMixingOfSDIandCDI() {
510    
511            MutablePicoContainer container = createPicoContainer(null);
512            container.addComponent(Horse.class);
513            container.change(SDI);
514            container.addComponent(SdiDonkey.class);
515            container.addComponent(SdiRabbit.class);
516            container.change(CDI);
517            container.addComponent(CdiTurtle.class);
518    
519            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
520            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
521            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
522    
523            assertions(donkey, rabbit, turtle);
524        }
525    
526        public void testMixingOfSDIandCDIDifferently() {
527    
528            MutablePicoContainer container = createPicoContainer(null);
529            container.addComponent(Horse.class);
530            container.addComponent(CdiTurtle.class);
531            container.change(SDI);
532            container.addComponent(SdiDonkey.class);
533            container.addComponent(SdiRabbit.class);
534    
535            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
536            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
537            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
538    
539            assertions(donkey, rabbit, turtle);
540        }
541    
542        public void testMixingOfSDIandCDIInBuilderStyle() {
543    
544            MutablePicoContainer container = createPicoContainer(null);
545            container.addComponent(Horse.class).change(SDI)
546                    .addComponent(SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI).addComponent(CdiTurtle.class);
547    
548            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
549            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
550            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
551    
552            assertions(donkey, rabbit, turtle);
553        }
554    
555        private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
556            assertNotNull(rabbit);
557            assertNotNull(donkey);
558            assertNotNull(turtle);
559            assertNotNull(turtle.horse);
560            assertNotNull(donkey.horse);
561            assertNotNull(rabbit.horse);
562            assertSame(donkey.horse, turtle.horse);
563            assertSame(rabbit.horse, turtle.horse);
564        }
565    
566        public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
567    
568            MutablePicoContainer container = createPicoContainer(null);
569            container.addComponent(Horse.class);
570            container.addComponent(CdiTurtle.class);
571            container.as(SDI).addComponent(SdiDonkey.class);
572            container.as(SDI).addComponent(SdiRabbit.class);
573    
574            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
575            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
576            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
577    
578            assertions(donkey, rabbit, turtle);
579        }
580    
581        public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
582    
583            MutablePicoContainer container = createPicoContainer(null);
584            container.as(SDI).addComponent(SdiDonkey.class);
585            container.as(SDI).addComponent(SdiRabbit.class);
586            container.addComponent(Horse.class);
587            container.addComponent(CdiTurtle.class);
588    
589            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
590            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
591            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
592    
593            assertions(donkey, rabbit, turtle);
594        }
595    
596        public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
597            final String[] missingKey = new String[1];
598            
599            String foo = (String) new DefaultPicoContainer(new NullComponentMonitor(){
600                public Object noComponentFound(MutablePicoContainer container, Object componentKey) {
601                    missingKey[0] = (String) componentKey;
602                    return "foo";
603                }
604            }).getComponent("missingKey");
605    
606            assertNotNull(missingKey[0]);
607            assertEquals("missingKey", missingKey[0]);
608            assertEquals("foo", foo);
609    
610        }
611    }