001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.rules.constraint; 017 018 import java.lang.reflect.Method; 019 020 import org.springframework.rules.constraint.Constraint; 021 import org.springframework.rules.reporting.TypeResolvable; 022 import org.springframework.util.Assert; 023 024 /** 025 * A adapter that can adapt a method on an object that accepts a single argument 026 * and returns a boolean result a UnaryPredicate. For example, a DAO might have 027 * the method <code>isUnique(String objectName)<code> that 028 * tests whether not a name parameter is unique. To adapt that method as a 029 * UnaryPredicate, use this class. 030 * 031 * @author Keith Donald 032 */ 033 public class MethodInvokingConstraint implements Constraint, TypeResolvable { 034 035 private Object targetObject; 036 037 private Method testMethod; 038 039 private String type; 040 041 /** 042 * Creates a MethodInvokingConstraint for the provided target object - the 043 * constraint logic is encapsulated within the specified method name. 044 * 045 * Note: this constructor will attempt to guess the parameter type for the 046 * method as it accept a single unary argument and return a boolean result. 047 * 048 * @param targetObject 049 * The target object 050 * @param methodName 051 * The method name 052 */ 053 public MethodInvokingConstraint(Object targetObject, String methodName) { 054 this(targetObject, methodName, null, null); 055 } 056 057 public MethodInvokingConstraint(Object targetObject, String methodName, 058 String constraintType) { 059 this(targetObject, methodName, null, constraintType); 060 } 061 062 private Class guessParameterType(Object object, String methodName) { 063 Method[] methods = targetObject.getClass().getMethods(); 064 for (int i = 0; i < methods.length; i++) { 065 Method m = methods[i]; 066 if (m.getName().equals(methodName)) { 067 Class[] types = m.getParameterTypes(); 068 if (types.length == 1) { 069 return types[0]; 070 } 071 } 072 } 073 throw new IllegalArgumentException( 074 "No single argument, boolean method found with name '" 075 + methodName + "'"); 076 } 077 078 public MethodInvokingConstraint(Object targetObject, String methodName, 079 Class parameterType) { 080 this(targetObject, methodName, parameterType, null); 081 } 082 083 public MethodInvokingConstraint(Object targetObject, String methodName, 084 Class parameterType, String constraintType) { 085 Assert.notNull(targetObject, "targetObject is required"); 086 this.targetObject = targetObject; 087 if (parameterType == null) { 088 parameterType = guessParameterType(targetObject, methodName); 089 } 090 setType(constraintType); 091 try { 092 this.testMethod = targetObject.getClass().getMethod(methodName, 093 new Class[]{parameterType}); 094 } 095 catch (NoSuchMethodException e) { 096 throw new RuntimeException(e); 097 } 098 Class returnType = testMethod.getReturnType(); 099 Assert.isTrue(returnType == Boolean.class 100 || returnType == boolean.class, "Return type must be a boolean type"); 101 } 102 103 public String getType() { 104 return type; 105 } 106 107 public void setType(String type) { 108 this.type = type; 109 } 110 111 public boolean test(Object argument) { 112 try { 113 return ((Boolean) testMethod.invoke(targetObject, 114 new Object[]{argument})).booleanValue(); 115 } 116 catch (Exception e) { 117 throw new RuntimeException(e); 118 } 119 } 120 }