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