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