+ return this;
+ }
+ }
+
+ throw new IllegalArgumentException("Method '" + aMethod +
+ "' was not configured. ");
+ }
+
+ /**
+ * Adds a given setter name to the setters.
+ *
+ * @param aName
+ * Name of a setter method.
+ *
+ * @return Reference to the current object to allow call chaining.
+ *
+ */
+ public SetterConfiguration add(final String aName) {
+ int oldlen = setters.size();
+ List<Method> methods = new ArrayList<Method>();
+ CollectionFilter.filter(getAllSetters(clazz, publicOnly), methods,
+ new Condition<Method>() {
+ @Override
+ public boolean matches(Method aObject) {
+ return aObject.getName().equals(aName);
+ }
+ });
+
+ if (methods.size() == 0) {
+ throw new IllegalArgumentException("Method '" + aName +
+ "' not found in " + clazz.getName());
+ }
+
+ // TODO is it possible to get more than one setter here in case the
+ // subclass overrides
+ // the baseclass method?
+ setters.put(methods.get(0), createParameterValues(methods.get(0)));
+
+ return this;
+ }
+
+ /**
+ * Adds a given setter identified by the type it accepts to the list of
+ * setters.N
+ *
+ * @param aType
+ * Type to look for. Note that this must be the exact type as
+ * autoboxing and autounboxing is not used.
+ *
+ * @return Reference to the current object to allow call chaining.
+ *
+ * @throws IllegalArgumentException
+ * In case no setter is found or multiple setters are found.
+ */
+ public SetterConfiguration addSetter(final Class aType) {
+ List<Method> result = new ArrayList<Method>();
+ CollectionFilter.filter(getAllSetters(clazz, publicOnly), result,
+ new Condition<Method>() {
+ @Override
+ public boolean matches(Method aObject) {
+ Class type = aObject.getParameterTypes()[0];
+
+ return type.equals(aType);
+ }
+ });
+
+ if (result.size() == 0) {
+ throw new IllegalArgumentException("No setter found in class '" +
+ clazz.getName() + "' that has a setter with argument type '" +
+ aType.getName() + "'");
+ }
+
+ if (result.size() > 1) {
+ String setters = "";
+
+ for (Method method : result) {
+ setters += (method.getName() + " ");
+ }
+
+ throw new IllegalArgumentException(
+ "Multiple setters found in class '" + clazz.getName() +
+ " that accept type '" + aType.getName() + "': " + setters);
+ }
+
+ Method method = result.get(0);
+ setters.put(method, createParameterValues(method));
+
+ return this;
+ }
+
+ /**
+ * Gets all setters for the current class.
+ *
+ *
+ * @return List of all setters.
+ */
+ public static List<Method> getAllSetters(Class aClass, boolean aPublicOnly) {
+ List<Method> result = new ArrayList<Method>();
+
+ for (Method method : getAllMethods(aClass)) {
+ if (!aPublicOnly || Modifier.isPublic(method.getModifiers())) {
+ if (method.getName().startsWith("set") &&
+ (method.getParameterTypes().length == 1)) {
+ method.setAccessible(true);
+ result.add(method);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ private static ParameterValues createParameterValues(Method aMethod) {
+ Class[] paramTypes = aMethod.getParameterTypes();
+ String[] paramNames = new String[paramTypes.length];
+
+ for (int i = 0; i < paramTypes.length; i++) {
+ paramNames[i] = aMethod.getName() + "." + i;
+ }
+
+ return new ParameterValues(paramNames, paramTypes);
+ }
+
+ private static final List<Method> getAllMethods(Class aClass) {
+ return ReflectionUtils.getAllMethods(aClass);
+ }
+
+ /**
+ * Gets the required interfaces based on the configured setteres.
+ *
+ * @return List of required interfaces.
+ */
+ public List<RequiredInterface> getRequiredInterfaces() {
+ List<RequiredInterface> result = new ArrayList<RequiredInterface>();
+
+ for (Method method : setters.keySet()) {
+ result.addAll(setters.get(method).getRequiredInterfaces());
+ }
+
+ return result;
+ }
+
+ /**
+ * Invokes all configured setters with the appropriate values.
+ *
+ * @param aScope
+ * Scope within which invocation takes place.
+ * @param aObject
+ * Object on which the invocation takes place.
+ *
+ */
+ public void inject(Scope aScope, Object aObject) {
+ if (!clazz.isInstance(aObject)) {
+ throw new IllegalArgumentException("Object '" + aObject +
+ "' is not an instance of " + clazz.getName());
+ }
+
+ for (Method method : setters.keySet()) {
+ ParameterValues values = setters.get(method);
+
+ try {
+ method.invoke(aObject, values.values(aScope));
+ } catch (IllegalAccessException e) {
+ throw new SystemAssemblyException("Problem invoking " + method +
+ " with " + values, e);
+ } catch (InvocationTargetException e) {
+ throw new SystemAssemblyException("Problem invoking " + method +
+ " with " + values, e);
+ }
+ }
+ }
+
+ /**
+ * Returns the parameter values for allowing detailed configuration of how
+ * parameter values are set.
+ *
+ * @param aMethod
+ * Setter name without the "set" prefix with the first character
+ * converted to lower case.
+ *
+ * @return Parameter values.
+ *
+ */
+ public ParameterValues values(String aMethod) {
+ for (Method method : setters.keySet()) {
+ if (method.getName().equals(aMethod)) {
+ return setters.get(method);
+ }
+ }
+
+ throw new IllegalArgumentException("No setter method '" + aMethod +
+ "' found");
+ }
+
+ public List<Method> getSetters() {
+ return new ArrayList<Method>(setters.keySet());
+ }