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