001package org.picocontainer.adapters; 002 003import org.junit.Test; 004import org.picocontainer.Characteristics; 005import org.picocontainer.ComponentAdapter; 006import org.picocontainer.ComponentMonitor; 007import org.picocontainer.DefaultPicoContainer; 008import org.picocontainer.LifecycleStrategy; 009import org.picocontainer.MutablePicoContainer; 010import org.picocontainer.Parameter; 011import org.picocontainer.PicoCompositionException; 012import org.picocontainer.PicoContainer; 013import org.picocontainer.behaviors.AbstractBehaviorFactory; 014import org.picocontainer.injectors.AbstractInjectionFactory; 015import org.picocontainer.injectors.AbstractInjector; 016 017import java.lang.annotation.ElementType; 018import java.lang.annotation.Retention; 019import java.lang.annotation.RetentionPolicy; 020import java.lang.annotation.Target; 021import java.lang.reflect.Field; 022import java.lang.reflect.Type; 023import java.util.Properties; 024 025import static java.lang.reflect.Modifier.isStatic; 026import static org.junit.Assert.assertEquals; 027 028 029/** 030 * @author Paul Hammant 031 * @author Jörg Schaible 032 */ 033@SuppressWarnings("serial") 034public 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}