    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&ouml;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(
    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 (final Field field : declaredFields) {
    141                        Named bindAnnotation = field.getAnnotation(Named.class);
    142                        Object value;
    143                        if (bindAnnotation != null) {
    144                            value = container.getComponent(bindKey(field.getType(), bindAnnotation.value()));
    145                        } else {
    146                            value = container.getComponent(field.getType());
    147                        }
    148                        field.setAccessible(true);
    149                        field.set(inst, value);
    150                    }
    151
    152                } catch (InstantiationException e) {
    153                    return caughtInstantiationException(currentMonitor(), null, e, container);
    154                } catch (IllegalAccessException e) {
    155                    return caughtIllegalAccessException(currentMonitor(), null, e, container);
    156                }
    157                return inst;
    158            }
    159
    160            public String getDescriptor() {
    161                return "FieldInjector";
    162            }
    163
    164        }
    165    }