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 }