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 }