Coverage Report - org.apache.commons.ognl.OgnlOps
 
Classes in this File Line Coverage Branch Coverage Complexity
OgnlOps
78%
313/397
74%
304/407
5.162
 
 1  
 package org.apache.commons.ognl;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import org.apache.commons.ognl.enhance.UnsupportedCompilationException;
 23  
 
 24  
 import java.lang.reflect.Array;
 25  
 import java.math.BigDecimal;
 26  
 import java.math.BigInteger;
 27  
 import java.util.Enumeration;
 28  
 
 29  
 /**
 30  
  * This is an abstract class with static methods that define the operations of OGNL.
 31  
  * 
 32  
  * @author Luke Blanshard (blanshlu@netscape.net)
 33  
  * @author Drew Davidson (drew@ognl.org)
 34  
  */
 35  0
 public abstract class OgnlOps
 36  
     implements NumericTypes
 37  
 {
 38  
 
 39  
     /**
 40  
      * Compares two objects for equality, even if it has to convert one of them to the other type. If both objects are
 41  
      * numeric they are converted to the widest type and compared. If one is non-numeric and one is numeric the
 42  
      * non-numeric is converted to double and compared to the double numeric value. If both are non-numeric and
 43  
      * Comparable and the types are compatible (i.e. v1 is of the same or superclass of v2's type) they are compared
 44  
      * with Comparable.compareTo(). If both values are non-numeric and not Comparable or of incompatible classes this
 45  
      * will throw and IllegalArgumentException.
 46  
      * 
 47  
      * @param v1 First value to compare
 48  
      * @param v2 second value to compare
 49  
      * @return integer describing the comparison between the two objects. A negative number indicates that v1 < v2.
 50  
      *         Positive indicates that v1 > v2. Zero indicates v1 == v2.
 51  
      * @throws IllegalArgumentException if the objects are both non-numeric yet of incompatible types or do not
 52  
      *             implement Comparable.
 53  
      */
 54  
     public static int compareWithConversion( Object v1, Object v2 )
 55  
     {
 56  
         int result;
 57  
 
 58  176
         if ( v1 == v2 )
 59  
         {
 60  2
             result = 0;
 61  
         }
 62  
         else
 63  
         {
 64  174
             int t1 = getNumericType( v1 ), t2 = getNumericType( v2 ), type = getNumericType( t1, t2, true );
 65  
 
 66  174
             switch ( type )
 67  
             {
 68  
                 case BIGINT:
 69  30
                     result = bigIntValue( v1 ).compareTo( bigIntValue( v2 ) );
 70  30
                     break;
 71  
 
 72  
                 case BIGDEC:
 73  1
                     result = bigDecValue( v1 ).compareTo( bigDecValue( v2 ) );
 74  1
                     break;
 75  
 
 76  
                 case NONNUMERIC:
 77  31
                     if ( ( t1 == NONNUMERIC ) && ( t2 == NONNUMERIC ) )
 78  
                     {
 79  14
                         if ( ( v1 instanceof Comparable ) && v1.getClass().isAssignableFrom( v2.getClass() ) )
 80  
                         {
 81  14
                             result = ( (Comparable) v1 ).compareTo( v2 );
 82  14
                             break;
 83  
                         }
 84  0
                         throw new IllegalArgumentException( "invalid comparison: " + v1.getClass().getName()
 85  
                             + " and " + v2.getClass().getName() );
 86  
                     }
 87  
                     // else fall through
 88  
                 case FLOAT:
 89  
                 case DOUBLE:
 90  21
                     double dv1 = doubleValue( v1 ),
 91  21
                     dv2 = doubleValue( v2 );
 92  
 
 93  21
                     return ( dv1 == dv2 ) ? 0 : ( ( dv1 < dv2 ) ? -1 : 1 );
 94  
 
 95  
                 default:
 96  108
                     long lv1 = longValue( v1 ),
 97  108
                     lv2 = longValue( v2 );
 98  
 
 99  108
                     return ( lv1 == lv2 ) ? 0 : ( ( lv1 < lv2 ) ? -1 : 1 );
 100  
             }
 101  
         }
 102  47
         return result;
 103  
     }
 104  
 
 105  
     /**
 106  
      * Returns true if object1 is equal to object2 in either the sense that they are the same object or, if both are
 107  
      * non-null if they are equal in the <CODE>equals()</CODE> sense.
 108  
      * 
 109  
      * @param object1 First object to compare
 110  
      * @param object2 Second object to compare
 111  
      * @return true if v1 == v2
 112  
      */
 113  
     public static boolean isEqual( Object object1, Object object2 )
 114  
     {
 115  66
         boolean result = false;
 116  
 
 117  66
         if ( object1 == object2 )
 118  
         {
 119  0
             result = true;
 120  
         }
 121  
         else
 122  
         {
 123  66
             if ( ( object1 != null ) && object1.getClass().isArray() )
 124  
             {
 125  0
                 if ( ( object2 != null ) && object2.getClass().isArray() && ( object2.getClass()
 126  
                     == object1.getClass() ) )
 127  
                 {
 128  0
                     result = ( Array.getLength( object1 ) == Array.getLength( object2 ) );
 129  0
                     if ( result )
 130  
                     {
 131  0
                         for ( int i = 0, icount = Array.getLength( object1 ); result && ( i < icount ); i++ )
 132  
                         {
 133  0
                             result = isEqual( Array.get( object1, i ), Array.get( object2, i ) );
 134  
                         }
 135  
                     }
 136  
                 }
 137  
             }
 138  
             else
 139  
             {
 140  
                 // Check for converted equivalence first, then equals() equivalence
 141  66
                 result =
 142  
                     ( object1 != null ) && ( object2 != null )
 143  
                         && ( object1.equals( object2 ) || ( compareWithConversion( object1, object2 ) == 0 ) );
 144  
             }
 145  
         }
 146  66
         return result;
 147  
     }
 148  
 
 149  
     public static boolean booleanValue( boolean value )
 150  
     {
 151  30
         return value;
 152  
     }
 153  
 
 154  
     public static boolean booleanValue( int value )
 155  
     {
 156  5
         return value > 0;
 157  
     }
 158  
 
 159  
     public static boolean booleanValue( float value )
 160  
     {
 161  0
         return value > 0;
 162  
     }
 163  
 
 164  
     public static boolean booleanValue( long value )
 165  
     {
 166  0
         return value > 0;
 167  
     }
 168  
 
 169  
     public static boolean booleanValue( double value )
 170  
     {
 171  0
         return value > 0;
 172  
     }
 173  
 
 174  
     /**
 175  
      * Evaluates the given object as a boolean: if it is a Boolean object, it's easy; if it's a Number or a Character,
 176  
      * returns true for non-zero objects; and otherwise returns true for non-null objects.
 177  
      * 
 178  
      * @param value an object to interpret as a boolean
 179  
      * @return the boolean value implied by the given object
 180  
      */
 181  
     public static boolean booleanValue( Object value )
 182  
     {
 183  252
         if ( value == null )
 184  
         {
 185  16
             return false;
 186  
         }
 187  236
         Class<?> c = value.getClass();
 188  
 
 189  236
         if ( c == Boolean.class )
 190  
         {
 191  194
             return (Boolean) value;
 192  
         }
 193  
         // if ( c == String.class )
 194  
         // return ((String)value).length() > 0;
 195  
 
 196  42
         if ( c == Character.class )
 197  
         {
 198  1
             return (Character) value != 0;
 199  
         }
 200  41
         return !( value instanceof Number ) || ( (Number) value ).doubleValue() != 0;
 201  
 
 202  
     }
 203  
 
 204  
     /**
 205  
      * Evaluates the given object as a long integer.
 206  
      * 
 207  
      * @param value an object to interpret as a long integer
 208  
      * @return the long integer value implied by the given object
 209  
      * @throws NumberFormatException if the given object can't be understood as a long integer
 210  
      */
 211  
     public static long longValue( Object value )
 212  
     {
 213  804
         if ( value == null )
 214  
         {
 215  0
             return 0L;
 216  
         }
 217  804
         Class<?> c = value.getClass();
 218  804
         if ( c.getSuperclass() == Number.class )
 219  
         {
 220  757
             return ( (Number) value ).longValue();
 221  
         }
 222  47
         if ( c == Boolean.class )
 223  
         {
 224  9
             return (Boolean) value ? 1 : 0;
 225  
         }
 226  38
         if ( c == Character.class )
 227  
         {
 228  6
             return (Character) value;
 229  
         }
 230  32
         return Long.parseLong( stringValue( value, true ) );
 231  
     }
 232  
 
 233  
     /**
 234  
      * Evaluates the given object as a double-precision floating-point number.
 235  
      * 
 236  
      * @param value an object to interpret as a double
 237  
      * @return the double value implied by the given object
 238  
      * @throws NumberFormatException if the given object can't be understood as a double
 239  
      */
 240  
     public static double doubleValue( Object value )
 241  
     {
 242  89
         if ( value == null )
 243  
         {
 244  0
             return 0.0;
 245  
         }
 246  89
         Class<?> c = value.getClass();
 247  89
         if ( c.getSuperclass() == Number.class )
 248  
         {
 249  63
             return ( (Number) value ).doubleValue();
 250  
         }
 251  26
         if ( c == Boolean.class )
 252  
         {
 253  2
             return (Boolean) value ? 1 : 0;
 254  
         }
 255  24
         if ( c == Character.class )
 256  
         {
 257  2
             return (Character) value;
 258  
         }
 259  22
         String s = stringValue( value, true );
 260  
 
 261  22
         return ( s.length() == 0 ) ? 0.0 : Double.parseDouble( s );
 262  
     }
 263  
 
 264  
     /**
 265  
      * Evaluates the given object as a BigInteger.
 266  
      * 
 267  
      * @param value an object to interpret as a BigInteger
 268  
      * @return the BigInteger value implied by the given object
 269  
      * @throws NumberFormatException if the given object can't be understood as a BigInteger
 270  
      */
 271  
     public static BigInteger bigIntValue( Object value )
 272  
     {
 273  349
         if ( value == null )
 274  
         {
 275  0
             return BigInteger.valueOf( 0L );
 276  
         }
 277  349
         Class<?> c = value.getClass();
 278  349
         if ( c == BigInteger.class )
 279  
         {
 280  227
             return (BigInteger) value;
 281  
         }
 282  122
         if ( c == BigDecimal.class )
 283  
         {
 284  2
             return ( (BigDecimal) value ).toBigInteger();
 285  
         }
 286  120
         if ( c.getSuperclass() == Number.class )
 287  
         {
 288  115
             return BigInteger.valueOf( ( (Number) value ).longValue() );
 289  
         }
 290  5
         if ( c == Boolean.class )
 291  
         {
 292  1
             return BigInteger.valueOf( (Boolean) value ? 1 : 0 );
 293  
         }
 294  4
         if ( c == Character.class )
 295  
         {
 296  1
             return BigInteger.valueOf( (Character) value );
 297  
         }
 298  3
         return new BigInteger( stringValue( value, true ) );
 299  
     }
 300  
 
 301  
     /**
 302  
      * Evaluates the given object as a BigDecimal.
 303  
      * 
 304  
      * @param value an object to interpret as a BigDecimal
 305  
      * @return the BigDecimal value implied by the given object
 306  
      * @throws NumberFormatException if the given object can't be understood as a BigDecimal
 307  
      */
 308  
     public static BigDecimal bigDecValue( Object value )
 309  
     {
 310  38
         if ( value == null )
 311  
         {
 312  0
             return BigDecimal.valueOf( 0L );
 313  
         }
 314  38
         Class<?> c = value.getClass();
 315  38
         if ( c == BigDecimal.class )
 316  
         {
 317  13
             return (BigDecimal) value;
 318  
         }
 319  25
         if ( c == BigInteger.class )
 320  
         {
 321  1
             return new BigDecimal( (BigInteger) value );
 322  
         }
 323  24
         if ( c == Boolean.class )
 324  
         {
 325  1
             return BigDecimal.valueOf( (Boolean) value ? 1 : 0 );
 326  
         }
 327  23
         if ( c == Character.class )
 328  
         {
 329  1
             return BigDecimal.valueOf( ( (Character) value ).charValue() );
 330  
         }
 331  22
         return new BigDecimal( stringValue( value, true ) );
 332  
     }
 333  
 
 334  
     /**
 335  
      * Evaluates the given object as a String and trims it if the trim flag is true.
 336  
      * 
 337  
      * @param value an object to interpret as a String
 338  
      * @param trim if true trims the result
 339  
      * @return the String value implied by the given object as returned by the toString() method, or "null" if the
 340  
      *         object is null.
 341  
      */
 342  
     public static String stringValue( Object value, boolean trim )
 343  
     {
 344  
         String result;
 345  
 
 346  211
         if ( value == null )
 347  
         {
 348  3
             result = OgnlRuntime.NULL_STRING;
 349  
         }
 350  
         else
 351  
         {
 352  208
             result = value.toString();
 353  208
             if ( trim )
 354  
             {
 355  79
                 result = result.trim();
 356  
             }
 357  
         }
 358  211
         return result;
 359  
     }
 360  
 
 361  
     /**
 362  
      * Evaluates the given object as a String.
 363  
      * 
 364  
      * @param value an object to interpret as a String
 365  
      * @return the String value implied by the given object as returned by the toString() method, or "null" if the
 366  
      *         object is null.
 367  
      */
 368  
     public static String stringValue( Object value )
 369  
     {
 370  132
         return stringValue( value, false );
 371  
     }
 372  
 
 373  
     /**
 374  
      * Returns a constant from the NumericTypes interface that represents the numeric type of the given object.
 375  
      * 
 376  
      * @param value an object that needs to be interpreted as a number
 377  
      * @return the appropriate constant from the NumericTypes interface
 378  
      */
 379  
     public static int getNumericType( Object value )
 380  
     {
 381  1373
         if ( value != null )
 382  
         {
 383  1365
             Class<?> c = value.getClass();
 384  1365
             if ( c == Integer.class )
 385  
             {
 386  719
                 return INT;
 387  
             }
 388  646
             if ( c == Double.class )
 389  
             {
 390  25
                 return DOUBLE;
 391  
             }
 392  621
             if ( c == Boolean.class )
 393  
             {
 394  8
                 return BOOL;
 395  
             }
 396  613
             if ( c == Byte.class )
 397  
             {
 398  0
                 return BYTE;
 399  
             }
 400  613
             if ( c == Character.class )
 401  
             {
 402  20
                 return CHAR;
 403  
             }
 404  593
             if ( c == Short.class )
 405  
             {
 406  0
                 return SHORT;
 407  
             }
 408  593
             if ( c == Long.class )
 409  
             {
 410  137
                 return LONG;
 411  
             }
 412  456
             if ( c == Float.class )
 413  
             {
 414  2
                 return FLOAT;
 415  
             }
 416  454
             if ( c == BigInteger.class )
 417  
             {
 418  229
                 return BIGINT;
 419  
             }
 420  225
             if ( c == BigDecimal.class )
 421  
             {
 422  19
                 return BIGDEC;
 423  
             }
 424  
         }
 425  214
         return NONNUMERIC;
 426  
     }
 427  
 
 428  
     public static Object toArray( char value, Class<?> toType )
 429  
         throws OgnlException
 430  
     {
 431  0
         return toArray( Character.valueOf( value ), toType );
 432  
     }
 433  
 
 434  
     public static Object toArray( byte value, Class<?> toType )
 435  
         throws OgnlException
 436  
     {
 437  0
         return toArray( Byte.valueOf( value ), toType );
 438  
     }
 439  
 
 440  
     public static Object toArray( int value, Class<?> toType )
 441  
         throws OgnlException
 442  
     {
 443  0
         return toArray( Integer.valueOf( value ), toType );
 444  
     }
 445  
 
 446  
     public static Object toArray( long value, Class<?> toType )
 447  
         throws OgnlException
 448  
     {
 449  0
         return toArray( Long.valueOf( value ), toType );
 450  
     }
 451  
 
 452  
     public static Object toArray( float value, Class<?> toType )
 453  
         throws OgnlException
 454  
     {
 455  0
         return toArray( Float.valueOf( value ), toType );
 456  
     }
 457  
 
 458  
     public static Object toArray( double value, Class<?> toType )
 459  
         throws OgnlException
 460  
     {
 461  0
         return toArray( Double.valueOf( value ), toType );
 462  
     }
 463  
 
 464  
     public static Object toArray( boolean value, Class<?> toType )
 465  
         throws OgnlException
 466  
     {
 467  0
         return toArray( Boolean.valueOf( value ), toType );
 468  
     }
 469  
 
 470  
     public static <T> Object convertValue( char value, Class<T> toType )
 471  
         throws OgnlException
 472  
     {
 473  2
         return convertValue( Character.valueOf(value), toType );
 474  
     }
 475  
 
 476  
     public static <T> Object convertValue( byte value, Class<T> toType )
 477  
         throws OgnlException
 478  
     {
 479  0
         return convertValue( Byte.valueOf( value ), toType );
 480  
     }
 481  
 
 482  
     public static <T> Object convertValue( int value, Class<T> toType )
 483  
         throws OgnlException
 484  
     {
 485  3
         return convertValue( Integer.valueOf( value ), toType );
 486  
     }
 487  
 
 488  
     public static <T> Object convertValue( long value, Class<T> toType )
 489  
         throws OgnlException
 490  
     {
 491  0
         return convertValue( Long.valueOf( value ), toType );
 492  
     }
 493  
 
 494  
     public static <T> Object convertValue( float value, Class<T> toType )
 495  
         throws OgnlException
 496  
     {
 497  0
         return convertValue( Float.valueOf( value ), toType );
 498  
     }
 499  
 
 500  
     public static <T> Object convertValue( double value, Class<T> toType )
 501  
         throws OgnlException
 502  
     {
 503  0
         return convertValue( Double.valueOf( value ), toType );
 504  
     }
 505  
 
 506  
     public static <T> Object convertValue( boolean value, Class<T> toType )
 507  
         throws OgnlException
 508  
     {
 509  0
         return convertValue( Boolean.valueOf( value ), toType );
 510  
     }
 511  
 
 512  
     // //////////////////////////////////////////////////////////////
 513  
 
 514  
     public static <T> Object convertValue( char value, Class<T> toType, boolean preventNull )
 515  
         throws OgnlException
 516  
     {
 517  0
         return convertValue( Character.valueOf( value ), toType, preventNull );
 518  
     }
 519  
 
 520  
     public static <T> Object convertValue( byte value, Class<T> toType, boolean preventNull )
 521  
         throws OgnlException
 522  
     {
 523  0
         return convertValue( Byte.valueOf( value ), toType, preventNull );
 524  
     }
 525  
 
 526  
     public static <T> Object convertValue( int value, Class<T> toType, boolean preventNull )
 527  
         throws OgnlException
 528  
     {
 529  5
         return convertValue( Integer.valueOf( value ), toType, preventNull );
 530  
     }
 531  
 
 532  
     public static <T> Object convertValue( long value, Class<T> toType, boolean preventNull )
 533  
         throws OgnlException
 534  
     {
 535  0
         return convertValue( Long.valueOf( value ), toType, preventNull );
 536  
     }
 537  
 
 538  
     public static <T> Object convertValue( float value, Class<T> toType, boolean preventNull )
 539  
         throws OgnlException
 540  
     {
 541  0
         return convertValue( new Float( value ), toType, preventNull );
 542  
     }
 543  
 
 544  
     public static <T> Object convertValue( double value, Class<T> toType, boolean preventNull )
 545  
         throws OgnlException
 546  
     {
 547  0
         return convertValue( new Double( value ), toType, preventNull );
 548  
     }
 549  
 
 550  
     public static <T> Object convertValue( boolean value, Class<T> toType, boolean preventNull )
 551  
         throws OgnlException
 552  
     {
 553  0
         return convertValue( Boolean.valueOf( value ), toType, preventNull );
 554  
     }
 555  
 
 556  
     // ///////////////////////////////////////////////////////////////
 557  
 
 558  
     public static Object toArray( char value, Class<?> toType, boolean preventNull )
 559  
         throws OgnlException
 560  
     {
 561  0
         return toArray( Character.valueOf( value ), toType, preventNull );
 562  
     }
 563  
 
 564  
     public static Object toArray( byte value, Class<?> toType, boolean preventNull )
 565  
         throws OgnlException
 566  
     {
 567  0
         return toArray( Byte.valueOf( value ), toType, preventNull );
 568  
     }
 569  
 
 570  
     public static Object toArray( int value, Class<?> toType, boolean preventNull )
 571  
         throws OgnlException
 572  
     {
 573  1
         return toArray( Integer.valueOf( value ), toType, preventNull );
 574  
     }
 575  
 
 576  
     public static Object toArray( long value, Class<?> toType, boolean preventNull )
 577  
         throws OgnlException
 578  
     {
 579  0
         return toArray( Long.valueOf(value), toType, preventNull );
 580  
     }
 581  
 
 582  
     public static Object toArray( float value, Class<?> toType, boolean preventNull )
 583  
         throws OgnlException
 584  
     {
 585  0
         return toArray( Float.valueOf( value ), toType, preventNull );
 586  
     }
 587  
 
 588  
     public static Object toArray( double value, Class<?> toType, boolean preventNull )
 589  
         throws OgnlException
 590  
     {
 591  0
         return toArray( Double.valueOf(value), toType, preventNull );
 592  
     }
 593  
 
 594  
     public static Object toArray( boolean value, Class<?> toType, boolean preventNull )
 595  
         throws OgnlException
 596  
     {
 597  0
         return toArray( Boolean.valueOf( value ), toType, preventNull );
 598  
     }
 599  
 
 600  
     /**
 601  
      * Returns the value converted numerically to the given class type This method also detects when arrays are being
 602  
      * converted and converts the components of one array to the type of the other.
 603  
      * 
 604  
      * @param value an object to be converted to the given type
 605  
      * @param toType class type to be converted to
 606  
      * @return converted value of the type given, or value if the value cannot be converted to the given type.
 607  
      */
 608  
     public static Object convertValue( Object value, Class<?> toType )
 609  
     {
 610  193
         return convertValue( value, toType, false );
 611  
     }
 612  
 
 613  
     public static Object toArray( Object value, Class<?> toType )
 614  
         throws OgnlException
 615  
     {
 616  2
         return toArray( value, toType, false );
 617  
     }
 618  
 
 619  
     public static Object toArray( Object value, Class<?> toType, boolean preventNulls )
 620  
         throws OgnlException
 621  
     {
 622  3
         if ( value == null )
 623  
         {
 624  0
             return null;
 625  
         }
 626  
 
 627  
         Object result;
 628  
 
 629  3
         Class<?> aClass = value.getClass();
 630  3
         if ( aClass.isArray() && toType.isAssignableFrom( aClass.getComponentType() ) )
 631  
         {
 632  1
             return value;
 633  
         }
 634  
 
 635  2
         if ( !aClass.isArray() )
 636  
         {
 637  
 
 638  1
             if ( toType == Character.TYPE )
 639  
             {
 640  0
                 return stringValue( value ).toCharArray();
 641  
             }
 642  
 
 643  1
             Object arr = Array.newInstance( toType, 1 );
 644  1
             Array.set( arr, 0, convertValue( value, toType, preventNulls ) );
 645  
 
 646  1
             return arr;
 647  
         }
 648  
 
 649  1
         result = Array.newInstance( toType, Array.getLength( value ) );
 650  3
         for ( int i = 0, icount = Array.getLength( value ); i < icount; i++ )
 651  
         {
 652  2
             Array.set( result, i, convertValue( Array.get( value, i ), toType ) );
 653  
         }
 654  
 
 655  1
         if ( result == null && preventNulls )
 656  
         {
 657  0
             return value;
 658  
         }
 659  
 
 660  1
         return result;
 661  
     }
 662  
 
 663  
     public static <T> Object convertValue( Object value, Class<T> toType, boolean preventNulls )
 664  
     {
 665  218
         Object result = null;
 666  
 
 667  218
         if ( value != null && toType.isAssignableFrom( value.getClass() ) )
 668  
         {
 669  35
             return value;
 670  
         }
 671  
 
 672  183
         if ( value != null )
 673  
         {
 674  
             /* If array -> array then convert components of array individually */
 675  180
             boolean classIsArray = value.getClass().isArray();
 676  180
             boolean toTypeIsArray = toType.isArray();
 677  180
             if ( classIsArray && toTypeIsArray)
 678  
             {
 679  1
                 Class<?> componentType = toType.getComponentType();
 680  
 
 681  1
                 result = Array.newInstance( componentType, Array.getLength( value ) );
 682  4
                 for ( int i = 0, icount = Array.getLength( value ); i < icount; i++ )
 683  
                 {
 684  3
                     Array.set( result, i, convertValue( Array.get( value, i ), componentType ) );
 685  
                 }
 686  1
             }
 687  179
             else if ( classIsArray && !toTypeIsArray)
 688  
             {
 689  
 
 690  2
                 return convertValue( Array.get( value, 0 ), toType );
 691  
             }
 692  177
             else if ( toTypeIsArray )
 693  
             {
 694  
 
 695  0
                 if ( toType.getComponentType() == Character.TYPE )
 696  
                 {
 697  
 
 698  0
                     result = stringValue( value ).toCharArray();
 699  
                 }
 700  0
                 else if ( toType.getComponentType() == Object.class )
 701  
                 {
 702  0
                     return new Object[] { value };
 703  
                 }
 704  
             }
 705  
             else
 706  
             {
 707  177
                 if ( ( toType == Integer.class ) || ( toType == Integer.TYPE ) )
 708  
                 {
 709  37
                     result = (int) longValue( value );
 710  
                 }
 711  140
                 else if ( ( toType == Double.class ) || ( toType == Double.TYPE ) )
 712  
                 {
 713  12
                     result = doubleValue( value );
 714  
                 }
 715  128
                 else if ( ( toType == Boolean.class ) || ( toType == Boolean.TYPE ) )
 716  
                 {
 717  15
                     result = booleanValue( value ) ? Boolean.TRUE : Boolean.FALSE;
 718  
                 }
 719  113
                 else if ( ( toType == Byte.class ) || ( toType == Byte.TYPE ) )
 720  
                 {
 721  12
                     result = (byte) longValue( value );
 722  
                 }
 723  101
                 else if ( ( toType == Character.class ) || ( toType == Character.TYPE ) )
 724  
                 {
 725  14
                     result = (char) longValue( value );
 726  
                 }
 727  87
                 else if ( ( toType == Short.class ) || ( toType == Short.TYPE ) )
 728  
                 {
 729  12
                     result = (short) longValue( value );
 730  
                 }
 731  75
                 else if ( ( toType == Long.class ) || ( toType == Long.TYPE ) )
 732  
                 {
 733  15
                     result = longValue( value );
 734  
                 }
 735  60
                 else if ( ( toType == Float.class ) || ( toType == Float.TYPE ) )
 736  
                 {
 737  15
                     result = new Float( doubleValue( value ) );
 738  
                 }
 739  45
                 else if ( toType == BigInteger.class )
 740  
                 {
 741  12
                     result = bigIntValue( value );
 742  
                 }
 743  33
                 else if ( toType == BigDecimal.class )
 744  
                 {
 745  12
                     result = bigDecValue( value );
 746  
                 }
 747  21
                 else if ( toType == String.class )
 748  
                 {
 749  20
                     result = stringValue( value );
 750  
                 }
 751  
             }
 752  170
         }
 753  
         else
 754  
         {
 755  3
             if ( toType.isPrimitive() )
 756  
             {
 757  0
                 result = OgnlRuntime.getPrimitiveDefaultValue( toType );
 758  
             }
 759  3
             else if ( preventNulls && toType == Boolean.class )
 760  
             {
 761  0
                 result = Boolean.FALSE;
 762  
             }
 763  3
             else if ( preventNulls && Number.class.isAssignableFrom( toType ) )
 764  
             {
 765  0
                 result = OgnlRuntime.getNumericDefaultValue( toType );
 766  
             }
 767  
         }
 768  
 
 769  173
         if ( result == null && preventNulls )
 770  
         {
 771  0
             return value;
 772  
         }
 773  
 
 774  173
         if ( value != null && result == null )
 775  
         {
 776  
 
 777  1
             throw new IllegalArgumentException( "Unable to convert type " + value.getClass().getName() + " of " + value
 778  
                 + " to type of " + toType.getName() );
 779  
         }
 780  
 
 781  172
         return result;
 782  
     }
 783  
 
 784  
     /**
 785  
      * Converts the specified value to a primitive integer value.
 786  
      * <ul>
 787  
      * <li>Null values will cause a -1 to be returned.</li>
 788  
      * <li>{@link Number} instances have their intValue() methods invoked.</li>
 789  
      * <li>All other types result in calling Integer.parseInt(value.toString());</li>
 790  
      * </ul>
 791  
      * 
 792  
      * @param value The object to get the value of.
 793  
      * @return A valid integer.
 794  
      */
 795  
     public static int getIntValue( Object value )
 796  
     {
 797  
         try
 798  
         {
 799  1
             if ( value == null )
 800  
             {
 801  0
                 return -1;
 802  
             }
 803  
 
 804  1
             if ( Number.class.isInstance( value ) )
 805  
             {
 806  
 
 807  0
                 return ( (Number) value ).intValue();
 808  
             }
 809  
 
 810  1
             String str = String.class.isInstance( value ) ? (String) value : value.toString();
 811  
 
 812  1
             return Integer.parseInt( str );
 813  
         }
 814  0
         catch ( Throwable t )
 815  
         {
 816  0
             throw new RuntimeException( "Error converting " + value + " to integer:", t );
 817  
         }
 818  
     }
 819  
 
 820  
     /**
 821  
      * Returns the constant from the NumericTypes interface that best expresses the type of a numeric operation on the
 822  
      * two given objects.
 823  
      * 
 824  
      * @param v1 one argument to a numeric operator
 825  
      * @param v2 the other argument
 826  
      * @return the appropriate constant from the NumericTypes interface
 827  
      */
 828  
     public static int getNumericType( Object v1, Object v2 )
 829  
     {
 830  306
         return getNumericType( v1, v2, false );
 831  
     }
 832  
 
 833  
     /**
 834  
      * Returns the constant from the NumericTypes interface that best expresses the type of an operation, which can be
 835  
      * either numeric or not, on the two given types.
 836  
      * 
 837  
      * @param t1 type of one argument to an operator
 838  
      * @param t2 type of the other argument
 839  
      * @param canBeNonNumeric whether the operator can be interpreted as non-numeric
 840  
      * @return the appropriate constant from the NumericTypes interface
 841  
      */
 842  
     public static int getNumericType( int t1, int t2, boolean canBeNonNumeric )
 843  
     {
 844  618
         if ( t1 == t2 )
 845  
         {
 846  367
             return t1;
 847  
         }
 848  
 
 849  251
         if ( canBeNonNumeric && ( t1 == NONNUMERIC || t2 == NONNUMERIC || t1 == CHAR || t2 == CHAR ) )
 850  
         {
 851  44
             return NONNUMERIC;
 852  
         }
 853  
 
 854  207
         if ( t1 == NONNUMERIC )
 855  
         {
 856  0
             t1 = DOUBLE; // Try to interpret strings as doubles...
 857  
         }
 858  207
         if ( t2 == NONNUMERIC )
 859  
         {
 860  5
             t2 = DOUBLE; // Try to interpret strings as doubles...
 861  
         }
 862  
 
 863  207
         if ( t1 >= MIN_REAL_TYPE )
 864  
         {
 865  22
             if ( t2 >= MIN_REAL_TYPE )
 866  
             {
 867  8
                 return Math.max( t1, t2 );
 868  
             }
 869  14
             if ( t2 < INT )
 870  
             {
 871  0
                 return t1;
 872  
             }
 873  14
             if ( t2 == BIGINT )
 874  
             {
 875  0
                 return BIGDEC;
 876  
             }
 877  14
             return Math.max( DOUBLE, t1 );
 878  
         }
 879  185
         else if ( t2 >= MIN_REAL_TYPE )
 880  
         {
 881  10
             if ( t1 < INT )
 882  
             {
 883  0
                 return t2;
 884  
             }
 885  10
             if ( t1 == BIGINT )
 886  
             {
 887  0
                 return BIGDEC;
 888  
             }
 889  10
             return Math.max( DOUBLE, t2 );
 890  
         }
 891  
         else
 892  
         {
 893  175
             return Math.max( t1, t2 );
 894  
         }
 895  
     }
 896  
 
 897  
     /**
 898  
      * Returns the constant from the NumericTypes interface that best expresses the type of an operation, which can be
 899  
      * either numeric or not, on the two given objects.
 900  
      * 
 901  
      * @param v1 one argument to an operator
 902  
      * @param v2 the other argument
 903  
      * @param canBeNonNumeric whether the operator can be interpreted as non-numeric
 904  
      * @return the appropriate constant from the NumericTypes interface
 905  
      */
 906  
     public static int getNumericType( Object v1, Object v2, boolean canBeNonNumeric )
 907  
     {
 908  444
         return getNumericType( getNumericType( v1 ), getNumericType( v2 ), canBeNonNumeric );
 909  
     }
 910  
 
 911  
     /**
 912  
      * Returns a new Number object of an appropriate type to hold the given integer value. The type of the returned
 913  
      * object is consistent with the given type argument, which is a constant from the NumericTypes interface.
 914  
      * 
 915  
      * @param type the nominal numeric type of the result, a constant from the NumericTypes interface
 916  
      * @param value the integer value to convert to a Number object
 917  
      * @return a Number object with the given value, of type implied by the type argument
 918  
      */
 919  
     public static Number newInteger( int type, long value )
 920  
     {
 921  304
         switch ( type )
 922  
         {
 923  
             case BOOL:
 924  
             case CHAR:
 925  
             case INT:
 926  172
                 return (int) value;
 927  
 
 928  
             case FLOAT:
 929  0
                 if ( (long) (float) value == value )
 930  
                 {
 931  0
                     return (float) value;
 932  
                 }
 933  
                 // else fall through:
 934  
             case DOUBLE:
 935  6
                 if ( (long) (double) value == value )
 936  
                 {
 937  6
                     return (double) value;
 938  
                 }
 939  
                 // else fall through:
 940  
             case LONG:
 941  96
                 return value;
 942  
 
 943  
             case BYTE:
 944  0
                 return (byte) value;
 945  
 
 946  
             case SHORT:
 947  0
                 return (short) value;
 948  
 
 949  
             default:
 950  30
                 return BigInteger.valueOf( value );
 951  
         }
 952  
     }
 953  
 
 954  
     /**
 955  
      * Returns a new Number object of an appropriate type to hold the given real value. The type of the returned object
 956  
      * is always either Float or Double, and is only Float if the given type tag (a constant from the NumericTypes
 957  
      * interface) is FLOAT.
 958  
      * 
 959  
      * @param type the nominal numeric type of the result, a constant from the NumericTypes interface
 960  
      * @param value the real value to convert to a Number object
 961  
      * @return a Number object with the given value, of type implied by the type argument
 962  
      */
 963  
     public static Number newReal( int type, double value )
 964  
     {
 965  10
         if ( type == FLOAT )
 966  
         {
 967  1
             return (float) value;
 968  
         }
 969  9
         return value;
 970  
     }
 971  
 
 972  
     public static Object binaryOr( Object v1, Object v2 )
 973  
     {
 974  7
         int type = getNumericType( v1, v2 );
 975  7
         if ( type == BIGINT || type == BIGDEC )
 976  
         {
 977  1
             return bigIntValue( v1 ).or( bigIntValue( v2 ) );
 978  
         }
 979  6
         return newInteger( type, longValue( v1 ) | longValue( v2 ) );
 980  
     }
 981  
 
 982  
     public static Object binaryXor( Object v1, Object v2 )
 983  
     {
 984  11
         int type = getNumericType( v1, v2 );
 985  11
         if ( type == BIGINT || type == BIGDEC )
 986  
         {
 987  1
             return bigIntValue( v1 ).xor( bigIntValue( v2 ) );
 988  
         }
 989  10
         return newInteger( type, longValue( v1 ) ^ longValue( v2 ) );
 990  
     }
 991  
 
 992  
     public static Object binaryAnd( Object v1, Object v2 )
 993  
     {
 994  9
         int type = getNumericType( v1, v2 );
 995  9
         if ( type == BIGINT || type == BIGDEC )
 996  
         {
 997  4
             return bigIntValue( v1 ).and( bigIntValue( v2 ) );
 998  
         }
 999  5
         return newInteger( type, longValue( v1 ) & longValue( v2 ) );
 1000  
     }
 1001  
 
 1002  
     public static boolean equal( Object v1, Object v2 )
 1003  
     {
 1004  87
         if ( v1 == null )
 1005  
         {
 1006  16
             return v2 == null;
 1007  
         }
 1008  71
         if ( v1 == v2 || isEqual( v1, v2 ) )
 1009  
         {
 1010  28
             return true;
 1011  
         }
 1012  43
         if ( v1 instanceof Number && v2 instanceof Number )
 1013  
         {
 1014  7
             return ( (Number) v1 ).doubleValue() == ( (Number) v2 ).doubleValue();
 1015  
         }
 1016  36
         return false;
 1017  
     }
 1018  
 
 1019  
     public static boolean less( Object v1, Object v2 )
 1020  
     {
 1021  21
         return compareWithConversion( v1, v2 ) < 0;
 1022  
     }
 1023  
 
 1024  
     public static boolean greater( Object v1, Object v2 )
 1025  
     {
 1026  128
         return compareWithConversion( v1, v2 ) > 0;
 1027  
     }
 1028  
 
 1029  
     public static boolean in( Object v1, Object v2 )
 1030  
         throws OgnlException
 1031  
     {
 1032  6
         if ( v2 == null ) // A null collection is always treated as empty
 1033  
         {
 1034  0
             return false;
 1035  
         }
 1036  
 
 1037  6
         ElementsAccessor elementsAccessor = OgnlRuntime.getElementsAccessor( OgnlRuntime.getTargetClass( v2 ) );
 1038  
 
 1039  
         // FIXME O(n) is there a better way?!
 1040  6
         for ( Enumeration<?> e = elementsAccessor.getElements( v2 ); e.hasMoreElements(); )
 1041  
         {
 1042  17
             Object o = e.nextElement();
 1043  
 
 1044  17
             if ( equal( v1, o ) )
 1045  
             {
 1046  4
                 return true;
 1047  
             }
 1048  13
         }
 1049  
 
 1050  2
         return false;
 1051  
     }
 1052  
 
 1053  
     public static Object shiftLeft( Object v1, Object v2 )
 1054  
     {
 1055  3
         int type = getNumericType( v1 );
 1056  3
         if ( type == BIGINT || type == BIGDEC )
 1057  
         {
 1058  1
             return bigIntValue( v1 ).shiftLeft( (int) longValue( v2 ) );
 1059  
         }
 1060  2
         return newInteger( type, longValue( v1 ) << (int) longValue( v2 ) );
 1061  
     }
 1062  
 
 1063  
     public static Object shiftRight( Object v1, Object v2 )
 1064  
     {
 1065  5
         int type = getNumericType( v1 );
 1066  5
         if ( type == BIGINT || type == BIGDEC )
 1067  
         {
 1068  2
             return bigIntValue( v1 ).shiftRight( (int) longValue( v2 ) );
 1069  
         }
 1070  3
         return newInteger( type, longValue( v1 ) >> (int) longValue( v2 ) );
 1071  
     }
 1072  
 
 1073  
     public static Object unsignedShiftRight( Object v1, Object v2 )
 1074  
     {
 1075  5
         int type = getNumericType( v1 );
 1076  5
         if ( type == BIGINT || type == BIGDEC )
 1077  
         {
 1078  1
             return bigIntValue( v1 ).shiftRight( (int) longValue( v2 ) );
 1079  
         }
 1080  4
         if ( type <= INT )
 1081  
         {
 1082  3
             return newInteger( INT, ( (int) longValue( v1 ) ) >>> (int) longValue( v2 ) );
 1083  
         }
 1084  1
         return newInteger( type, longValue( v1 ) >>> (int) longValue( v2 ) );
 1085  
     }
 1086  
 
 1087  
     public static Object add( Object v1, Object v2 )
 1088  
     {
 1089  138
         int type = getNumericType( v1, v2, true );
 1090  138
         switch ( type )
 1091  
         {
 1092  
             case BIGINT:
 1093  34
                 return bigIntValue( v1 ).add( bigIntValue( v2 ) );
 1094  
             case BIGDEC:
 1095  4
                 return bigDecValue( v1 ).add( bigDecValue( v2 ) );
 1096  
             case FLOAT:
 1097  
             case DOUBLE:
 1098  4
                 return newReal( type, doubleValue( v1 ) + doubleValue( v2 ) );
 1099  
             case NONNUMERIC:
 1100  57
                 int t1 = getNumericType( v1 ),
 1101  57
                 t2 = getNumericType( v2 );
 1102  
 
 1103  57
                 if ( ( ( t1 != NONNUMERIC ) && ( v2 == null ) ) || ( ( t2 != NONNUMERIC ) && ( v1 == null ) ) )
 1104  
                 {
 1105  1
                     throw new NullPointerException( "Can't add values " + v1 + " , " + v2 );
 1106  
                 }
 1107  
 
 1108  56
                 return stringValue( v1 ) + stringValue( v2 );
 1109  
             default:
 1110  39
                 return newInteger( type, longValue( v1 ) + longValue( v2 ) );
 1111  
         }
 1112  
     }
 1113  
 
 1114  
     public static Object subtract( Object v1, Object v2 )
 1115  
     {
 1116  109
         int type = getNumericType( v1, v2 );
 1117  109
         switch ( type )
 1118  
         {
 1119  
             case BIGINT:
 1120  30
                 return bigIntValue( v1 ).subtract( bigIntValue( v2 ) );
 1121  
             case BIGDEC:
 1122  1
                 return bigDecValue( v1 ).subtract( bigDecValue( v2 ) );
 1123  
             case FLOAT:
 1124  
             case DOUBLE:
 1125  2
                 return newReal( type, doubleValue( v1 ) - doubleValue( v2 ) );
 1126  
             default:
 1127  76
                 return newInteger( type, longValue( v1 ) - longValue( v2 ) );
 1128  
         }
 1129  
     }
 1130  
 
 1131  
     public static Object multiply( Object v1, Object v2 )
 1132  
     {
 1133  139
         int type = getNumericType( v1, v2 );
 1134  139
         switch ( type )
 1135  
         {
 1136  
             case BIGINT:
 1137  64
                 return bigIntValue( v1 ).multiply( bigIntValue( v2 ) );
 1138  
             case BIGDEC:
 1139  5
                 return bigDecValue( v1 ).multiply( bigDecValue( v2 ) );
 1140  
             case FLOAT:
 1141  
             case DOUBLE:
 1142  2
                 return newReal( type, doubleValue( v1 ) * doubleValue( v2 ) );
 1143  
             default:
 1144  68
                 return newInteger( type, longValue( v1 ) * longValue( v2 ) );
 1145  
         }
 1146  
     }
 1147  
 
 1148  
     public static Object divide( Object v1, Object v2 )
 1149  
     {
 1150  9
         int type = getNumericType( v1, v2 );
 1151  9
         switch ( type )
 1152  
         {
 1153  
             case BIGINT:
 1154  1
                 return bigIntValue( v1 ).divide( bigIntValue( v2 ) );
 1155  
             case BIGDEC:
 1156  2
                 return bigDecValue( v1 ).divide( bigDecValue( v2 ), BigDecimal.ROUND_HALF_EVEN );
 1157  
             case FLOAT:
 1158  
             case DOUBLE:
 1159  2
                 return newReal( type, doubleValue( v1 ) / doubleValue( v2 ) );
 1160  
             default:
 1161  4
                 return newInteger( type, longValue( v1 ) / longValue( v2 ) );
 1162  
         }
 1163  
     }
 1164  
 
 1165  
     public static Object remainder( Object v1, Object v2 )
 1166  
     {
 1167  22
         int type = getNumericType( v1, v2 );
 1168  22
         switch ( type )
 1169  
         {
 1170  
             case BIGDEC:
 1171  
             case BIGINT:
 1172  1
                 return bigIntValue( v1 ).remainder( bigIntValue( v2 ) );
 1173  
             default:
 1174  21
                 return newInteger( type, longValue( v1 ) % longValue( v2 ) );
 1175  
         }
 1176  
     }
 1177  
 
 1178  
     public static Object negate( Object value )
 1179  
     {
 1180  4
         int type = getNumericType( value );
 1181  4
         switch ( type )
 1182  
         {
 1183  
             case BIGINT:
 1184  1
                 return bigIntValue( value ).negate();
 1185  
             case BIGDEC:
 1186  0
                 return bigDecValue( value ).negate();
 1187  
             case FLOAT:
 1188  
             case DOUBLE:
 1189  0
                 return newReal( type, -doubleValue( value ) );
 1190  
             default:
 1191  3
                 return newInteger( type, -longValue( value ) );
 1192  
         }
 1193  
     }
 1194  
 
 1195  
     public static Object bitNegate( Object value )
 1196  
     {
 1197  0
         int type = getNumericType( value );
 1198  0
         switch ( type )
 1199  
         {
 1200  
             case BIGDEC:
 1201  
             case BIGINT:
 1202  0
                 return bigIntValue( value ).not();
 1203  
             default:
 1204  0
                 return newInteger( type, ~longValue( value ) );
 1205  
         }
 1206  
     }
 1207  
 
 1208  
     public static String getEscapeString( String value )
 1209  
     {
 1210  159
         StringBuilder result = new StringBuilder();
 1211  
 
 1212  159
         int length = value.length();
 1213  1335
         for ( int i = 0; i < length; i++ )
 1214  
         {
 1215  1176
             result.append( getEscapedChar( value.charAt( i ) ) );
 1216  
         }
 1217  159
         return result.toString();
 1218  
     }
 1219  
 
 1220  
     public static String getEscapedChar( char ch )
 1221  
     {
 1222  
         String result;
 1223  
 
 1224  1194
         switch ( ch )
 1225  
         {
 1226  
             case '\b':
 1227  1
                 result = "\b";
 1228  1
                 break;
 1229  
             case '\t':
 1230  1
                 result = "\\t";
 1231  1
                 break;
 1232  
             case '\n':
 1233  2
                 result = "\\n";
 1234  2
                 break;
 1235  
             case '\f':
 1236  1
                 result = "\\f";
 1237  1
                 break;
 1238  
             case '\r':
 1239  1
                 result = "\\r";
 1240  1
                 break;
 1241  
             case '\"':
 1242  4
                 result = "\\\"";
 1243  4
                 break;
 1244  
             case '\'':
 1245  2
                 result = "\\\'";
 1246  2
                 break;
 1247  
             case '\\':
 1248  1
                 result = "\\\\";
 1249  1
                 break;
 1250  
             default:
 1251  1181
                 if ( Character.isISOControl( ch ) )
 1252  
                 {
 1253  
 
 1254  0
                     String hc = Integer.toString( (int) ch, 16 );
 1255  0
                     int hcl = hc.length();
 1256  
 
 1257  0
                     result = "\\u";
 1258  0
                     if ( hcl < 4 )
 1259  
                     {
 1260  0
                         if ( hcl == 3 )
 1261  
                         {
 1262  0
                             result = result + "0";
 1263  
                         }
 1264  
                         else
 1265  
                         {
 1266  0
                             if ( hcl == 2 )
 1267  
                             {
 1268  0
                                 result = result + "00";
 1269  
                             }
 1270  
                             else
 1271  
                             {
 1272  0
                                 result = result + "000";
 1273  
                             }
 1274  
                         }
 1275  
                     }
 1276  
 
 1277  0
                     result = result + hc;
 1278  0
                 }
 1279  
                 else
 1280  
                 {
 1281  1181
                     result = ch + "";
 1282  
                 }
 1283  
                 break;
 1284  
         }
 1285  1194
         return result;
 1286  
     }
 1287  
 
 1288  
     public static Object returnValue( Object ignore, Object returnValue )
 1289  
     {
 1290  1
         return returnValue;
 1291  
     }
 1292  
 
 1293  
     /**
 1294  
      * Utility method that converts incoming exceptions to {@link RuntimeException} instances - or casts them if they
 1295  
      * already are.
 1296  
      * 
 1297  
      * @param t The exception to cast.
 1298  
      * @return The exception cast to a {@link RuntimeException}.
 1299  
      */
 1300  
     public static RuntimeException castToRuntime( Throwable t )
 1301  
     {
 1302  285
         if ( RuntimeException.class.isInstance( t ) )
 1303  
         {
 1304  279
             return (RuntimeException) t;
 1305  
         }
 1306  
 
 1307  6
         if ( OgnlException.class.isInstance( t ) )
 1308  
         {
 1309  6
             throw new UnsupportedCompilationException( "Error evluating expression: " + t.getMessage(), t );
 1310  
         }
 1311  
 
 1312  0
         return new RuntimeException( t );
 1313  
     }
 1314  
 }