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