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.lang.reflect.Method;
015 import java.util.Properties;
016 import java.security.AccessController;
017 import java.security.PrivilegedAction;
018
019 import org.picocontainer.Characteristics;
020 import org.picocontainer.ComponentAdapter;
021 import org.picocontainer.ComponentMonitor;
022 import org.picocontainer.LifecycleStrategy;
023 import org.picocontainer.Parameter;
024 import org.picocontainer.PicoCompositionException;
025 import org.picocontainer.annotations.Inject;
026 import org.picocontainer.behaviors.AbstractBehaviorFactory;
027
028 /**
029 * Creates injector instances, depending on the injection characteristics of the component class.
030 * It will attempt to create a component adapter with - in order of priority:
031 * <ol>
032 * <li>Annotated field injection: if annotation {@link @Inject} is found for field</li>
033 * <li>Annotated method injection: if annotation {@link @Inject} is found for method</li>
034 * <li>Setter injection: if {@link Characteristics.SDI} is found</li>
035 * <li>Method injection: if {@link Characteristics.METHOD_INJECTION} if found</li>
036 * <li>Constructor injection (the default, must find {@link Characteristics.CDI})</li>
037 * </ol>
038 *
039 * @author Paul Hammant
040 * @author Mauro Talevi
041 * @see AnnotatedFieldInjection
042 * @see AnnotatedMethodInjection
043 * @see SetterInjection
044 * @see MethodInjection
045 * @see ConstructorInjection
046 */
047 @SuppressWarnings("serial")
048 public class AdaptingInjection extends AbstractInjectionFactory {
049
050
051 public <T> ComponentAdapter<T> createComponentAdapter(ComponentMonitor componentMonitor,
052 LifecycleStrategy lifecycleStrategy,
053 Properties componentProperties,
054 Object componentKey,
055 Class<T> componentImplementation,
056 Parameter... parameters) throws PicoCompositionException {
057 ComponentAdapter<T> componentAdapter = null;
058
059 componentAdapter = fieldAnnotatedInjectionAdapter(componentImplementation,
060 componentMonitor,
061 lifecycleStrategy,
062 componentProperties,
063 componentKey,
064 componentAdapter,
065 parameters);
066
067 if (componentAdapter != null) {
068 return componentAdapter;
069 }
070
071
072 componentAdapter = methodAnnotatedInjectionAdapter(componentImplementation,
073 componentMonitor,
074 lifecycleStrategy,
075 componentProperties,
076 componentKey,
077 componentAdapter,
078 parameters);
079
080 if (componentAdapter != null) {
081 return componentAdapter;
082 }
083
084 componentAdapter = setterInjectionAdapter(componentProperties,
085 componentMonitor,
086 lifecycleStrategy,
087 componentKey,
088 componentImplementation,
089 componentAdapter,
090 parameters);
091
092 if (componentAdapter != null) {
093 return componentAdapter;
094 }
095
096 componentAdapter = methodInjectionAdapter(componentProperties,
097 componentMonitor,
098 lifecycleStrategy,
099 componentKey,
100 componentImplementation,
101 componentAdapter,
102 parameters);
103
104 if (componentAdapter != null) {
105 return componentAdapter;
106 }
107
108
109 return defaultInjectionAdapter(componentProperties,
110 componentMonitor,
111 lifecycleStrategy,
112 componentKey,
113 componentImplementation,
114 parameters);
115 }
116
117 private <T> ComponentAdapter<T> defaultInjectionAdapter(Properties componentProperties,
118 ComponentMonitor componentMonitor,
119 LifecycleStrategy lifecycleStrategy,
120 Object componentKey,
121 Class<T> componentImplementation, Parameter... parameters) {
122 AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.CDI);
123 return new ConstructorInjection().createComponentAdapter(componentMonitor,
124 lifecycleStrategy,
125 componentProperties,
126 componentKey,
127 componentImplementation,
128 parameters);
129 }
130
131 private <T> ComponentAdapter<T> setterInjectionAdapter(Properties componentProperties,
132 ComponentMonitor componentMonitor,
133 LifecycleStrategy lifecycleStrategy,
134 Object componentKey,
135 Class<T> componentImplementation,
136 ComponentAdapter<T> componentAdapter,
137 Parameter... parameters) {
138 if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.SDI)) {
139 componentAdapter = new SetterInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
140 componentProperties,
141 componentKey,
142 componentImplementation,
143 parameters);
144 }
145 return componentAdapter;
146 }
147
148 private <T> ComponentAdapter<T> methodInjectionAdapter(Properties componentProperties,
149 ComponentMonitor componentMonitor,
150 LifecycleStrategy lifecycleStrategy,
151 Object componentKey,
152 Class<T> componentImplementation,
153 ComponentAdapter<T> componentAdapter,
154 Parameter... parameters) {
155 if (AbstractBehaviorFactory.removePropertiesIfPresent(componentProperties, Characteristics.METHOD_INJECTION)) {
156 componentAdapter = new MethodInjection().createComponentAdapter(componentMonitor, lifecycleStrategy,
157 componentProperties,
158 componentKey,
159 componentImplementation,
160 parameters);
161 }
162 return componentAdapter;
163 }
164
165
166 private <T> ComponentAdapter<T> methodAnnotatedInjectionAdapter(Class<T> componentImplementation,
167 ComponentMonitor componentMonitor,
168 LifecycleStrategy lifecycleStrategy,
169 Properties componentProperties,
170 Object componentKey,
171 ComponentAdapter<T> componentAdapter,
172 Parameter... parameters) {
173 if (injectionMethodAnnotated(componentImplementation)) {
174 componentAdapter =
175 new AnnotatedMethodInjection().createComponentAdapter(componentMonitor,
176 lifecycleStrategy,
177 componentProperties,
178 componentKey,
179 componentImplementation,
180 parameters);
181 }
182 return componentAdapter;
183 }
184
185 private <T> ComponentAdapter<T> fieldAnnotatedInjectionAdapter(Class<T> componentImplementation,
186 ComponentMonitor componentMonitor,
187 LifecycleStrategy lifecycleStrategy,
188 Properties componentProperties,
189 Object componentKey, ComponentAdapter<T> componentAdapter, Parameter... parameters) {
190 if (injectionFieldAnnotated(componentImplementation)) {
191 componentAdapter = new AnnotatedFieldInjection().createComponentAdapter(componentMonitor,
192 lifecycleStrategy,
193 componentProperties,
194 componentKey,
195 componentImplementation,
196 parameters);
197 }
198 return componentAdapter;
199 }
200
201 private boolean injectionMethodAnnotated(final Class<?> componentImplementation) {
202 return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() {
203 public Object run() {
204 return injectionAnnotated(componentImplementation.getDeclaredMethods());
205 }
206 });
207 }
208
209 private boolean injectionFieldAnnotated(final Class<?> componentImplementation) {
210 return (Boolean) AccessController.doPrivileged(new PrivilegedAction<Object>() {
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 }