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 }