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); 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 (int i = 0; i < declaredFields.length; i++ ) { 141 final Field field = declaredFields[i]; 142 Named bindAnnotation = field.getAnnotation(Named.class); 143 Object value; 144 if (bindAnnotation != null) { 145 value = container.getComponent(bindKey(field.getType(), bindAnnotation 146 .value())); 147 } else { 148 value = container.getComponent(field.getType()); 149 } 150 field.setAccessible(true); 151 field.set(inst, value); 152 } 153 154 } catch (InstantiationException e) { 155 return caughtInstantiationException(currentMonitor(), null, e, container); 156 } catch (IllegalAccessException e) { 157 return caughtIllegalAccessException(currentMonitor(), null, e, container); 158 } 159 return inst; 160 } 161 162 public void decorateComponentInstance(PicoContainer container, Type into, T instance) { 163 } 164 165 public String getDescriptor() { 166 return "FieldInjector"; 167 } 168 169 } 170 }