1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  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
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  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.
  15. */
  16. package org.apache.commons.betwixt.expression;
  17. import java.lang.reflect.Method;
  18. /** <p><code>MethodExpression</code> evaluates a method on the current bean context.</p>
  19. *
  20. * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
  21. * @version $Revision: 1.8 $
  22. */
  23. public class MethodExpression implements Expression {
  24. /** null arguments */
  25. protected static Object[] NULL_ARGUMENTS;
  26. /** null classes */
  27. protected static Class[] NULL_CLASSES;
  28. /** The method to call on the bean */
  29. private Method method;
  30. /** Base constructor */
  31. public MethodExpression() {
  32. }
  33. /**
  34. * Convenience constructor sets method property
  35. * @param method the Method whose return value when invoked on the bean
  36. * will the value of this expression
  37. */
  38. public MethodExpression(Method method) {
  39. this.method = method;
  40. }
  41. /**
  42. * Evaluate by calling the read method on the current bean
  43. *
  44. * @param context the context against which this expression will be evaluated
  45. * @return the value returned by the method when it's invoked on the context's bean,
  46. * so long as the method can be invoked.
  47. * Otherwise, null.
  48. */
  49. public Object evaluate(Context context) {
  50. Object bean = context.getBean();
  51. if ( bean != null ) {
  52. Object[] arguments = getArguments();
  53. try {
  54. return method.invoke( bean, arguments );
  55. } catch (IllegalAccessException e) {
  56. // lets try use another method with the same name
  57. try {
  58. Class type = bean.getClass();
  59. Method alternate = findAlternateMethod( type, method );
  60. if ( alternate != null ) {
  61. return alternate.invoke( bean, arguments );
  62. }
  63. } catch (Exception e2) {
  64. handleException(context, e2);
  65. }
  66. } catch (Exception e) {
  67. handleException(context, e);
  68. }
  69. }
  70. return null;
  71. }
  72. /**
  73. * Do nothing.
  74. * @see org.apache.commons.betwixt.expression.Expression
  75. */
  76. public void update(Context context, String newValue) {
  77. // do nothing
  78. }
  79. /**
  80. * Gets the method used to evaluate this expression.
  81. * @return the method whose value (when invoked against the context's bean) will be used
  82. * to evaluate this expression.
  83. */
  84. public Method getMethod() {
  85. return method;
  86. }
  87. /**
  88. * Sets the method used to evaluate this expression
  89. * @param method method whose value (when invoked against the context's bean) will be used
  90. * to evaluate this expression
  91. */
  92. public void setMethod(Method method) {
  93. this.method = method;
  94. }
  95. // Implementation methods
  96. //-------------------------------------------------------------------------
  97. /**
  98. * Allows derived objects to create arguments for the method call
  99. * @return {@link #NULL_ARGUMENTS}
  100. */
  101. protected Object[] getArguments() {
  102. return NULL_ARGUMENTS;
  103. }
  104. /** Tries to find an alternate method for the given type using interfaces
  105. * which gets around the problem of inner classes,
  106. * such as on Map.Entry implementations.
  107. *
  108. * @param type the Class whose methods are to be searched
  109. * @param method the Method for which an alternative is to be search for
  110. * @return the alternative Method, if one can be found. Otherwise null.
  111. */
  112. protected Method findAlternateMethod(
  113. Class type,
  114. Method method ) {
  115. // XXX
  116. // Would it be better to use the standard reflection code in eg. lang
  117. // since this code contains workarounds for common JVM bugs?
  118. //
  119. Class[] interfaces = type.getInterfaces();
  120. if ( interfaces != null ) {
  121. String name = method.getName();
  122. for ( int i = 0, size = interfaces.length; i < size; i++ ) {
  123. Class otherType = interfaces[i];
  124. //
  125. // catch NoSuchMethodException so that all interfaces will be tried
  126. try {
  127. Method alternate = otherType.getMethod( name, NULL_CLASSES );
  128. if ( alternate != null && alternate != method ) {
  129. return alternate;
  130. }
  131. } catch (NoSuchMethodException e) {
  132. // swallow
  133. }
  134. }
  135. }
  136. return null;
  137. }
  138. /**
  139. * <p>Log error to context's logger.</p>
  140. *
  141. * <p>Allows derived objects to handle exceptions differently.</p>
  142. *
  143. * @param context the Context being evaluated when the exception occured
  144. * @param e the exception to handle
  145. */
  146. protected void handleException(Context context, Exception e) {
  147. // use the context's logger to log the problem
  148. context.getLog().error("[MethodExpression] Cannot evaluate expression ", e);
  149. }
  150. /**
  151. * Returns something useful for logging.
  152. * @return something useful for logging
  153. */
  154. public String toString() {
  155. return "MethodExpression [method=" + method + "]";
  156. }
  157. }