Coverage Report - org.apache.commons.betwixt.expression.MethodExpression

Classes in this File Line Coverage Branch Coverage Complexity
MethodExpression
57% 
100% 
2.5

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