001 package org.picocontainer.adapters;
002
003 import org.junit.Test;
004 import org.picocontainer.Characteristics;
005 import org.picocontainer.ComponentAdapter;
006 import org.picocontainer.ComponentMonitor;
007 import org.picocontainer.DefaultPicoContainer;
008 import org.picocontainer.LifecycleStrategy;
009 import org.picocontainer.MutablePicoContainer;
010 import org.picocontainer.Parameter;
011 import org.picocontainer.PicoCompositionException;
012 import org.picocontainer.PicoContainer;
013 import org.picocontainer.behaviors.AbstractBehaviorFactory;
014 import org.picocontainer.injectors.AbstractInjectionFactory;
015 import org.picocontainer.injectors.AbstractInjector;
016
017 import java.lang.annotation.ElementType;
018 import java.lang.annotation.Retention;
019 import java.lang.annotation.RetentionPolicy;
020 import java.lang.annotation.Target;
021 import java.lang.reflect.Field;
022 import java.lang.reflect.Type;
023 import java.util.Properties;
024
025 import static java.lang.reflect.Modifier.isStatic;
026 import static org.junit.Assert.assertEquals;
027
028
029 /**
030 * @author Paul Hammant
031 * @author Jörg Schaible
032 */
033 @SuppressWarnings("serial")
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, true);
115 return new FieldInjector(componentKey, componentImplementation, parameters, componentMonitor, useNames);
116 }
117 }
118
119 public static class FieldInjector<T> extends AbstractInjector<T> {
120
121 protected FieldInjector(Object componentKey, Class componentImplementation, Parameter[] parameters, ComponentMonitor monitor, boolean useNames) {
122 super(componentKey, componentImplementation, parameters, monitor, useNames);
123 }
124
125 @Override
126 public void verify(PicoContainer container) throws PicoCompositionException {
127 // TODO Auto-generated method stub
128 }
129
130 public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
131 final T inst;
132 try {
133 inst = getComponentImplementation().newInstance();
134 Field[] declaredFields = getComponentImplementation().getDeclaredFields();
135 for (final Field field : declaredFields) {
136 if (!isStatic(field.getModifiers())) {
137 Named bindAnnotation = field.getAnnotation(Named.class);
138 Object value;
139 if (bindAnnotation != null) {
140 value = container.getComponent(bindKey(field.getType(), bindAnnotation.value()));
141 } else {
142 value = container.getComponent(field.getType());
143 }
144 field.setAccessible(true);
145 field.set(inst, value);
146 }
147 }
148
149 } catch (InstantiationException e) {
150 return caughtInstantiationException(currentMonitor(), null, e, container);
151 } catch (IllegalAccessException e) {
152 return caughtIllegalAccessException(currentMonitor(), null, e, container);
153 }
154 return inst;
155 }
156
157 public String getDescriptor() {
158 return "FieldInjector";
159 }
160
161 }
162 }