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