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.defaults;
011
012 import java.awt.event.ActionEvent;
013 import java.awt.event.ActionListener;
014 import java.lang.reflect.Constructor;
015 import java.lang.reflect.InvocationTargetException;
016 import java.util.HashMap;
017 import java.util.Map;
018
019 import org.jmock.Mock;
020 import org.jmock.core.Constraint;
021 import org.picocontainer.ComponentAdapter;
022 import org.picocontainer.ComponentMonitor;
023 import org.picocontainer.MutablePicoContainer;
024 import org.picocontainer.Parameter;
025 import org.picocontainer.PicoInitializationException;
026 import org.picocontainer.PicoIntrospectionException;
027 import org.picocontainer.PicoRegistrationException;
028 import org.picocontainer.tck.AbstractComponentAdapterTestCase;
029 import org.picocontainer.testmodel.DependsOnTouchable;
030 import org.picocontainer.testmodel.NullLifecycle;
031 import org.picocontainer.testmodel.SimpleTouchable;
032 import org.picocontainer.testmodel.Touchable;
033
034
035 public class ConstructorInjectionComponentAdapterTestCase extends AbstractComponentAdapterTestCase {
036
037 protected Class getComponentAdapterType() {
038 return ConstructorInjectionComponentAdapter.class;
039 }
040
041 protected ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer) {
042 return new ConstructorInjectionComponentAdapter("foo", A.class);
043 }
044
045 public static class A {
046 public A() {
047 fail("verification should not instantiate");
048 }
049 }
050
051 public static class B {
052 public B(A a) {
053 fail("verification should not instantiate");
054 }
055 }
056
057 protected ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer) {
058 picoContainer.registerComponentImplementation(A.class);
059 return new ConstructorInjectionComponentAdapter(B.class, B.class);
060 }
061
062 protected ComponentAdapter prepDEF_visitable() {
063 return new ConstructorInjectionComponentAdapter("bar", B.class, new Parameter[]{ComponentParameter.DEFAULT});
064 }
065
066 protected ComponentAdapter prepDEF_isAbleToTakeParameters(MutablePicoContainer picoContainer) {
067 picoContainer.registerComponentImplementation(SimpleTouchable.class);
068 return new ConstructorInjectionComponentAdapter(
069 NamedDependsOnTouchable.class, NamedDependsOnTouchable.class, new Parameter[]{
070 ComponentParameter.DEFAULT, new ConstantParameter("Name")});
071 }
072
073 protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) {
074 return new ConstructorInjectionComponentAdapter(SimpleTouchable.class, SimpleTouchable.class);
075 }
076
077 protected ComponentAdapter prepSER_isXStreamSerializable(final MutablePicoContainer picoContainer) {
078 return prepSER_isSerializable(picoContainer);
079 }
080
081 public static class NamedDependsOnTouchable extends DependsOnTouchable {
082 public NamedDependsOnTouchable(Touchable t, String name) {
083 super(t);
084 }
085 }
086
087 protected ComponentAdapter prepVER_verificationFails(MutablePicoContainer picoContainer) {
088 return new ConstructorInjectionComponentAdapter(DependsOnTouchable.class, DependsOnTouchable.class);
089 }
090
091 protected ComponentAdapter prepINS_createsNewInstances(MutablePicoContainer picoContainer) {
092 return new ConstructorInjectionComponentAdapter(SimpleTouchable.class, SimpleTouchable.class);
093 }
094
095 public static class Erroneous {
096 public Erroneous() {
097 throw new VerifyError("test");
098 }
099 }
100
101 protected ComponentAdapter prepINS_errorIsRethrown(MutablePicoContainer picoContainer) {
102 return new ConstructorInjectionComponentAdapter(Erroneous.class, Erroneous.class);
103 }
104
105 public static class RuntimeThrowing {
106 public RuntimeThrowing() {
107 throw new RuntimeException("test");
108 }
109 }
110
111 protected ComponentAdapter prepINS_runtimeExceptionIsRethrown(MutablePicoContainer picoContainer) {
112 return new ConstructorInjectionComponentAdapter(RuntimeThrowing.class, RuntimeThrowing.class);
113 }
114
115 public static class NormalExceptionThrowing {
116 public NormalExceptionThrowing() throws Exception {
117 throw new Exception("test");
118 }
119 }
120
121 protected ComponentAdapter prepINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException(
122 MutablePicoContainer picoContainer) {
123 return new ConstructorInjectionComponentAdapter(NormalExceptionThrowing.class, NormalExceptionThrowing.class);
124 }
125
126 protected ComponentAdapter prepRES_dependenciesAreResolved(MutablePicoContainer picoContainer) {
127 picoContainer.registerComponentImplementation(SimpleTouchable.class);
128 return new ConstructorInjectionComponentAdapter(DependsOnTouchable.class, DependsOnTouchable.class);
129 }
130
131 public static class C1 {
132 public C1(C2 c2) {
133 fail("verification should not instantiate");
134 }
135 }
136
137 public static class C2 {
138 public C2(C1 c1) {
139 fail("verification should not instantiate");
140 }
141 }
142
143 protected ComponentAdapter prepRES_failingVerificationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
144 final ComponentAdapter componentAdapter = new ConstructorInjectionComponentAdapter(C1.class, C1.class);
145 picoContainer.registerComponent(componentAdapter);
146 picoContainer.registerComponentImplementation(C2.class, C2.class);
147 return componentAdapter;
148 }
149
150 protected ComponentAdapter prepRES_failingInstantiationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
151 final ComponentAdapter componentAdapter = new ConstructorInjectionComponentAdapter(C1.class, C1.class);
152 picoContainer.registerComponent(componentAdapter);
153 picoContainer.registerComponentImplementation(C2.class, C2.class);
154 return componentAdapter;
155 }
156
157 public void testNormalExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() {
158 DefaultPicoContainer picoContainer = new DefaultPicoContainer();
159 picoContainer.registerComponentImplementation(NormalExceptionThrowing.class);
160 try {
161 picoContainer.getComponentInstance(NormalExceptionThrowing.class);
162 fail();
163 } catch (PicoInvocationTargetInitializationException e) {
164 assertEquals("test", e.getCause().getMessage());
165 }
166 }
167
168 public abstract class InstantiationExceptionThrowing {
169 public InstantiationExceptionThrowing() {
170 }
171 }
172
173 public void testInstantiationExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() {
174 DefaultPicoContainer picoContainer = new DefaultPicoContainer();
175 try {
176 picoContainer.registerComponentImplementation(InstantiationExceptionThrowing.class);
177 picoContainer.getComponentInstance(InstantiationExceptionThrowing.class);
178 fail();
179 } catch (NotConcreteRegistrationException e) {
180 }
181 }
182
183 public class IllegalAccessExceptionThrowing {
184 private IllegalAccessExceptionThrowing() {
185 }
186 }
187
188 // TODO test fails currently, since non accessible ctors are filtered out, because of
189 // PICO-201.
190 // Maybe we can activate it again with some kind of SecurityManager & Policy combination?
191 public void XXXtestIllegalAccessExceptionThrownInCtorIsRethrownInsideInvocationTargetExeption() {
192 DefaultPicoContainer picoContainer = new DefaultPicoContainer();
193 try {
194 picoContainer.registerComponentImplementation(IllegalAccessExceptionThrowing.class);
195 picoContainer.getComponentInstance(IllegalAccessExceptionThrowing.class);
196 fail();
197 } catch (PicoInitializationException e) {
198 assertTrue(e.getCause().getMessage().indexOf(IllegalAccessExceptionThrowing.class.getName()) > 0);
199 }
200 }
201
202 public void testPicoInitializationExceptionThrownBecauseOfFilteredConstructors() {
203 DefaultPicoContainer picoContainer = new DefaultPicoContainer();
204 try {
205 picoContainer.registerComponentImplementation(IllegalAccessExceptionThrowing.class);
206 picoContainer.getComponentInstance(IllegalAccessExceptionThrowing.class);
207 fail();
208 } catch (PicoInitializationException e) {
209 assertTrue(e.getMessage().indexOf(IllegalAccessExceptionThrowing.class.getName()) > 0);
210 }
211 }
212
213 public void testRegisterAbstractShouldFail() throws PicoRegistrationException, PicoIntrospectionException {
214 MutablePicoContainer pico = new DefaultPicoContainer();
215
216 try {
217 pico.registerComponentImplementation(Runnable.class);
218 fail("Shouldn't be allowed to register abstract classes or interfaces.");
219 } catch (NotConcreteRegistrationException e) {
220 assertEquals(Runnable.class, e.getComponentImplementation());
221 assertTrue(e.getMessage().indexOf(Runnable.class.getName()) > 0);
222 }
223 }
224
225 private static class Private {
226 private Private() {
227 }
228 }
229
230 private static class NotYourBusiness {
231 private NotYourBusiness(Private aPrivate) {
232 assertNotNull(aPrivate);
233 }
234 }
235
236 // http://jira.codehaus.org/browse/PICO-189
237 public void testShouldBeAbleToInstantiateNonPublicClassesWithNonPublicConstructors() {
238 DefaultPicoContainer pico = new DefaultPicoContainer(new ConstructorInjectionComponentAdapterFactory(true));
239 pico.registerComponentImplementation(Private.class);
240 pico.registerComponentImplementation(NotYourBusiness.class);
241 assertNotNull(pico.getComponentInstance(NotYourBusiness.class));
242 }
243
244 static public class Component201 {
245 public Component201(final String s) {
246 }
247
248 protected Component201(final Integer i, final Boolean b) {
249 fail("Wrong constructor taken.");
250 }
251 }
252
253 // http://jira.codehaus.org/browse/PICO-201
254 public void testShouldNotConsiderNonPublicConstructors() {
255 DefaultPicoContainer pico = new DefaultPicoContainer();
256 pico.registerComponentImplementation(Component201.class);
257 pico.registerComponentInstance(new Integer(2));
258 pico.registerComponentInstance(new Boolean(true));
259 pico.registerComponentInstance("Hello");
260 assertNotNull(pico.getComponentInstance(Component201.class));
261 }
262
263 public void testMonitoringHappensBeforeAndAfterInstantiation() throws NoSuchMethodException {
264 Mock monitor = mock(ComponentMonitor.class);
265 Constructor emptyHashMapCtor = HashMap.class.getConstructor(new Class[0]);
266 monitor.expects(once()).method("instantiating").with(eq(emptyHashMapCtor));
267 Constraint durationIsGreaterThanOrEqualToZero = new Constraint() {
268 public boolean eval(Object o) {
269 Long duration = (Long)o;
270 return 0 <= duration.longValue();
271 }
272
273 public StringBuffer describeTo(StringBuffer stringBuffer) {
274 return stringBuffer.append("The endTime wasn't after the startTime");
275 }
276 };
277 Constraint isAHashMapThatWozCreated = new Constraint() {
278 public boolean eval(Object o) {
279 return o instanceof HashMap;
280 }
281
282 public StringBuffer describeTo(StringBuffer stringBuffer) {
283 return stringBuffer.append("Should have been a hashmap");
284 }
285 };
286
287 Constraint injectedIsEmptyArray = new Constraint() {
288 public boolean eval(Object o) {
289 Object[] injected = (Object[])o;
290 return 0 == injected.length;
291 }
292
293 public StringBuffer describeTo(StringBuffer stringBuffer) {
294 return stringBuffer.append("Should have had nothing injected into it");
295 }
296 };
297
298 monitor.expects(once()).method("instantiated").with(eq(emptyHashMapCtor), isAHashMapThatWozCreated, injectedIsEmptyArray, durationIsGreaterThanOrEqualToZero);
299 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter(
300 Map.class, HashMap.class, new Parameter[0], false, (ComponentMonitor)monitor.proxy());
301 cica.getComponentInstance(null);
302 }
303
304 public void testMonitoringHappensBeforeAndOnFailOfImpossibleComponentsInstantiation() throws NoSuchMethodException {
305 Mock monitor = mock(ComponentMonitor.class);
306 Constructor barfingActionListenerCtor = BarfingActionListener.class.getConstructor(new Class[0]);
307 monitor.expects(once()).method("instantiating").with(eq(barfingActionListenerCtor));
308
309 Constraint isITE = new Constraint() {
310 public boolean eval(Object o) {
311 Exception ex = (Exception)o;
312 return ex instanceof InvocationTargetException;
313 }
314
315 public StringBuffer describeTo(StringBuffer stringBuffer) {
316 return stringBuffer.append("Should have been unable to instantiate");
317 }
318 };
319
320 monitor.expects(once()).method("instantiationFailed").with(eq(barfingActionListenerCtor), isITE);
321 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter(
322 ActionListener.class, BarfingActionListener.class, new Parameter[0], false, (ComponentMonitor)monitor.proxy());
323 try {
324 cica.getComponentInstance(null);
325 fail("Should barf");
326 } catch (RuntimeException e) {
327 assertEquals("Barf!", e.getMessage());
328 }
329 }
330
331 private static class BarfingActionListener implements ActionListener {
332 public BarfingActionListener() {
333 throw new RuntimeException("Barf!");
334 }
335
336 public void actionPerformed(ActionEvent e) {
337 }
338 }
339
340 public void testCustomLifecycleCanBeInjected() throws NoSuchMethodException {
341 RecordingLifecycleStrategy strategy = new RecordingLifecycleStrategy(new StringBuffer());
342 ConstructorInjectionComponentAdapter cica = new ConstructorInjectionComponentAdapter(
343 NullLifecycle.class, NullLifecycle.class, new Parameter[0], false,
344 new DelegatingComponentMonitor(), strategy);
345 Touchable touchable = new SimpleTouchable();
346 cica.start(touchable);
347 cica.stop(touchable);
348 cica.dispose(touchable);
349 assertEquals("<start<stop<dispose", strategy.recording());
350 }
351 }