    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    }