    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     *****************************************************************************/
    009    package org.picocontainer.injectors;
    010
    011    import org.picocontainer.ComponentMonitor;
    012    import org.picocontainer.LifecycleStrategy;
    013    import org.picocontainer.Parameter;
    014    import org.picocontainer.PicoContainer;
    015    import org.picocontainer.PicoCompositionException;
    016    import org.picocontainer.annotations.Bind;
    017
    018    import java.lang.annotation.Annotation;
    019    import java.lang.reflect.AccessibleObject;
    020    import java.lang.reflect.Type;
    021
    022    import com.thoughtworks.paranamer.CachingParanamer;
    023
    024    /**
    025     * Injection will happen in a single member function on the component.
    026     *
    027     * @author Paul Hammant
    028     *
    029     */
    030    public abstract class SingleMemberInjector<T> extends AbstractInjector<T> {
    031
    032        private transient CachingParanamer paranamer = new CachingParanamer();
    033
    034        public SingleMemberInjector(Object componentKey,
    035                                    Class componentImplementation,
    036                                    Parameter[] parameters,
    037                                    ComponentMonitor monitor,
    038                                    LifecycleStrategy lifecycleStrategy, boolean useNames) {
    039            super(componentKey, componentImplementation, parameters, monitor, lifecycleStrategy, useNames);
    040        }
    041
    042        protected CachingParanamer getParanamer() {
    043            return paranamer;
    044        }
    045
    046        @SuppressWarnings("unchecked")
    047        protected Object[] getMemberArguments(PicoContainer container, final AccessibleObject member, final Type[] parameterTypes, final Annotation[] bindings) {
    048            boxParameters(parameterTypes);
    049            Object[] result = new Object[parameterTypes.length];
    050            Parameter[] currentParameters = parameters != null ? parameters : createDefaultParameters(parameterTypes);
    051
    052            for (int i = 0; i < currentParameters.length; i++) {
    053                result[i] = getParameter(container, member, i, parameterTypes[i], bindings[i], currentParameters[i]);
    054            }
    055
    056            return result;
    057        }
    058
    059        private void boxParameters(Type[] parameterTypes) {
    060            for (int i = 0; i < parameterTypes.length; i++) {
    061                parameterTypes[i] = box(parameterTypes[i]);
    062
    063            }
    064        }
    065
    066        private Object getParameter(PicoContainer container, AccessibleObject member, int i, Type parameterType, Annotation binding, Parameter currentParameter) {
    067            ParameterNameBinding expectedNameBinding = new ParameterNameBinding(paranamer, getComponentImplementation(), member, i);
    068            Object result = currentParameter.resolveInstance(container, this, parameterType, expectedNameBinding, useNames(), binding);
    069            if (result == null && !isNullParamAllowed(member, i)) {
    070                throw new ParameterCannotBeNullException(i, member, expectedNameBinding.getName());
    071            }
    072            return result;
    073        }
    074
    075        protected boolean isNullParamAllowed(AccessibleObject member, int i) {
    076            return false;
    077        }
    078
    079        protected Annotation[] getBindings(Annotation[][] annotationss) {
    080            Annotation[] retVal = new Annotation[annotationss.length];
    081            for (int i = 0; i < annotationss.length; i++) {
    082                Annotation[] annotations = annotationss[i];
    083                for (Annotation annotation : annotations) {
    084                    if (annotation.annotationType().getAnnotation(Bind.class) != null) {
    085                        retVal[i] = annotation;
    086                        break;
    087                    }
    088                }
    089            }
    090            return retVal;
    091        }
    092
    093        public static class ParameterCannotBeNullException extends PicoCompositionException {
    094            private final String name;
    095            private ParameterCannotBeNullException(int ix, AccessibleObject member, String name) {
    096                super("Parameter " + ix + " of '" + member + "' named '" + name + "' cannot be null");
    097                this.name = name;
    098            }
    099            public String getParameterName() {
    100                return name;
    101            }
    102        }
    103
    104    }