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 }