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 *****************************************************************************/ 010package org.picocontainer.injectors; 011 012import org.picocontainer.ComponentMonitor; 013import org.picocontainer.Parameter; 014import org.picocontainer.PicoContainer; 015import org.picocontainer.behaviors.PropertyApplicator; 016import org.picocontainer.behaviors.Cached; 017 018import java.lang.reflect.Method; 019import java.lang.reflect.Type; 020import java.lang.reflect.AccessibleObject; 021import java.lang.reflect.InvocationTargetException; 022import java.util.List; 023import 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") 042public 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}