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 *****************************************************************************/
009package org.picocontainer.injectors;
010
011import org.junit.Test;
012import org.picocontainer.DefaultPicoContainer;
013import org.picocontainer.MutablePicoContainer;
014import org.picocontainer.PicoCompositionException;
015import org.picocontainer.PicoContainer;
016import org.picocontainer.annotations.Inject;
017
018import java.lang.reflect.Type;
019import java.util.Map;
020
021import static org.junit.Assert.assertEquals;
022import static org.junit.Assert.assertNotNull;
023import static org.junit.Assert.assertNotSame;
024
025public class FactoryInjectorTestCase {
026
027    public static interface Swede {
028    }
029
030    public static class Turnip2 {
031        Swede swede;
032        private final String foo;
033        public Turnip2(String foo, Swede swede) {
034            this.foo = foo;
035            assertNotNull(swede);
036            this.swede = swede;
037        }
038        public Swede getSwede() {
039            return swede;
040        }
041
042        public String getFoo() {
043            return foo;
044        }                     
045    }
046
047    public static class Turnip {
048        @Inject
049        Swede swede;
050        private final String foo;
051
052        public Turnip(String foo) {
053            this.foo = foo;
054        }
055
056        public Swede getSwede() {
057            return swede;
058        }
059
060        public String getFoo() {
061            return foo;
062        }
063    }
064
065    @Test
066    public void testThatComponentCanHaveAProvidedDependency() {
067        MutablePicoContainer container = new DefaultPicoContainer(new MultiInjection());
068        container.addComponent(String.class, "foo");
069        container.addComponent(Turnip.class);
070        container.addAdapter(new SwedeFactoryInjector());
071        Turnip t = container.getComponent(Turnip.class);
072        assertNotNull(t);
073        assertEquals("Swede for " + Turnip.class.getName(), t.getSwede().toString());
074        assertEquals("foo", t.getFoo());
075
076    }
077
078    @Test
079    public void testThatComponentCanHaveAProvidedDependencyWithInlinedFactoryInjector() {
080        MutablePicoContainer container = new DefaultPicoContainer(new MultiInjection());
081        container.addComponent(String.class, "foo");
082        container.addComponent(Turnip.class);
083        container.addAdapter(new FactoryInjector<Swede>() {
084            public Swede getComponentInstance(PicoContainer container, final Type into) {
085                return new Swede() {
086                    public String toString() {
087                        return "Swede for " + ((InjectInto) into).getIntoClass().getName();
088                    }
089                };
090            }
091        });
092        Turnip t = container.getComponent(Turnip.class);
093        assertNotNull(t);
094        assertEquals("Swede for " + Turnip.class.getName(), t.getSwede().toString());
095        assertEquals("foo", t.getFoo());
096
097    }
098
099    @Test
100    public void testThatComponentCanHaveAProvidedDependencyWithInlinedFactoryInjector2() {
101        MutablePicoContainer container = new DefaultPicoContainer(new MultiInjection());
102        container.addComponent(String.class, "foo");
103        container.addComponent(Turnip.class);
104        container.addAdapter(new FactoryInjector(Swede.class) {
105            public Swede getComponentInstance(PicoContainer container, final Type into) {
106                return new Swede() {
107                    public String toString() {
108                        return "Swede for " + ((InjectInto) into).getIntoClass().getName();
109                    }
110                };
111            }
112        });
113        Turnip t = container.getComponent(Turnip.class);
114        assertNotNull(t);
115        assertEquals("Swede for " + Turnip.class.getName(), t.getSwede().toString());
116        assertEquals("foo", t.getFoo());
117
118    }
119
120    @Test
121    public void testThatComponentCanHaveAProvidedDependencyWithInlinedFactoryInjector3() {
122        MutablePicoContainer container = new DefaultPicoContainer(new MultiInjection());
123        container.addComponent(String.class, "foo");
124        container.addComponent(Turnip.class);
125        container.addAdapter(new FactoryInjector(Swede.class) {
126            public Swede getComponentInstance(PicoContainer container, final Type into) {
127                return new Swede() {
128                    public String toString() {
129                        return "Swede for " + ((InjectInto) into).getIntoClass().getName();
130                    }
131                };
132            }
133        });
134        Turnip t = container.getComponent(Turnip.class);
135        assertNotNull(t);
136        assertEquals("Swede for " + Turnip.class.getName(), t.getSwede().toString());
137        assertEquals("foo", t.getFoo());
138
139    }
140
141
142    @Test
143    public void testThatComponentCanHaveAProvidedDependencyViaConstructor() {
144        MutablePicoContainer container = new DefaultPicoContainer();
145        container.addComponent(String.class, "foo");
146        container.addComponent(Turnip2.class);
147        container.addAdapter(new SwedeFactoryInjector());
148        Turnip2 t = container.getComponent(Turnip2.class);
149        assertNotNull(t);
150        assertEquals("Swede for " + Turnip2.class.getName(), t.getSwede().toString());
151        assertEquals("foo", t.getFoo());
152
153    }
154
155    @Test
156    public void testThatComponentCanHaveAProvidedDependencyViaConstructorADifferentWay() {
157        MutablePicoContainer container = new DefaultPicoContainer();
158        container.addComponent(String.class, "foo");
159        container.addComponent(Turnip2.class);
160        container.addAdapter(new Swede2FactoryInjector()); // this injector defines Swede2 as key in its ctor
161        Turnip2 t = container.getComponent(Turnip2.class);
162        assertNotNull(t);
163        assertEquals("Swede for " + Turnip2.class.getName(), t.getSwede().toString());
164        assertEquals("foo", t.getFoo());
165
166    }
167
168    private static class SwedeFactoryInjector extends FactoryInjector<Swede> {
169        public Swede getComponentInstance(PicoContainer container, final Type into) throws PicoCompositionException {
170            // Mauro: you can do anything in here by way of startegy for injecting a specific logger :-)
171            return new Swede() {
172                public String toString() {
173                    return "Swede for " + ((InjectInto) into).getIntoClass().getName();
174                }
175            };
176        }
177    }
178
179    private static class Swede2FactoryInjector extends FactoryInjector {
180        private Swede2FactoryInjector() {
181            super(Swede.class);
182        }
183
184        public Swede getComponentInstance(PicoContainer container, final Type into) throws PicoCompositionException {
185            // Mauro: you can do anything in here by way of startegy for injecting a specific logger :-)
186            return new Swede() {
187                public String toString() {
188                    return "Swede for " + ((InjectInto) into).getIntoClass().getName();
189                }
190            };
191        }
192    }
193
194    private abstract class Footle<T> {
195        private class ServiceConnectionInjector extends FactoryInjector<T> {
196            public T getComponentInstance(PicoContainer container, Type into) {
197                System.out.println("**** injector called for " + into);
198                return null;
199            }
200        }
201
202        private void addAdapter(MutablePicoContainer mpc) {
203            mpc.addAdapter(new ServiceConnectionInjector());
204        }
205    }
206
207    public static interface Tree {
208        String leafColor();
209    }
210    public static class OakTree implements Tree {
211        private String leafColor;
212
213        public OakTree(String leafColor) {
214            this.leafColor = leafColor;
215        }
216
217        public String leafColor() {
218            return leafColor;
219        }
220    }
221
222    @Test public void ensureSophistcatedFactorInjectorCaseIsPossible() {
223
224        DefaultPicoContainer pico = new DefaultPicoContainer();
225        pico.addConfig("leafColor", "green");
226        pico.addComponent(Tree.class, OakTree.class);
227
228        Footle<Map> ft = new Footle<Map>(){};
229
230        ft.addAdapter(pico);
231
232        Tree tree = pico.getComponent(Tree.class);
233    }
234
235    private static class KeyAwareSwedeFactoryInjector extends FactoryInjector<Swede> {
236
237        public Swede getComponentInstance(PicoContainer container, final Type into) throws PicoCompositionException {
238            return new Swede() {
239                public String toString() {
240                    InjectInto intoType = (InjectInto) into;
241                    return "Swede for " + intoType.getIntoClass().getName() + " " + intoType.getIntoKey();
242                }
243            };
244        }
245    }
246
247    @Test
248    public void testThatFactoryCanUseTargetComponentKey() {
249        MutablePicoContainer container = new DefaultPicoContainer(new MultiInjection());
250        container.addComponent(String.class, "foo");
251        container.addComponent("turnip1", Turnip.class);
252        container.addComponent("turnip2", Turnip.class);
253        container.addAdapter(new KeyAwareSwedeFactoryInjector());
254        Turnip turnip1 = (Turnip)container.getComponent("turnip1");
255        Turnip turnip2 = (Turnip)container.getComponent("turnip2");
256        assertNotNull(turnip1);
257        assertNotNull(turnip2);
258        assertNotSame(turnip1, turnip2);
259        assertNotSame(turnip1.getSwede(), turnip2.getSwede());
260        assertEquals("Swede for " + Turnip.class.getName() + " turnip1", turnip1.getSwede().toString());
261        assertEquals("Swede for " + Turnip.class.getName() + " turnip2", turnip2.getSwede().toString());        
262    }
263
264    @Test
265    public void brendansNullTypeCase() {
266        MutablePicoContainer pico = new DefaultPicoContainer();
267        pico.addComponent(BrendansComponent.class);
268        pico.addAdapter(new BrendansLoggerInjector());
269
270        BrendansComponent bc = pico.getComponent(BrendansComponent.class);
271        assertEquals("org.picocontainer.injectors.InjectInto", bc.logger.canonicalName);
272    }
273
274    public static class BrendansLogger {
275        private String canonicalName;
276
277        public BrendansLogger(String canonicalName) {
278            this.canonicalName = canonicalName;
279        }
280
281        public static BrendansLogger getLogger(String canonicalName) {
282            return new BrendansLogger(canonicalName);
283        }
284    }
285
286    public static class BrendansComponent {
287        BrendansLogger logger;
288
289        public BrendansComponent(BrendansLogger logger) {
290            this.logger = logger;
291        }
292    }
293
294    public static class BrendansLoggerInjector extends FactoryInjector<BrendansLogger> {
295
296        @Override
297        public BrendansLogger getComponentInstance(PicoContainer arg0, final Type arg1)
298                throws PicoCompositionException {
299            return BrendansLogger.getLogger(arg1.getClass().getCanonicalName());
300        }
301
302    }
303
304}