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 static org.junit.Assert.assertEquals; 013 import static org.junit.Assert.assertNotSame; 014 import static org.junit.Assert.assertSame; 015 016 import java.util.HashMap; 017 import java.util.Map; 018 import java.lang.reflect.Type; 019 020 import org.junit.Test; 021 import org.picocontainer.Characteristics; 022 import org.picocontainer.DefaultPicoContainer; 023 import org.picocontainer.MutablePicoContainer; 024 import org.picocontainer.PicoCompositionException; 025 import org.picocontainer.PicoContainer; 026 import org.picocontainer.adapters.AbstractAdapter; 027 import org.picocontainer.injectors.ConstructorInjection; 028 029 /** 030 * This class can be used to test out various things asked on the mailing list. 031 * Or to answer questions. 032 * 033 * @author Aslak Hellesøy 034 */ 035 @SuppressWarnings("serial") 036 public final class UserQuestionTestCase { 037 038 // From Scott Farquahsr 039 public static final class CheeseAdapter<T extends Cheese> extends AbstractAdapter<T> { 040 private final Map<String,?> bla; 041 042 public CheeseAdapter(Object componentKey, Class<T> componentImplementation, Map<String,?> cheeseMap) throws PicoCompositionException { 043 super(componentKey, componentImplementation); 044 this.bla = cheeseMap; 045 } 046 047 @SuppressWarnings("unchecked") 048 public T getComponentInstance(PicoContainer pico, Type into) throws PicoCompositionException { 049 return (T) bla.get("cheese"); 050 } 051 052 public void verify(PicoContainer pico) { 053 } 054 055 public String getDescriptor() { 056 return null; 057 } 058 } 059 060 public static interface Cheese { 061 String getName(); 062 } 063 064 public static class Gouda implements Cheese { 065 public String getName() { 066 return "Gouda"; 067 } 068 } 069 070 public static class Roquefort implements Cheese { 071 public String getName() { 072 return "Roquefort"; 073 } 074 } 075 076 public static class Omelette { 077 private final Cheese cheese; 078 079 public Omelette(Cheese cheese) { 080 this.cheese = cheese; 081 } 082 083 public Cheese getCheese() { 084 return cheese; 085 } 086 } 087 088 @Test public void testOmeletteCanHaveDifferentCheeseWithAFunnyComponentAdapter() { 089 Map<String,Cheese> cheeseMap = new HashMap<String,Cheese>(); 090 091 MutablePicoContainer pico = new DefaultPicoContainer(new ConstructorInjection()); 092 pico.addComponent(Omelette.class); 093 pico.addAdapter(new CheeseAdapter<Gouda>("scott", Gouda.class, cheeseMap)); 094 095 Cheese gouda = new Gouda(); 096 cheeseMap.put("cheese", gouda); 097 Omelette goudaOmelette = pico.getComponent(Omelette.class); 098 assertSame(gouda, goudaOmelette.getCheese()); 099 100 Cheese roquefort = new Roquefort(); 101 cheeseMap.put("cheese", roquefort); 102 Omelette roquefortOmelette = pico.getComponent(Omelette.class); 103 assertSame(roquefort, roquefortOmelette.getCheese()); 104 } 105 106 public static interface InterfaceX { 107 String getIt(); 108 } 109 110 public static class Enabled implements InterfaceX { 111 public String getIt() { 112 return "Enabled"; 113 } 114 } 115 116 public static class Disabled implements InterfaceX { 117 public String getIt() { 118 return "Disabled"; 119 } 120 } 121 122 @SuppressWarnings("unchecked") 123 public static class Something implements InterfaceX { 124 private final Disabled disabled; 125 private final Enabled enabled; 126 private final Map map; 127 128 public Something(Disabled disabled, Enabled enabled, Map map) { 129 this.disabled = disabled; 130 this.enabled = enabled; 131 this.map = map; 132 } 133 134 public String getIt() { 135 if (map.get("enabled") == null) { 136 return disabled.getIt(); 137 } else { 138 return enabled.getIt(); 139 } 140 } 141 } 142 143 public static class NeedsInterfaceX { 144 private final InterfaceX interfaceX; 145 146 public NeedsInterfaceX(InterfaceX interfaceX) { 147 this.interfaceX = interfaceX; 148 } 149 150 public String getIt() { 151 return interfaceX.getIt(); 152 } 153 } 154 155 @Test public void testMoreWeirdness() { 156 MutablePicoContainer pico = new DefaultPicoContainer(); 157 Map<String,String> map = new HashMap<String,String>(); 158 pico.addComponent(map); 159 // See class level javadoc in DefaultPicoContainer - about precedence. 160 pico.addComponent(InterfaceX.class, Something.class); 161 pico.addComponent(Disabled.class); 162 pico.addComponent(Enabled.class); 163 pico.addComponent(NeedsInterfaceX.class); 164 165 NeedsInterfaceX needsInterfaceX = pico.getComponent(NeedsInterfaceX.class); 166 assertEquals("Disabled", needsInterfaceX.getIt()); 167 map.put("enabled", "blah"); 168 assertEquals("Enabled", needsInterfaceX.getIt()); 169 } 170 171 // From John Tal 23/03/2004 172 public static interface ABC { 173 } 174 175 public static interface DEF { 176 } 177 178 public static class ABCImpl implements ABC { 179 public ABCImpl(DEF def) { 180 } 181 } 182 183 public static class DEFImpl implements DEF { 184 public DEFImpl() { 185 } 186 } 187 188 @Test public void testJohnTalOne() { 189 MutablePicoContainer picoContainer = new DefaultPicoContainer(); 190 191 picoContainer.addComponent("ABC", ABCImpl.class); 192 picoContainer.addComponent("DEF", DEFImpl.class); 193 194 assertEquals(ABCImpl.class, picoContainer.getComponent("ABC").getClass()); 195 } 196 197 public static interface Foo { 198 } 199 200 public static interface Bar { 201 } 202 203 public static class FooBar implements Foo, Bar { 204 } 205 206 public static class NeedsFoo { 207 private final Foo foo; 208 209 public NeedsFoo(Foo foo) { 210 this.foo = foo; 211 } 212 213 public Foo getFoo() { 214 return foo; 215 } 216 } 217 218 public static class NeedsBar { 219 private final Bar bar; 220 221 public NeedsBar(Bar bar) { 222 this.bar = bar; 223 } 224 225 public Bar getBar() { 226 return bar; 227 } 228 } 229 230 @Test public void testShouldBeAbleShareSameReferenceForDifferentTypes() { 231 MutablePicoContainer pico = new DefaultPicoContainer(); 232 pico.as(Characteristics.CACHE).addComponent(FooBar.class); 233 pico.addComponent(NeedsFoo.class); 234 pico.addComponent(NeedsBar.class); 235 NeedsFoo needsFoo = pico.getComponent(NeedsFoo.class); 236 NeedsBar needsBar = pico.getComponent(NeedsBar.class); 237 assertSame(needsFoo.getFoo(), needsBar.getBar()); 238 } 239 240 @Test public void testSeveralDifferentInstancesCanBeCreatedWithOnePreconfiguredContainer() { 241 // create a container that doesn't cache instances 242 MutablePicoContainer container = new DefaultPicoContainer(new ConstructorInjection()); 243 container.addComponent(NeedsBar.class); 244 245 Bar barOne = new FooBar(); 246 container.addComponent(Bar.class, barOne); 247 NeedsBar needsBarOne = container.getComponent(NeedsBar.class); 248 assertSame(barOne, needsBarOne.getBar()); 249 250 // reuse the same container - just flip out the existing foo. 251 Bar barTwo = new FooBar(); 252 container.removeComponent(Bar.class); 253 container.addComponent(Bar.class, barTwo); 254 NeedsBar needsBarTwo = container.getComponent(NeedsBar.class); 255 assertSame(barTwo, needsBarTwo.getBar()); 256 257 assertNotSame(needsBarOne, needsBarTwo); 258 } 259 }