001 /***************************************************************************** 002 * Copyright (c) PicoContainer Organization. All rights reserved. * 003 * ------------------------------------------------------------------------- * 004 * The software in this package is published under the terms of the BSD * 005 * style license a copy of which has been included with this distribution in * 006 * the LICENSE.txt file. * 007 * * 008 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant * 009 *****************************************************************************/ 010 011 package org.picocontainer.injectors; 012 013 import java.lang.reflect.AccessibleObject; 014 import java.security.AccessController; 015 import java.security.PrivilegedAction; 016 import java.util.Properties; 017 import org.picocontainer.Characteristics; 018 import org.picocontainer.ComponentAdapter; 019 import org.picocontainer.ComponentMonitor; 020 import org.picocontainer.LifecycleStrategy; 021 import org.picocontainer.Parameter; 022 import org.picocontainer.PicoCompositionException; 023 import org.picocontainer.annotations.Inject; 024 import org.picocontainer.behaviors.AbstractBehaviorFactory; 025 026 /** 027 * Creates injector instances, depending on the injection characteristics of the component class. 028 * It will attempt to create a component adapter with - in order of priority: 029 * <ol> 030 * <li>Annotated field injection: if annotation {@link org.picocontainer.annotations.Inject} is found for field</li> 031 * <li>Annotated method injection: if annotation {@link org.picocontainer.annotations.Inject} is found for method</li> 032 * <li>Setter injection: if {@link Characteristics.SDI} is found</li> 033 * <li>Method injection: if {@link Characteristics.METHOD_INJECTION} if found</li> 034 * <li>Constructor injection (the default, must find {@link Characteristics.CDI})</li> 035 * </ol> 036 * 037 * @author Paul Hammant 038 * @author Mauro Talevi 039 * @see AnnotatedFieldInjection 040 * @see AnnotatedMethodInjection 041 * @see SetterInjection 042 * @see MethodInjection 043 * @see ConstructorInjection 044 */ 045 @SuppressWarnings("serial") 046 public class AdaptingInjection extends AbstractInjectionFactory { 047 048 049 public <T> ComponentAdapter<T> createComponentAdapter(ComponentMonitor componentMonitor, 050 LifecycleStrategy lifecycleStrategy, 051 Properties componentProperties, 052 Object componentKey, 053 Class<T> componentImplementation, 054 Parameter... parameters) throws PicoCompositionException { 055 ComponentAdapter<T> componentAdapter = null; 056 057 componentAdapter = fieldAnnotatedInjectionAdapter(componentImplementation, 058 componentMonitor, 059 lifecycleStrategy, 060 componentProperties, 061 componentKey, 062 componentAdapter, 063 parameters); 064 065 if (componentAdapter != null) { 066 return componentAdapter; 067 } 068 069 070 componentAdapter = methodAnnotatedInjectionAdapter(componentImplementation, 071 componentMonitor, 072 lifecycleStrategy, 073 componentProperties, 074 componentKey, 075 componentAdapter, 076 parameters); 077 078 if (componentAdapter != null) { 079 return componentAdapter; 080 } 081 082 componentAdapter = setterInjectionAdapter(componentProperties, 083 componentMonitor, 084 lifecycleStrategy, 085 componentKey, 086 componentImplementation, 087 componentAdapter, 088 parameters); 089 090 if (componentAdapter != null) { 091 return componentAdapter; 092 } 093 094 componentAdapter = methodInjectionAdapter(componentProperties, 095 componentMonitor, 096 lifecycleStrategy, 097 componentKey, 098 componentImplementation, 099 componentAdapter, 100 parameters); 101 102 if (componentAdapter != null) { 103 return componentAdapter; 104 } 105 106 107 return defaultInjectionAdapter(componentProperties, 108 componentMonitor, 109 lifecycleStrategy, 110 componentKey, 111 componentImplementation, 112 parameters); 113 } 114 115 private <T> ComponentAdapter<T> defaultInjectionAdapter(Properties componentProperties, 116 ComponentMonitor componentMonitor, 117 LifecycleStrategy lifecycleStrategy, 118 Object componentKey, 119 Class<T> componentImplementation, Parameter... parameters) { 120 AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.CDI); 121 return new ConstructorInjection().createComponentAdapter(componentMonitor, 122 lifecycleStrategy, 123 componentProperties, 124 componentKey, 125 componentImplementation, 126 parameters); 127 } 128 129 private <T> ComponentAdapter<T> setterInjectionAdapter(Properties componentProperties, 130 ComponentMonitor componentMonitor, 131 LifecycleStrategy lifecycleStrategy, 132 Object componentKey, 133 Class<T> componentImplementation, 134 ComponentAdapter<T> componentAdapter, 135 Parameter... parameters) { 136 if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.SDI)) { 137 componentAdapter = new SetterInjection().createComponentAdapter(componentMonitor, lifecycleStrategy, 138 componentProperties, 139 componentKey, 140 componentImplementation, 141 parameters); 142 } 143 return componentAdapter; 144 } 145 146 private <T> ComponentAdapter<T> methodInjectionAdapter(Properties componentProperties, 147 ComponentMonitor componentMonitor, 148 LifecycleStrategy lifecycleStrategy, 149 Object componentKey, 150 Class<T> componentImplementation, 151 ComponentAdapter<T> componentAdapter, 152 Parameter... parameters) { 153 if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.METHOD_INJECTION)) { 154 componentAdapter = new MethodInjection().createComponentAdapter(componentMonitor, lifecycleStrategy, 155 componentProperties, 156 componentKey, 157 componentImplementation, 158 parameters); 159 } 160 return componentAdapter; 161 } 162 163 164 private <T> ComponentAdapter<T> methodAnnotatedInjectionAdapter(Class<T> componentImplementation, 165 ComponentMonitor componentMonitor, 166 LifecycleStrategy lifecycleStrategy, 167 Properties componentProperties, 168 Object componentKey, 169 ComponentAdapter<T> componentAdapter, 170 Parameter... parameters) { 171 if (injectionMethodAnnotated(componentImplementation)) { 172 componentAdapter = 173 new AnnotatedMethodInjection().createComponentAdapter(componentMonitor, 174 lifecycleStrategy, 175 componentProperties, 176 componentKey, 177 componentImplementation, 178 parameters); 179 } 180 return componentAdapter; 181 } 182 183 private <T> ComponentAdapter<T> fieldAnnotatedInjectionAdapter(Class<T> componentImplementation, 184 ComponentMonitor componentMonitor, 185 LifecycleStrategy lifecycleStrategy, 186 Properties componentProperties, 187 Object componentKey, ComponentAdapter<T> componentAdapter, Parameter... parameters) { 188 if (injectionFieldAnnotated(componentImplementation)) { 189 componentAdapter = new AnnotatedFieldInjection().createComponentAdapter(componentMonitor, 190 lifecycleStrategy, 191 componentProperties, 192 componentKey, 193 componentImplementation, 194 parameters); 195 } 196 return componentAdapter; 197 } 198 199 private boolean injectionMethodAnnotated(final Class<?> componentImplementation) { 200 return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() { 201 @SuppressWarnings("synthetic-access") 202 public Object run() { 203 return injectionAnnotated(componentImplementation.getDeclaredMethods()); 204 } 205 }); 206 } 207 208 private boolean injectionFieldAnnotated(final Class<?> componentImplementation) { 209 return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() { 210 @SuppressWarnings("synthetic-access") 211 public Object run() { 212 if (componentImplementation.isInterface()) { 213 return false; 214 } 215 Class impl = componentImplementation; 216 while (impl != Object.class) { 217 boolean injAnnotated = injectionAnnotated(impl.getDeclaredFields()); 218 if (injAnnotated) { 219 return true; 220 } 221 impl = impl.getSuperclass(); 222 } 223 return false; 224 } 225 }); 226 } 227 228 private boolean injectionAnnotated(AccessibleObject[] objects) { 229 for (AccessibleObject object : objects) { 230 if (object.getAnnotation(Inject.class) != null) { 231 return true; 232 } 233 } 234 return false; 235 } 236 237 }