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 all setters are added.
58 * Class which is being configured.
60 public SetterConfiguration(Class aClass) {
66 private void initSetters() {
67 _setters = new HashMap<Method, ParameterValues>();
68 for (Method method: getAllSetters(_class, _publicOnly) ) {
69 _setters.put(method, createParameterValues(method));
74 * Called to set whether non-public setters are also used. By default only
75 * public setters are used. This resets all changes made and selects all
76 * public setters if non-public is false and all setters if it is true.
81 public void setNonPublic(boolean aIsNonPublic) {
82 _publicOnly = !aIsNonPublic;
87 * Removes all setters.
89 * @return Reference to the current object to allow call chaining.
91 public SetterConfiguration clear() {
97 * Removes a setter from the set of methods.
100 * Name of the setter to remove (without the "set" prefix).
101 * @return Reference to the current object to allow call chaining.
103 public SetterConfiguration remove(String aName) {
104 final String name = createSetterName(aName);
105 Map<Method, ParameterValues> setters = new HashMap<Method, ParameterValues>();
106 for (Method method : _setters.keySet()) {
107 if (method.getName().equals(name)) {
108 _setters.remove(method);
112 throw new IllegalArgumentException(
113 "No setter configured by the name of '" + aName + "'");
117 * Creates the name of a setter based on the name of the setter without the
122 * @return Setter name.
124 private String createSetterName(String aName) {
125 return "set" + aName.substring(0, 1).toUpperCase() + aName.substring(1);
129 * Adds a given setter name to the setters.
132 * @return Reference to the current object to allow call chaining.
134 public SetterConfiguration add(String aName) {
135 final String name = createSetterName(aName);
136 int oldlen = _setters.size();
137 List<Method> methods = new ArrayList<Method>();
138 CollectionFilter.filter(getAllSetters(_class, _publicOnly), methods,
139 new Condition<Method>() {
141 public boolean matches(Method aObject) {
142 return aObject.getName().equals(name);
146 if (methods.size() == 0 ) {
147 throw new IllegalArgumentException("No setter found for '" + aName
148 + "' in " + _class.getName());
150 // TODO is it possible to get more than one setter here in case the subclass overrides
151 // the baseclass method?
152 _setters.put(methods.get(0), createParameterValues(methods.get(0)));
157 * Adds a given setter identified by the type it accepts to the list of
161 * Type to look for. Note that this must be the exact type as
162 * autoboxing and autounboxing is not used.
163 * @return Reference to the current object to allow call chaining.
164 * @throws IllegalArgumentException
165 * In case no setter is found or multiple setters are found.
167 public SetterConfiguration add(final Class aType) {
168 List<Method> result = new ArrayList<Method>();
169 CollectionFilter.filter(getAllSetters(_class, _publicOnly), result,
170 new Condition<Method>() {
172 public boolean matches(Method aObject) {
173 Class type = aObject.getParameterTypes()[0];
174 return type.equals(aType);
178 if (result.size() == 0) {
179 throw new IllegalArgumentException("No setter found in class '"
181 + "' that has a setter with argument type '"
182 + aType.getName() + "'");
184 if (result.size() > 1) {
186 for (Method method : result) {
187 setters += method.getName() + " ";
189 throw new IllegalArgumentException(
190 "Multiple setters found in class '" + _class.getName()
191 + " that accept type '" + aType.getName() + "': "
194 Method method = result.get(0);
195 _setters.put(method, createParameterValues(method));
200 * Gets all setters for the current class.
202 * @return List of all setters.
204 private static List<Method> getAllSetters(Class aClass,
205 boolean aPublicOnly) {
206 List<Method> result = new ArrayList<Method>();
207 for (Method method : getAllMethods(aClass)) {
208 if (!aPublicOnly || Modifier.isPublic(method.getModifiers())) {
209 if (method.getName().startsWith("set")
210 && method.getParameterTypes().length == 1) {
211 method.setAccessible(true);
219 private static ParameterValues createParameterValues(Method method) {
220 return new ParameterValues(
221 new String[] { getSetterName(method) }, new Class[] { method
222 .getParameterTypes()[0] });
225 private static final List<Method> getAllMethods(Class aClass) {
226 return ReflectionUtils.getAllMethods(aClass);
230 * Gets the required interfaces based on the configured setteres.
232 * @return List of required interfaces.
234 public List<RequiredInterface> getRequiredInterfaces() {
235 List<RequiredInterface> result = new ArrayList<RequiredInterface>();
236 for (Method method : _setters.keySet()) {
237 result.addAll(_setters.get(method).getRequiredInterfaces());
243 * Invokes all configured setters with the appropriate values.
246 * Scope within which invocation takes place.
248 * Object on which the invocation takes place.
250 public void inject(Scope aScope, Object aObject) {
251 if (!_class.isInstance(aObject)) {
252 throw new IllegalArgumentException("Object '" + aObject
253 + "' is not an instance of " + _class.getName());
255 for (Method method : _setters.keySet()) {
256 ParameterValues values = _setters.get(method);
259 method.invoke(aObject, values.values(aScope));
260 } catch (IllegalAccessException e) {
261 throw new SystemAssemblyException("Problem invoking " + method
262 + " with " + values, e);
263 } catch (InvocationTargetException e) {
264 throw new SystemAssemblyException("Problem invoking " + method
265 + " with " + values, e);
271 * Returns the parameter values for allowing detailed configuration of how
272 * parameter values are set.
275 * Setter name without the "set" prefix with the first character
276 * converted to lower case.
277 * @return Parameter values.
279 public ParameterValues values(String aMethod) {
280 String name = createSetterName(aMethod);
281 for (Method method : _setters.keySet()) {
282 if (method.getName().equals(name)) {
283 return _setters.get(method);
286 throw new IllegalArgumentException("No setter method '" + name
291 * Gets the setter name for a given setter method. This is the name of the
292 * setter without the "set" prefix and with the first character converted to
297 * @return Setter name.
299 private static String getSetterName(Method aMethod) {
300 String result = aMethod.getName().substring(3);
301 return result.substring(0, 1).toLowerCase() + result.substring(1);
304 public List<Method> getSetters() {
305 return new ArrayList<Method>(_setters.keySet());