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 @SuppressWarnings("serial") 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, ComponentAdapter.NOTHING.class); 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, ComponentAdapter.NOTHING.class); 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, ComponentAdapter.NOTHING.class); 409 assertTrue(c.instantiatedAsBean()); 410 C c0 = (C) cNullAdapter.getComponentInstance(pico, ComponentAdapter.NOTHING.class); 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 }