1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.betwixt.expression;
18
19 import java.lang.reflect.Method;
20
21 /*** <p><code>MethodExpression</code> evaluates a method on the current bean context.</p>
22 *
23 * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
24 * @version $Revision: 471234 $
25 */
26 public class MethodExpression implements Expression {
27
28 /*** null arguments */
29 protected static Object[] NULL_ARGUMENTS;
30 /*** null classes */
31 protected static Class[] NULL_CLASSES;
32
33 /*** The method to call on the bean */
34 private Method method;
35
36 /*** Base constructor */
37 public MethodExpression() {
38 }
39
40 /***
41 * Convenience constructor sets method property
42 * @param method the Method whose return value when invoked on the bean
43 * will the value of this expression
44 */
45 public MethodExpression(Method method) {
46 this.method = method;
47 }
48
49 /***
50 * Evaluate by calling the read method on the current bean
51 *
52 * @param context the context against which this expression will be evaluated
53 * @return the value returned by the method when it's invoked on the context's bean,
54 * so long as the method can be invoked.
55 * Otherwise, null.
56 */
57 public Object evaluate(Context context) {
58 Object bean = context.getBean();
59 if ( bean != null ) {
60 Object[] arguments = getArguments();
61 try {
62 return method.invoke( bean, arguments );
63
64 } catch (IllegalAccessException e) {
65
66 Method alternate = null;
67 try {
68 Class type = bean.getClass();
69 alternate = findAlternateMethod( type, method );
70 if ( alternate != null ) {
71 try
72 {
73 return alternate.invoke( bean, arguments );
74 } catch (IllegalAccessException ex) {
75 alternate.setAccessible(true);
76 return alternate.invoke( bean, arguments );
77 }
78 }
79 else
80 {
81 method.setAccessible(true);
82 return method.invoke( bean, arguments );
83 }
84 } catch (Exception e2) {
85 handleException(context, e2, alternate);
86 }
87 } catch (Exception e) {
88 handleException(context, e, method);
89 }
90 }
91 return null;
92 }
93
94 /***
95 * Do nothing.
96 * @see org.apache.commons.betwixt.expression.Expression
97 */
98 public void update(Context context, String newValue) {
99
100 }
101
102 /***
103 * Gets the method used to evaluate this expression.
104 * @return the method whose value (when invoked against the context's bean) will be used
105 * to evaluate this expression.
106 */
107 public Method getMethod() {
108 return method;
109 }
110
111 /***
112 * Sets the method used to evaluate this expression
113 * @param method method whose value (when invoked against the context's bean) will be used
114 * to evaluate this expression
115 */
116 public void setMethod(Method method) {
117 this.method = method;
118 }
119
120
121
122
123 /***
124 * Allows derived objects to create arguments for the method call
125 * @return {@link #NULL_ARGUMENTS}
126 */
127 protected Object[] getArguments() {
128 return NULL_ARGUMENTS;
129 }
130
131 /*** Tries to find an alternate method for the given type using interfaces
132 * which gets around the problem of inner classes,
133 * such as on Map.Entry implementations.
134 *
135 * @param type the Class whose methods are to be searched
136 * @param method the Method for which an alternative is to be search for
137 * @return the alternative Method, if one can be found. Otherwise null.
138 */
139 protected Method findAlternateMethod(
140 Class type,
141 Method method ) {
142
143
144
145
146 Class[] interfaces = type.getInterfaces();
147 if ( interfaces != null ) {
148 String name = method.getName();
149 for ( int i = 0, size = interfaces.length; i < size; i++ ) {
150 Class otherType = interfaces[i];
151
152
153 try {
154 Method alternate = otherType.getMethod( name, NULL_CLASSES );
155 if ( alternate != null && alternate != method ) {
156 return alternate;
157 }
158 } catch (NoSuchMethodException e) {
159
160 }
161 }
162 }
163 return null;
164 }
165
166 /***
167 * <p>Log error to context's logger.</p>
168 *
169 * <p>Allows derived objects to handle exceptions differently.</p>
170 *
171 * @param context the Context being evaluated when the exception occured
172 * @param e the exception to handle
173 * @since 0.8
174 */
175 protected void handleException(Context context, Exception e, Method m) {
176
177 context.getLog().error("[MethodExpression] Cannot evaluate method " + m, e);
178 }
179
180 /***
181 * <p>Log error to context's logger.</p>
182 *
183 * <p>Allows derived objects to handle exceptions differently.</p>
184 *
185 * @param context the Context being evaluated when the exception occured
186 * @param e the exception to handle
187 */
188 protected void handleException(Context context, Exception e) {
189
190 context.getLog().error("[MethodExpression] Cannot evaluate method ", e);
191 }
192
193 /***
194 * Returns something useful for logging.
195 * @return something useful for logging
196 */
197 public String toString() {
198 return "MethodExpression [method=" + method + "]";
199 }
200 }