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 }