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