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 }