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, 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 }