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(componentKey, componentImplementation, parameters, componentMonitor, useNames);
115 }
116 }
117
118 public static class FieldInjector<T> extends AbstractInjector<T> {
119
120 protected FieldInjector(Object componentKey, Class componentImplementation, Parameter[] parameters, ComponentMonitor monitor, boolean useNames) {
121 super(componentKey, componentImplementation, parameters, monitor, useNames);
122 }
123
124 @Override
125 public void verify(PicoContainer container) throws PicoCompositionException {
126 // TODO Auto-generated method stub
127 }
128
129 public T getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
130 final T inst;
131 try {
132 inst = getComponentImplementation().newInstance();
133 Field[] declaredFields = getComponentImplementation().getDeclaredFields();
134 for (final Field field : declaredFields) {
135 Named bindAnnotation = field.getAnnotation(Named.class);
136 Object value;
137 if (bindAnnotation != null) {
138 value = container.getComponent(bindKey(field.getType(), bindAnnotation.value()));
139 } else {
140 value = container.getComponent(field.getType());
141 }
142 field.setAccessible(true);
143 field.set(inst, value);
144 }
145
146 } catch (InstantiationException e) {
147 return caughtInstantiationException(currentMonitor(), null, e, container);
148 } catch (IllegalAccessException e) {
149 return caughtIllegalAccessException(currentMonitor(), null, e, container);
150 }
151 return inst;
152 }
153
154 public String getDescriptor() {
155 return "FieldInjector";
156 }
157
158 }
159 }