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 }