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