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