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    }