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     *****************************************************************************/
009    package org.picocontainer.injectors;
010    
011    import org.junit.Test;
012    import org.picocontainer.DefaultPicoContainer;
013    import org.picocontainer.MutablePicoContainer;
014    import org.picocontainer.PicoCompositionException;
015    import org.picocontainer.PicoContainer;
016    import org.picocontainer.annotations.Inject;
017    
018    import java.lang.reflect.Type;
019    import java.util.Map;
020    
021    import static org.junit.Assert.assertEquals;
022    import static org.junit.Assert.assertNotNull;
023    import static org.junit.Assert.assertNotSame;
024    
025    public 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    }