2 * Copyright 2008 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org.wamblee.system.adapters;
18 import java.awt.CompositeContext;
19 import java.lang.reflect.InvocationTargetException;
20 import java.lang.reflect.Method;
21 import java.lang.reflect.Modifier;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.HashMap;
25 import java.util.List;
29 import org.wamblee.collections.CollectionFilter;
30 import org.wamblee.conditions.Condition;
31 import org.wamblee.conditions.FixedCondition;
32 import org.wamblee.general.Pair;
33 import org.wamblee.reflection.ReflectionUtils;
34 import org.wamblee.system.core.DefaultProvidedInterface;
35 import org.wamblee.system.core.DefaultRequiredInterface;
36 import org.wamblee.system.core.ProvidedInterface;
37 import org.wamblee.system.core.RequiredInterface;
38 import org.wamblee.system.core.Scope;
39 import org.wamblee.system.core.SystemAssemblyException;
42 * Represents the configuration for exposing the setters of a class as required
45 * @author Erik Brakkee
47 public class SetterConfiguration {
50 private boolean _publicOnly;
52 private Map<Method, ParameterValues> _setters;
55 * Constructs the setter configuration. By default no setters are added.
58 * Class which is being configured.
60 public SetterConfiguration(Class aClass) {
63 _setters = new HashMap<Method, ParameterValues>();
67 * Makes sure that all available setters are used.
69 public SetterConfiguration initAllSetters() {
71 for (Method method: getAllSetters(_class, _publicOnly) ) {
72 _setters.put(method, createParameterValues(method));
78 * Called to set whether non-public setters are also used. By default only
79 * public setters are used. The currently selected setters remain chosen.
84 public SetterConfiguration setNonPublic(boolean aIsNonPublic) {
85 _publicOnly = !aIsNonPublic;
90 * Removes all setters.
92 * @return Reference to the current object to allow call chaining.
94 public SetterConfiguration clear() {
100 * Removes a setter from the set of methods.
103 * Name of the setter to remove.
104 * @return Reference to the current object to allow call chaining.
106 public SetterConfiguration remove(String aName) {
107 for (Method method : _setters.keySet()) {
108 if (method.getName().equals(aName)) {
109 _setters.remove(method);
113 throw new IllegalArgumentException(
114 "No method configured by the name of '" + aName + "'");
118 * Removes the method from the set of methods.
119 * @param aMethod Method to remove.
122 public SetterConfiguration remove(Method aMethod) {
123 if ( !aMethod.getDeclaringClass().isAssignableFrom(_class) ) {
124 throw new RuntimeException("Method " + aMethod + " not found in class " + _class + " or its superclasses");
126 for (Method method : _setters.keySet()) {
127 if (method.equals(aMethod)) {
128 _setters.remove(method);
132 throw new IllegalArgumentException(
133 "Method '" + aMethod + "' was not configured. ");
137 * Adds a given setter name to the setters.
139 * @param aName Name of a setter method.
140 * @return Reference to the current object to allow call chaining.
142 public SetterConfiguration add(final String aName) {
143 int oldlen = _setters.size();
144 List<Method> methods = new ArrayList<Method>();
145 CollectionFilter.filter(getAllSetters(_class, _publicOnly), methods,
146 new Condition<Method>() {
148 public boolean matches(Method aObject) {
149 return aObject.getName().equals(aName);
153 if (methods.size() == 0 ) {
154 throw new IllegalArgumentException("Method '" + aName
155 + "' not found in " + _class.getName());
157 // TODO is it possible to get more than one setter here in case the subclass overrides
158 // the baseclass method?
159 _setters.put(methods.get(0), createParameterValues(methods.get(0)));
164 * Adds a given setter identified by the type it accepts to the list of
168 * Type to look for. Note that this must be the exact type as
169 * autoboxing and autounboxing is not used.
170 * @return Reference to the current object to allow call chaining.
171 * @throws IllegalArgumentException
172 * In case no setter is found or multiple setters are found.
174 public SetterConfiguration addSetter(final Class aType) {
175 List<Method> result = new ArrayList<Method>();
176 CollectionFilter.filter(getAllSetters(_class, _publicOnly), result,
177 new Condition<Method>() {
179 public boolean matches(Method aObject) {
180 Class type = aObject.getParameterTypes()[0];
181 return type.equals(aType);
185 if (result.size() == 0) {
186 throw new IllegalArgumentException("No setter found in class '"
188 + "' that has a setter with argument type '"
189 + aType.getName() + "'");
191 if (result.size() > 1) {
193 for (Method method : result) {
194 setters += method.getName() + " ";
196 throw new IllegalArgumentException(
197 "Multiple setters found in class '" + _class.getName()
198 + " that accept type '" + aType.getName() + "': "
201 Method method = result.get(0);
202 _setters.put(method, createParameterValues(method));
207 * Gets all setters for the current class.
209 * @return List of all setters.
211 public static List<Method> getAllSetters(Class aClass,
212 boolean aPublicOnly) {
213 List<Method> result = new ArrayList<Method>();
214 for (Method method : getAllMethods(aClass)) {
215 if (!aPublicOnly || Modifier.isPublic(method.getModifiers())) {
216 if (method.getName().startsWith("set")
217 && method.getParameterTypes().length == 1) {
218 method.setAccessible(true);
226 private static ParameterValues createParameterValues(Method aMethod) {
228 Class[] paramTypes = aMethod.getParameterTypes();
229 String[] paramNames = new String[paramTypes.length];
230 for (int i = 0; i < paramTypes.length; i++) {
231 paramNames[i] = aMethod.getName() + "." + i;
233 return new ParameterValues(paramNames, paramTypes);
236 private static final List<Method> getAllMethods(Class aClass) {
237 return ReflectionUtils.getAllMethods(aClass);
241 * Gets the required interfaces based on the configured setteres.
243 * @return List of required interfaces.
245 public List<RequiredInterface> getRequiredInterfaces() {
246 List<RequiredInterface> result = new ArrayList<RequiredInterface>();
247 for (Method method : _setters.keySet()) {
248 result.addAll(_setters.get(method).getRequiredInterfaces());
254 * Invokes all configured setters with the appropriate values.
257 * Scope within which invocation takes place.
259 * Object on which the invocation takes place.
261 public void inject(Scope aScope, Object aObject) {
262 if (!_class.isInstance(aObject)) {
263 throw new IllegalArgumentException("Object '" + aObject
264 + "' is not an instance of " + _class.getName());
266 for (Method method : _setters.keySet()) {
267 ParameterValues values = _setters.get(method);
270 method.invoke(aObject, values.values(aScope));
271 } catch (IllegalAccessException e) {
272 throw new SystemAssemblyException("Problem invoking " + method
273 + " with " + values, e);
274 } catch (InvocationTargetException e) {
275 throw new SystemAssemblyException("Problem invoking " + method
276 + " with " + values, e);
282 * Returns the parameter values for allowing detailed configuration of how
283 * parameter values are set.
286 * Setter name without the "set" prefix with the first character
287 * converted to lower case.
288 * @return Parameter values.
290 public ParameterValues values(String aMethod) {
291 for (Method method : _setters.keySet()) {
292 if (method.getName().equals(aMethod)) {
293 return _setters.get(method);
296 throw new IllegalArgumentException("No setter method '" + aMethod
300 public List<Method> getSetters() {
301 return new ArrayList<Method>(_setters.keySet());