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(), "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(),
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(), "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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
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(),
264 "set", false);
265 SetterInjector bAdapter = new SetterInjector("b", B.class, Parameter.DEFAULT, new NullComponentMonitor(),
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(),
282 "set", false);
283 SetterInjector bAdapter = new SetterInjector("b", B.class, null, new NullComponentMonitor(),
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(),
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(),
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, new Parameter[0], new NullComponentMonitor(),
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(),
397 "set", false);
398 SetterInjector cAdapter = new SetterInjector("c", C.class, null, new NullComponentMonitor(),
399 "set", false);
400 SetterInjector cNullAdapter = new SetterInjector("c0", C.class, null, new NullComponentMonitor(),
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 }