    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     *****************************************************************************/
    009
    010    package org.picocontainer.injectors;
    011
    012    import static org.junit.Assert.assertNotNull;
    013    import static org.junit.Assert.assertTrue;import static org.junit.Assert.assertSame;
    014    import static org.junit.Assert.assertEquals;
    015    import static org.junit.Assert.fail;
    016    import org.junit.Test;
    017    import org.junit.runner.RunWith;
    018    import org.picocontainer.ComponentFactory;
    019    import org.picocontainer.DefaultPicoContainer;
    020    import org.picocontainer.ComponentMonitor;
    021    import org.picocontainer.ComponentAdapter;
    022    import org.picocontainer.PicoContainer;
    023    import org.picocontainer.PicoCompositionException;
    024    import org.picocontainer.Characteristics;
    025    import org.picocontainer.monitors.NullComponentMonitor;
    026    import org.picocontainer.behaviors.Caching;
    027    import org.picocontainer.containers.EmptyPicoContainer;
    028    import org.picocontainer.containers.TransientPicoContainer;
    029    import org.picocontainer.tck.AbstractComponentFactoryTest;
    030    import static org.picocontainer.tck.MockFactory.mockeryWithCountingNamingScheme;
    031    import org.jmock.integration.junit4.JMock;
    032    import org.jmock.Mockery;
    033    import org.jmock.Expectations;
    034    import org.jmock.api.Action;
    035    import org.jmock.api.Invocation;
    036    import org.hamcrest.Description;
    037
    038    import java.lang.reflect.Method;
    039    import java.lang.annotation.Retention;
    040    import java.lang.annotation.RetentionPolicy;
    041    import java.lang.annotation.Target;
    042    import java.lang.annotation.ElementType;
    043
    044    @RunWith(JMock.class)
    045    public class ReinjectionTestCase extends AbstractComponentFactoryTest {
    046
    047        private Mockery mockery = mockeryWithCountingNamingScheme();
    048
    049        @Retention(RetentionPolicy.RUNTIME)
    050        @Target(value={ElementType.METHOD, ElementType.FIELD})
    051        public @interface Hurrah {
    052        }
    053
    054        public static class NeedsShoe {
    055            private Shoe bar;
    056            private String string;
    057
    058            public NeedsShoe(Shoe bar) {
    059                this.bar = bar;
    060            }
    061
    062            @Hurrah
    063            public int doIt(String s) {
    064                this.string = s;
    065                return Integer.parseInt(s) / 2;
    066            }
    067        }
    068
    069        public static class Shoe {
    070        }
    071
    072        private static Method DOIT_METHOD = NeedsShoe.class.getMethods()[0];
    073
    074        @Test public void testCachedComponentCanBeReflectionMethodReinjectedByATransientChildContainer() {
    075            cachedComponentCanBeReinjectedByATransientChildContainer(new MethodInjection(DOIT_METHOD));
    076        }
    077
    078        @Test public void testCachedComponentCanBeMethodNameReinjectedByATransientChildContainer() {
    079            cachedComponentCanBeReinjectedByATransientChildContainer(new MethodInjection("doIt"));
    080        }
    081
    082        @Test public void testCachedComponentCanBeAnnotatedMethodReinjectedByATransientChildContainer() {
    083            cachedComponentCanBeReinjectedByATransientChildContainer(new AnnotatedMethodInjection(Hurrah.class, false));
    084        }
    085
    086        private void cachedComponentCanBeReinjectedByATransientChildContainer(AbstractInjectionFactory methodInjection) {
    087            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
    088            parent.addComponent(NeedsShoe.class);
    089            parent.addComponent(Shoe.class);
    090            parent.addComponent("12");
    091
    092            NeedsShoe needsShoe = parent.getComponent(NeedsShoe.class);
    093            assertNotNull(needsShoe.bar);
    094            assertTrue(needsShoe.string == null);
    095
    096            TransientPicoContainer tpc = new TransientPicoContainer(new Reinjection(methodInjection, parent), parent);
    097            tpc.addComponent(NeedsShoe.class);
    098
    099            NeedsShoe needsShoe2 = tpc.getComponent(NeedsShoe.class);
    100            assertSame(needsShoe, needsShoe2);
    101            assertNotNull(needsShoe2.bar);
    102            assertNotNull(needsShoe2.string);
    103
    104            NeedsShoe needsShoe3 = parent.getComponent(NeedsShoe.class);
    105            assertSame(needsShoe, needsShoe3);
    106            assertNotNull(needsShoe3.bar);
    107            assertNotNull(needsShoe3.string);
    108        }
    109
    110        @Test
    111        public void confirmThatReinjectionCanLeverageParameterNamesForDisambiguation() {
    112            MethodInjection methodInjection = new MethodInjection(DOIT_METHOD);
    113            DefaultPicoContainer parent = new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
    114            parent.addComponent(NeedsShoe.class);
    115            parent.addComponent(Shoe.class);
    116            parent.addComponent("a", "1333");
    117            parent.addComponent("s", "12");
    118            parent.addComponent("tjklhjkjhkjh", "44");
    119
    120            NeedsShoe needsShoe = parent.getComponent(NeedsShoe.class);
    121            assertNotNull(needsShoe.bar);
    122            assertTrue(needsShoe.string == null);
    123
    124            Reinjection reinjection = new Reinjection(methodInjection, parent);
    125            TransientPicoContainer tpc = new TransientPicoContainer(reinjection, parent);
    126            tpc.as(Characteristics.USE_NAMES).addComponent(NeedsShoe.class);
    127
    128            NeedsShoe needsShoe2 = tpc.getComponent(NeedsShoe.class);
    129            assertSame(needsShoe, needsShoe2);
    130            assertNotNull(needsShoe2.bar);
    131            assertNotNull(needsShoe2.string);
    132            assertEquals("12", needsShoe2.string);
    133
    134        }
    135
    136        @Test public void testCachedComponentCanBeReinjectedByATransientReflectionMethodReinjector() {
    137            cachedComponentCanBeReinjectedByATransientReinjector(new MethodInjection(DOIT_METHOD));
    138        }
    139        @Test public void testCachedComponentCanBeReinjectedByATransientMethodNameReinjector() {
    140            cachedComponentCanBeReinjectedByATransientReinjector(new MethodInjection("doIt"));
    141        }
    142        @Test public void testCachedComponentCanBeReinjectedByATransientAnnotatedMethodReinjector() {
    143            cachedComponentCanBeReinjectedByATransientReinjector(new AnnotatedMethodInjection(Hurrah.class, false));
    144        }
    145
    146        public static class ReturnParameterAction implements Action {
    147            private final int parameter;
    148
    149            public ReturnParameterAction(int parameter) {
    150                this.parameter = parameter;
    151            }
    152
    153            public void describeTo(Description description) {
    154                // describe it
    155            }
    156
    157            public Object invoke(Invocation invocation) {
    158                return invocation.getParameter(parameter);
    159            }
    160        }
    161
    162        private void cachedComponentCanBeReinjectedByATransientReinjector(AbstractInjectionFactory methodInjection) {
    163            final DefaultPicoContainer parent = new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
    164            parent.setName("parent");
    165            parent.addComponent(NeedsShoe.class);
    166            parent.addComponent(Shoe.class);
    167            parent.addComponent("12");
    168
    169            final NeedsShoe foo = parent.getComponent(NeedsShoe.class);
    170            assertNotNull(foo.bar);
    171            assertTrue(foo.string == null);
    172
    173            final ComponentMonitor cm = mockery.mock(ComponentMonitor.class);
    174            Reinjector reinjector = new Reinjector(parent, cm);
    175            mockery.checking(new Expectations() {{
    176                atLeast(1).of(cm).newInjector(with(any(org.picocontainer.Injector.class)));
    177                will(new ReturnParameterAction(0));
    178                one(cm).invoking(with(any(PicoContainer.class)), with(any(ComponentAdapter.class)),
    179                        with(any(Method.class)), with(any(Object.class)));
    180            }});
    181
    182            Object o = reinjector.reinject(NeedsShoe.class, methodInjection);
    183            int result = (Integer) o;
    184            assertEquals(6, result);
    185
    186            NeedsShoe foo3 = parent.getComponent(NeedsShoe.class);
    187            assertSame(foo, foo3);
    188            assertNotNull(foo3.bar);
    189            assertNotNull(foo3.string);
    190            assertEquals("12", foo3.string);
    191        }
    192
    193        @Test public void testOverloadedReinjectMethodsAreIdentical() {
    194            final DefaultPicoContainer parent = new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
    195            parent.addComponent(NeedsShoe.class);
    196            parent.addComponent(Shoe.class);
    197            parent.addComponent("12");
    198
    199            final ComponentMonitor cm = new NullComponentMonitor();
    200            Reinjector reinjector = new Reinjector(parent, cm);
    201
    202            int result = (Integer) reinjector.reinject(NeedsShoe.class, DOIT_METHOD);
    203            assertEquals(6, (int) (Integer) reinjector.reinject(NeedsShoe.class, DOIT_METHOD));
    204            assertEquals(6, (int) (Integer) reinjector.reinject(NeedsShoe.class, new MethodInjection(DOIT_METHOD)));
    205
    206        }
    207
    208        protected ComponentFactory createComponentFactory() {
    209            return new Reinjection(new MethodInjection(DOIT_METHOD), new EmptyPicoContainer());
    210        }
    211
    212        @Test
    213        public void testRegisterComponent() throws PicoCompositionException {
    214            try {
    215                super.testRegisterComponent();
    216                fail();
    217            } catch (PicoCompositionException e) {
    218                assertTrue(e.getMessage().contains("] not on impl "));
    219            }
    220        }
    221
    222        @Test
    223        public void testUnregisterComponent() throws PicoCompositionException {
    224            try {
    225                super.testUnregisterComponent();
    226                fail();
    227            } catch (PicoCompositionException e) {
    228                assertTrue(e.getMessage().contains("] not on impl "));
    229            }
    230        }
    231
    232        @Test
    233        public void testEquals() throws PicoCompositionException {
    234            try {
    235                super.testEquals();
    236                fail();
    237            } catch (PicoCompositionException e) {
    238                assertTrue(e.getMessage().contains("] not on impl "));
    239            }
    240        }
    241    }