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     * Original code by                                                          *
009     *****************************************************************************/
010    package org.picocontainer.injectors;
011    
012    import java.util.ArrayList;
013    import java.util.List;
014    
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.MutablePicoContainer;
017    import org.picocontainer.Parameter;
018    import org.picocontainer.ComponentFactory;
019    import org.picocontainer.DefaultPicoContainer;
020    import org.picocontainer.Characteristics;
021    import org.picocontainer.lifecycle.NullLifecycleStrategy;
022    import org.picocontainer.parameters.ConstantParameter;
023    import org.picocontainer.monitors.AbstractComponentMonitor;
024    import org.picocontainer.monitors.NullComponentMonitor;
025    import static org.picocontainer.parameters.ComponentParameter.*;
026    import org.picocontainer.behaviors.Caching;
027    import org.picocontainer.tck.AbstractComponentAdapterTestCase;
028    import org.picocontainer.testmodel.NullLifecycle;
029    import org.picocontainer.testmodel.PersonBean;
030    import org.picocontainer.testmodel.PurseBean;
031    import org.picocontainer.testmodel.SimpleTouchable;
032    import org.picocontainer.testmodel.Touchable;
033    
034    
035    public class SetterInjectorTestCase
036        extends AbstractComponentAdapterTestCase {
037    
038        protected Class getComponentAdapterType() {
039            return SetterInjector.class;
040        }
041    
042        protected ComponentFactory createDefaultComponentFactory() {
043            return new Caching().wrap(new SetterInjection());
044        }
045    
046        protected ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer) {
047            return new SetterInjector(PersonBean.class, PersonBean.class, new Parameter[] {new ConstantParameter(
048                    "Pico Container")}, new NullComponentMonitor(), new NullLifecycleStrategy(), "set");
049        }
050    
051        protected ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer) {
052            picoContainer.addComponent("Pico Container");
053            return new SetterInjector(DeadBody.class, DeadBody.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
054                                      "set");
055        }
056    
057        protected ComponentAdapter prepDEF_visitable() {
058            return new SetterInjector(PersonBean.class, PersonBean.class, new Parameter[] {new ConstantParameter(
059                    "Pico Container")}, new NullComponentMonitor(), new NullLifecycleStrategy(), "set");
060    
061        }
062    
063        protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) {
064            picoContainer.addComponent("Pico Container");
065            return new SetterInjector(PersonBean.class, PersonBean.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
066                                      "set");
067        }
068    
069        protected ComponentAdapter prepSER_isXStreamSerializable(MutablePicoContainer picoContainer) {
070            return prepSER_isSerializable(picoContainer);
071        }
072    
073        protected ComponentAdapter prepDEF_isAbleToTakeParameters(MutablePicoContainer picoContainer) {
074            picoContainer.addComponent("Pico Container");
075            picoContainer.addComponent(PersonBean.class);
076            SetterInjector componentAdapter = new SetterInjector(
077                    PurseBean.class, MoneyPurse.class, new Parameter[] {DEFAULT, new ConstantParameter(100.0)}, new NullComponentMonitor(), new NullLifecycleStrategy(),
078                    "set");
079            return picoContainer.as(Characteristics.NO_CACHE).addAdapter(componentAdapter).getComponentAdapter(PurseBean.class, null);
080        }
081    
082        public static class MoneyPurse
083                extends PurseBean {
084            double money;
085    
086            public double getMoney() {
087                return money;
088            }
089    
090            public void setMoney(double money) {
091                this.money = money;
092            }
093        }
094    
095        protected ComponentAdapter prepVER_verificationFails(MutablePicoContainer picoContainer) {
096            picoContainer.addComponent("Pico Container");
097            picoContainer.addComponent(PersonBean.class);
098            SetterInjector componentAdapter = new SetterInjector(
099                    PurseBean.class, MoneyPurse.class, new Parameter[] {DEFAULT},new NullComponentMonitor(), new NullLifecycleStrategy(),
100                    "set");
101            return picoContainer.addAdapter(componentAdapter).getComponentAdapter(PurseBean.class, null);
102        }
103    
104        protected ComponentAdapter prepINS_createsNewInstances(MutablePicoContainer picoContainer) {
105            picoContainer.addComponent("Pico Container");
106            return new SetterInjector(PersonBean.class, PersonBean.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
107                                      "set");
108        }
109    
110        public static class Ghost
111                extends PersonBean {
112            public Ghost() {
113                throw new VerifyError("test");
114            }
115        }
116    
117        protected ComponentAdapter prepINS_errorIsRethrown(MutablePicoContainer picoContainer) {
118            picoContainer.addComponent("Pico Container");
119            return new SetterInjector(Ghost.class, Ghost.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
120                                      "set");
121        }
122    
123        public static class DeadBody
124                extends PersonBean {
125            public DeadBody() {
126                throw new RuntimeException("test");
127            }
128        }
129    
130        protected ComponentAdapter prepINS_runtimeExceptionIsRethrown(MutablePicoContainer picoContainer) {
131            picoContainer.addComponent("Pico Container");
132            return new SetterInjector(DeadBody.class, DeadBody.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
133                                      "set");
134        }
135    
136        public static class HidingPersion
137                extends PersonBean {
138            public HidingPersion() throws Exception {
139                throw new Exception("test");
140            }
141        }
142    
143        protected ComponentAdapter prepINS_normalExceptionIsRethrownInsidePicoInitializationException(
144                MutablePicoContainer picoContainer) {
145            picoContainer.addComponent("Pico Container");
146            return new SetterInjector(
147                    HidingPersion.class, HidingPersion.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
148                    "set");
149        }
150    
151        protected ComponentAdapter prepRES_dependenciesAreResolved(MutablePicoContainer picoContainer) {
152            picoContainer.addComponent("Pico Container");
153            picoContainer.addComponent(PersonBean.class);
154            return new SetterInjector(PurseBean.class, PurseBean.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
155                                      "set");
156        }
157    
158        public static class WealthyPerson
159                extends PersonBean {
160            PurseBean purse;
161    
162            public PurseBean getPurse() {
163                return purse;
164            }
165    
166            public void setPurse(PurseBean purse) {
167                this.purse = purse;
168            }
169        }
170    
171        protected ComponentAdapter prepRES_failingVerificationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
172            picoContainer.addComponent("Pico Container");
173            picoContainer.addComponent(PersonBean.class, WealthyPerson.class);
174            SetterInjector componentAdapter = new SetterInjector(
175                    PurseBean.class, PurseBean.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
176                    "set");
177            return picoContainer.as(Characteristics.NO_CACHE).addAdapter(componentAdapter).getComponentAdapter(PurseBean.class, null);
178        }
179    
180        protected ComponentAdapter prepRES_failingInstantiationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
181            picoContainer.addComponent("Pico Container");
182            picoContainer.addComponent(PersonBean.class, WealthyPerson.class);
183            SetterInjector componentAdapter = new SetterInjector(
184                    PurseBean.class, PurseBean.class, new Parameter[] {DEFAULT}, new NullComponentMonitor(), new NullLifecycleStrategy(),
185                    "set");
186            return picoContainer.as(Characteristics.NO_CACHE).addAdapter(componentAdapter).getComponentAdapter(PurseBean.class, null);
187        }
188    
189        public static class A {
190            private B b;
191            private String string;
192            private List list;
193    
194            public void setB(B b) {
195                this.b = b;
196            }
197    
198            public B getB() {
199                return b;
200            }
201    
202            public String getString() {
203                return string;
204            }
205    
206            public void setString(String string) {
207                this.string = string;
208            }
209    
210            public List getList() {
211                return list;
212            }
213    
214            public void setList(List list) {
215                this.list = list;
216            }
217        }
218    
219        public static class A2 {
220            private B b;
221            private String string;
222            private List list;
223    
224            public void injectB(B b) {
225                this.b = b;
226            }
227    
228            public B getB() {
229                return b;
230            }
231    
232            public String getString() {
233                return string;
234            }
235    
236            public void injectString(String string) {
237                this.string = string;
238            }
239    
240            public List getList() {
241                return list;
242            }
243    
244            public void injectList(List list) {
245                this.list = list;
246            }
247        }
248    
249    
250        public static class B {
251        }
252    
253        public void testAllUnsatisfiableDependenciesAreSignalled() {
254            SetterInjector aAdapter = new SetterInjector("a", A.class, Parameter.DEFAULT, new NullComponentMonitor(), new NullLifecycleStrategy(),
255                                                         "set");
256            SetterInjector bAdapter = new SetterInjector("b", B.class, Parameter.DEFAULT, new NullComponentMonitor(), new NullLifecycleStrategy(),
257                                                         "set");
258    
259            MutablePicoContainer pico = new DefaultPicoContainer();
260            pico.addAdapter(bAdapter);
261            pico.addAdapter(aAdapter);
262    
263            try {
264                aAdapter.getComponentInstance(pico);
265            } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
266                assertTrue(e.getUnsatisfiableDependencies().contains(List.class));
267                assertTrue(e.getUnsatisfiableDependencies().contains(String.class));
268            }
269        }
270    
271        public void testAllUnsatisfiableDependenciesAreSignalled2() {
272            SetterInjector aAdapter = new SetterInjector(A2.class, A2.class, null, new NullComponentMonitor(), new NullLifecycleStrategy(),
273                                                         "set");
274            SetterInjector bAdapter = new SetterInjector("b", B.class, null, new NullComponentMonitor(), new NullLifecycleStrategy(),
275                                                         "set");
276    
277            MutablePicoContainer pico = new DefaultPicoContainer();
278            pico.addComponent(List.class, ArrayList.class)
279                .addComponent(String.class, "foo")
280                .addAdapter(bAdapter)
281                .addAdapter(aAdapter);
282    
283            aAdapter.getComponentInstance(pico);
284    
285            assertNotNull(aAdapter);
286    
287            A2 a = pico.getComponent(A2.class);
288            assertTrue(a.getList() == null);
289            assertTrue(a.getString() == null);
290        }
291    
292        public static class InitBurp {
293    
294            private Wind wind;
295    
296            public void initWind(Wind wind) {
297                this.wind = wind;
298            }
299        }
300    
301        public static class SetterBurp {
302    
303            private Wind wind;
304    
305            public void setWind(Wind wind) {
306                this.wind = wind;
307            }
308        }
309    
310        public static class Wind {
311    
312        }
313    
314        public void testSetterMethodInjectionToContrastWithThatBelow() {
315    
316            MutablePicoContainer pico = new DefaultPicoContainer();
317            pico.addAdapter(new SetterInjector(SetterBurp.class, SetterBurp.class, Parameter.DEFAULT, new NullComponentMonitor(), new NullLifecycleStrategy(),
318                                               "set"));
319            pico.addComponent(Wind.class, new Wind());
320            SetterBurp burp = pico.getComponent(SetterBurp.class);
321            assertNotNull(burp);
322            assertNotNull(burp.wind);
323        }
324    
325        public void testNonSetterMethodInjection() {
326            MutablePicoContainer pico = new DefaultPicoContainer();
327            pico.addAdapter(new SetterInjector(InitBurp.class, InitBurp.class, Parameter.DEFAULT, new NullComponentMonitor(), new NullLifecycleStrategy(),
328                                               "set") {
329                protected String getInjectorPrefix() {
330                    return "init";
331                }
332            });
333            pico.addComponent(Wind.class, new Wind());
334            InitBurp burp = pico.getComponent(InitBurp.class);
335            assertNotNull(burp);
336            assertNotNull(burp.wind);
337        }
338    
339        public void testNonSetterMethodInjectionWithoutOverridingSetterPrefix() {
340            MutablePicoContainer pico = new DefaultPicoContainer();
341            pico.addAdapter(new SetterInjector(InitBurp.class, InitBurp.class, Parameter.ZERO, new NullComponentMonitor(), new NullLifecycleStrategy(),
342                                               "set"));
343            pico.addComponent(Wind.class, new Wind());
344            InitBurp burp = pico.getComponent(InitBurp.class);
345            assertNotNull(burp);
346            assertTrue(burp.wind == null);
347        }
348    
349    
350        public static class C {
351            private B b;
352            private List l;
353            private final boolean asBean;
354    
355            public C() {
356                asBean = true;
357            }
358    
359            public C(B b) {
360                this.l = new ArrayList();
361                this.b = b;
362                asBean = false;
363            }
364    
365            public void setB(B b) {
366                this.b = b;
367            }
368    
369            public B getB() {
370                return b;
371            }
372    
373            public void setList(List l) {
374                this.l = l;
375            }
376    
377            public List getList() {
378                return l;
379            }
380    
381            public boolean instantiatedAsBean() {
382                return asBean;
383            }
384        }
385    
386        public void testHybridBeans() {
387            SetterInjector bAdapter = new SetterInjector("b", B.class, (Parameter[])null, new NullComponentMonitor(), new NullLifecycleStrategy(),
388                                                         "set");
389            SetterInjector cAdapter = new SetterInjector("c", C.class, (Parameter[])null, new NullComponentMonitor(), new NullLifecycleStrategy(),
390                                                         "set");
391            SetterInjector cNullAdapter = new SetterInjector("c0", C.class, (Parameter[])null, new NullComponentMonitor(), new NullLifecycleStrategy(),
392                                                             "set");
393    
394            MutablePicoContainer pico = new DefaultPicoContainer();
395            pico.addAdapter(bAdapter);
396            pico.addAdapter(cAdapter);
397            pico.addAdapter(cNullAdapter);
398            pico.addComponent(ArrayList.class);
399    
400            C c = (C) cAdapter.getComponentInstance(pico);
401            assertTrue(c.instantiatedAsBean());
402            C c0 = (C) cNullAdapter.getComponentInstance(pico);
403            assertTrue(c0.instantiatedAsBean());
404        }
405    
406        public static class Yin {
407            private Yang yang;
408    
409            public void setYin(Yang yang) {
410                this.yang = yang;
411            }
412    
413            public Yang getYang() {
414                return yang;
415            }
416        }
417    
418        public static class Yang {
419            private Yin yin;
420    
421            public void setYang(Yin yin) {
422                this.yin = yin;
423            }
424    
425            public Yin getYin() {
426                return yin;
427            }
428        }
429    
430        // TODO PICO-188
431        // http://jira.codehaus.org/browse/PICO-188
432        public void FIXME_testShouldBeAbleToHandleMutualDependenciesWithSetterInjection() {
433            MutablePicoContainer pico = new DefaultPicoContainer(new Caching().wrap(new SetterInjection()));
434    
435            pico.addComponent(Yin.class);
436            pico.addComponent(Yang.class);
437    
438            Yin yin = pico.getComponent(Yin.class);
439            Yang yang = pico.getComponent(Yang.class);
440    
441            assertSame(yin, yang.getYin());
442            assertSame(yang, yin.getYang());
443        }
444        
445        public void testCustomLifecycleCanBeInjected() throws NoSuchMethodException {
446            RecordingLifecycleStrategy strategy = new RecordingLifecycleStrategy(new StringBuffer());
447            SetterInjector sica = new SetterInjector(
448                    NullLifecycle.class, NullLifecycle.class, new Parameter[0],
449                    new AbstractComponentMonitor(), strategy, "set");
450            Touchable touchable = new SimpleTouchable();
451            sica.start(touchable);
452            sica.stop(touchable);
453            sica.dispose(touchable);
454            assertEquals("<start<stop<dispose", strategy.recording());
455        }
456    
457    }