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 * Original code by *
009 *****************************************************************************/
010 package org.picocontainer.injectors;
011
012 import org.picocontainer.ComponentMonitor;
013 import org.picocontainer.Parameter;
014 import org.picocontainer.PicoContainer;
015 import org.picocontainer.behaviors.PropertyApplicator;
016 import org.picocontainer.behaviors.Cached;
017
018 import java.lang.reflect.Method;
019 import java.lang.reflect.Type;
020 import java.lang.reflect.AccessibleObject;
021 import java.lang.reflect.InvocationTargetException;
022 import java.util.List;
023 import java.util.Set;
024
025 /**
026 * Instantiates components using empty constructors and
027 * <a href="http://picocontainer.org/setter-injection.html">Setter Injection</a>.
028 * For easy setting of primitive properties, also see {@link PropertyApplicator}.
029 * <p/>
030 * <em>
031 * Note that this class doesn't cache instances. If you want caching,
032 * use a {@link Cached} around this one.
033 * </em>
034 * </p>
035 *
036 * @author Aslak Hellesøy
037 * @author Jörg Schaible
038 * @author Mauro Talevi
039 * @author Paul Hammant
040 */
041 @SuppressWarnings("serial")
042 public class SetterInjector<T> extends IterativeInjector<T> {
043
044 protected final String prefix;
045 private final boolean optional;
046 private final String notThisOneThough;
047
048 /**
049 * Constructs a SetterInjector
050 *
051 *
052 * @param componentKey the search key for this implementation
053 * @param componentImplementation the concrete implementation
054 * @param parameters the parameters to use for the initialization
055 * @param monitor the component monitor used by this addAdapter
056 * @param prefix the prefix to use (e.g. 'set')
057 * @param notThisOneThough a setter name that's not for injecting through
058 * @param optional not all setters need to be injected
059 * @param useNames @throws org.picocontainer.injectors.AbstractInjector.NotConcreteRegistrationException
060 * if the implementation is not a concrete class.
061 * @throws NullPointerException if one of the parameters is <code>null</code>
062 */
063 public SetterInjector(final Object componentKey,
064 final Class componentImplementation,
065 Parameter[] parameters,
066 ComponentMonitor monitor,
067 String prefix, String notThisOneThough,
068 boolean optional, boolean useNames) throws NotConcreteRegistrationException {
069 super(componentKey, componentImplementation, parameters, monitor, useNames);
070 this.prefix = prefix;
071 this.optional = optional;
072 this.notThisOneThough = notThisOneThough != null ? notThisOneThough : "";
073 }
074
075 protected Object memberInvocationReturn(Object lastReturn, AccessibleObject member, Object instance) {
076 return member != null && ((Method)member).getReturnType()!=void.class ? lastReturn : instance;
077 }
078
079 @Override
080 protected Object injectIntoMember(AccessibleObject member, Object componentInstance, Object toInject)
081 throws IllegalAccessException, InvocationTargetException {
082 return ((Method)member).invoke(componentInstance, toInject);
083 }
084
085 @Override
086 protected boolean isInjectorMethod(Method method) {
087 String methodName = method.getName();
088 return methodName.length() >= getInjectorPrefix().length() + 1 // long enough
089 && methodName.startsWith(getInjectorPrefix())
090 && !methodName.equals(notThisOneThough)
091 && Character.isUpperCase(methodName.charAt(getInjectorPrefix().length()));
092 }
093
094 protected String getInjectorPrefix() {
095 return prefix;
096 }
097
098 @Override
099 public String getDescriptor() {
100 return "SetterInjector-";
101 }
102
103 @Override
104 protected void unsatisfiedDependencies(PicoContainer container, Set<Type> unsatisfiableDependencyTypes, List<AccessibleObject> unsatisfiableDependencyMembers) {
105 if (!optional) {
106 throw new UnsatisfiableDependenciesException(this.getComponentImplementation().getName() + " has unsatisfied dependencies " + unsatisfiableDependencyTypes
107 + " for members " + unsatisfiableDependencyMembers + " from " + container);
108 }
109 }
110
111 }