    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(), new NullLifecycleStrategy(), "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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(), "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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    264                                                         "set", false);
    265            SetterInjector bAdapter = new SetterInjector("b", B.class, Parameter.DEFAULT, new NullComponentMonitor(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    282                                                         "set", false);
    283            SetterInjector bAdapter = new SetterInjector("b", B.class, null, new NullComponentMonitor(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    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, Parameter.ZERO, new NullComponentMonitor(), new NullLifecycleStrategy(),
    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(), new NullLifecycleStrategy(),
    397                                                         "set", false);
    398            SetterInjector cAdapter = new SetterInjector("c", C.class, null, new NullComponentMonitor(), new NullLifecycleStrategy(),
    399                                                         "set", false);
    400            SetterInjector cNullAdapter = new SetterInjector("c0", C.class, null, new NullComponentMonitor(), new NullLifecycleStrategy(),
    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        @Test public void testCustomLifecycleCanBeInjected() throws NoSuchMethodException {
    454            RecordingLifecycleStrategy strategy = new RecordingLifecycleStrategy(new StringBuffer());
    455            SetterInjector sica = new SetterInjector(
    456                    NullLifecycle.class, NullLifecycle.class, new Parameter[0],
    457                    new AbstractComponentMonitor(), strategy, "set", false);
    458            Touchable touchable = new SimpleTouchable();
    459            sica.start(touchable);
    460            sica.stop(touchable);
    461            sica.dispose(touchable);
    462            assertEquals("<start<stop<dispose", strategy.recording());
    463        }
    464
    465
    466    }