001    package org.picocontainer.adapters;
002    
003    import static org.junit.Assert.assertEquals;
004    
005    import java.io.Serializable;
006    import java.lang.annotation.ElementType;
007    import java.lang.annotation.Retention;
008    import java.lang.annotation.RetentionPolicy;
009    import java.lang.annotation.Target;
010    import java.lang.reflect.Field;
011    import java.util.Properties;
012    
013    import org.junit.Test;
014    import org.picocontainer.Characteristics;
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.ComponentMonitor;
017    import org.picocontainer.DefaultPicoContainer;
018    import org.picocontainer.InjectionFactory;
019    import org.picocontainer.LifecycleStrategy;
020    import org.picocontainer.MutablePicoContainer;
021    import org.picocontainer.Parameter;
022    import org.picocontainer.PicoCompositionException;
023    import org.picocontainer.PicoContainer;
024    import org.picocontainer.behaviors.AbstractBehaviorFactory;
025    import org.picocontainer.injectors.AbstractInjector;
026    
027    
028    /**
029     * @author Paul Hammant
030     * @author Jörg Schaible
031     */
032    public class SimpleNamedBindingAnnotationTestCase {
033    
034        @Test public void testNamedBinding() {
035            MutablePicoContainer mpc = new DefaultPicoContainer(new FieldInjection());
036            mpc.addComponent(FruitBasket.class);
037            mpc.addComponent(bindKey(Apple.class, "one"), AppleImpl1.class);
038            mpc.addComponent(bindKey(Apple.class, "two"), AppleImpl2.class);
039            mpc.addComponent(bindKey(Apple.class, "three"), AppleImpl3.class);
040            mpc.addComponent(bindKey(Apple.class, "four"), AppleImpl4.class);
041            // this level of terseness is the other way ....
042            // this should not be barfing if if we can get binding to annotations working
043            FruitBasket fb = mpc.getComponent(FruitBasket.class);
044            assertEquals(fb.one.getX(), 1);
045            assertEquals(fb.two.getX(), 2);
046            assertEquals(fb.three.getX(), 3);
047            assertEquals(fb.four.getX(), 4);
048        }
049    
050        public interface Apple {
051            int getX();
052        }
053    
054        public static class AppleImpl1 implements Apple {
055            public int getX() {
056                return 1;
057            }
058        }
059    
060        public static class AppleImpl2 implements Apple {
061            public int getX() {
062                return 2;
063            }
064        }
065    
066        public static class AppleImpl3 implements Apple {
067            public int getX() {
068                return 3;
069            }
070        }
071    
072        public static class AppleImpl4 implements Apple {
073            public int getX() {
074                return 4;
075            }
076        }
077    
078        public static class FruitBasket {
079            private @Named("one")
080            Apple one;
081            private @Named("two")
082            Apple two;
083            private @Named("three")
084            Apple three;
085            private @Named("four")
086            Apple four;
087    
088            public FruitBasket() {
089            }
090        }
091    
092        // to become an annotation
093        @Retention(RetentionPolicy.RUNTIME)
094        @Target({ElementType.FIELD, ElementType.PARAMETER})
095        public @interface Named {
096            String value();
097        }
098    
099        // implicitly this function goes into DPC
100        public static String bindKey(Class type, String bindingId) {
101            return type.getName() + "/" + bindingId;
102        }
103    
104        public class FieldInjection implements InjectionFactory, Serializable {
105    
106            public <T> ComponentAdapter<T> createComponentAdapter(
107                ComponentMonitor componentMonitor, LifecycleStrategy lifecycleStrategy,
108                Properties componentProperties, Object componentKey,
109                Class<T> componentImplementation, Parameter ... parameters)
110                throws PicoCompositionException {
111                boolean useNames = AbstractBehaviorFactory.removePropertiesIfPresent(
112                    componentProperties, Characteristics.USE_NAMES);
113                return new FieldInjector(
114                    componentKey, componentImplementation, parameters, componentMonitor,
115                    lifecycleStrategy, useNames);
116            }
117        }
118    
119        public static class FieldInjector<T> extends AbstractInjector<T> {
120    
121            protected FieldInjector(
122                Object componentKey, Class componentImplementation, Parameter[] parameters,
123                ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy, boolean useNames) {
124                super(
125                    componentKey, componentImplementation, parameters, monitor, lifecycleStrategy,
126                    useNames);
127            }
128    
129            @Override
130            public void verify(PicoContainer container) throws PicoCompositionException {
131                // @todo Auto-generated method stub
132            }
133    
134            public T getComponentInstance(PicoContainer container) throws PicoCompositionException {
135                final T inst;
136                try {
137                    inst = getComponentImplementation().newInstance();
138                    Field[] declaredFields = getComponentImplementation().getDeclaredFields();
139                    for (int i = 0; i < declaredFields.length; i++ ) {
140                        final Field field = declaredFields[i];
141                        Named bindAnnotation = field.getAnnotation(Named.class);
142                        Object value;
143                        if (bindAnnotation != null) {
144                            value = container.getComponent(bindKey(field.getType(), bindAnnotation
145                                .value()));
146                        } else {
147                            value = container.getComponent(field.getType());
148                        }
149                        field.setAccessible(true);
150                        field.set(inst, value);
151                    }
152    
153                } catch (InstantiationException e) {
154                    return caughtInstantiationException(currentMonitor(), null, e, container);
155                } catch (IllegalAccessException e) {
156                    return caughtIllegalAccessException(currentMonitor(), null, e, container);
157                }
158                return inst;
159            }
160    
161            public String getDescriptor() {
162                return "FieldInjector";
163            }
164    
165        }
166    }