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);
114                return new FieldInjector(
115                    componentKey, componentImplementation, parameters, componentMonitor,
116                    lifecycleStrategy, useNames);
117            }
118        }
119    
120        public static class FieldInjector<T> extends AbstractInjector<T> {
121    
122            protected FieldInjector(
123                Object componentKey, Class componentImplementation, Parameter[] parameters,
124                ComponentMonitor monitor, LifecycleStrategy lifecycleStrategy, boolean useNames) {
125                super(
126                    componentKey, componentImplementation, parameters, monitor, lifecycleStrategy,
127                    useNames);
128            }
129    
130            @Override
131            public void verify(PicoContainer container) throws PicoCompositionException {
132                // @todo Auto-generated method stub
133            }
134    
135            public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
136                final T inst;
137                try {
138                    inst = getComponentImplementation().newInstance();
139                    Field[] declaredFields = getComponentImplementation().getDeclaredFields();
140                    for (int i = 0; i < declaredFields.length; i++ ) {
141                        final Field field = declaredFields[i];
142                        Named bindAnnotation = field.getAnnotation(Named.class);
143                        Object value;
144                        if (bindAnnotation != null) {
145                            value = container.getComponent(bindKey(field.getType(), bindAnnotation
146                                .value()));
147                        } else {
148                            value = container.getComponent(field.getType());
149                        }
150                        field.setAccessible(true);
151                        field.set(inst, value);
152                    }
153    
154                } catch (InstantiationException e) {
155                    return caughtInstantiationException(currentMonitor(), null, e, container);
156                } catch (IllegalAccessException e) {
157                    return caughtIllegalAccessException(currentMonitor(), null, e, container);
158                }
159                return inst;
160            }
161    
162            public void decorateComponentInstance(PicoContainer container, Type into, T instance) {
163            }
164    
165            public String getDescriptor() {
166                return "FieldInjector";
167            }
168    
169        }
170    }