Package org.springframework.expression.spel

Source Code of org.springframework.expression.spel.SpelCompilationCoverageTests$SomeCompareMethod2

/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.expression.spel;

import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;

import org.junit.Test;

import org.springframework.asm.MethodVisitor;
import org.springframework.expression.AccessException;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ast.CompoundExpression;
import org.springframework.expression.spel.ast.OpLT;
import org.springframework.expression.spel.ast.SpelNodeImpl;
import org.springframework.expression.spel.ast.Ternary;
import org.springframework.expression.spel.standard.SpelCompiler;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.testdata.PersonInOtherPackage;

import static org.junit.Assert.*;

/**
* Checks the behaviour of the SpelCompiler. This should cover compilation all compiled node types.
*
* @author Andy Clement
* @since 4.1
*/
public class SpelCompilationCoverageTests extends AbstractExpressionTests {
 
  private Expression expression;
  private SpelNodeImpl ast;
 
  /*
   * Further TODOs for compilation:
   *
   * - OpMinus with a single literal operand could be treated as a negative literal. Will save a
   *   pointless loading of 0 and then a subtract instruction in code gen.
   * - allow other accessors/resolvers to participate in compilation and create their own code
   * - A TypeReference followed by (what ends up as) a static method invocation can really skip
   *   code gen for the TypeReference since once that is used to locate the method it is not
   *   used again.
   * - The opEq implementation is quite basic. It will compare numbers of the same type (allowing
   *   them to be their boxed or unboxed variants) or compare object references. It does not
   *   compile expressions where numbers are of different types or when objects implement
   *   Comparable. 
     *
   * Compiled nodes:
   *
   * TypeReference
   * OperatorInstanceOf
   * StringLiteral
   * NullLiteral
   * RealLiteral
   * IntLiteral
   * LongLiteral
   * BooleanLiteral
   * FloatLiteral
   * OpOr
   * OpAnd
   * OperatorNot
   * Ternary
   * Elvis
   * VariableReference
   * OpLt
   * OpLe
   * OpGt
   * OpGe
   * OpEq
   * OpNe
   * OpPlus
   * OpMinus
   * OpMultiply
   * OpDivide
   * MethodReference
   * PropertyOrFieldReference
   * Indexer
   * CompoundExpression
   * ConstructorReference
   * FunctionReference
   * InlineList
   * OpModulus
   *
   * Not yet compiled (some may never need to be):
   * Assign
   * BeanReference
   * Identifier
   * OpDec
   * OpBetween
   * OpMatches
   * OpPower
   * OpInc
   * Projection
   * QualifiedId
   * Selection
   */
 
  @Test
  public void typeReference() throws Exception {
    expression = parse("T(String)");
    assertEquals(String.class,expression.getValue());
    assertCanCompile(expression);
    assertEquals(String.class,expression.getValue());
    
    expression = parse("T(java.io.IOException)");
    assertEquals(IOException.class,expression.getValue());
    assertCanCompile(expression);
    assertEquals(IOException.class,expression.getValue());

    expression = parse("T(java.io.IOException[])");
    assertEquals(IOException[].class,expression.getValue());
    assertCanCompile(expression);
    assertEquals(IOException[].class,expression.getValue());

    expression = parse("T(int[][])");
    assertEquals(int[][].class,expression.getValue());
    assertCanCompile(expression);
    assertEquals(int[][].class,expression.getValue());

    expression = parse("T(int)");
    assertEquals(Integer.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Integer.TYPE,expression.getValue());

    expression = parse("T(byte)");
    assertEquals(Byte.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Byte.TYPE,expression.getValue());

    expression = parse("T(char)");
    assertEquals(Character.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Character.TYPE,expression.getValue());

    expression = parse("T(short)");
    assertEquals(Short.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Short.TYPE,expression.getValue());

    expression = parse("T(long)");
    assertEquals(Long.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Long.TYPE,expression.getValue());

    expression = parse("T(float)");
    assertEquals(Float.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Float.TYPE,expression.getValue());

    expression = parse("T(double)");
    assertEquals(Double.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Double.TYPE,expression.getValue());

    expression = parse("T(boolean)");
    assertEquals(Boolean.TYPE,expression.getValue());
    assertCanCompile(expression);
    assertEquals(Boolean.TYPE,expression.getValue());
   
    expression = parse("T(Missing)");
    assertGetValueFail(expression);
    assertCantCompile(expression);
  }

  @SuppressWarnings("unchecked")
  @Test
  public void operatorInstanceOf() throws Exception {
    expression = parse("'xyz' instanceof T(String)");
    assertEquals(true,expression.getValue());
    assertCanCompile(expression);
    assertEquals(true,expression.getValue());

    expression = parse("'xyz' instanceof T(Integer)");
    assertEquals(false,expression.getValue());
    assertCanCompile(expression);
    assertEquals(false,expression.getValue());

    List<String> list = new ArrayList<String>();
    expression = parse("#root instanceof T(java.util.List)");
    assertEquals(true,expression.getValue(list));
    assertCanCompile(expression);
    assertEquals(true,expression.getValue(list));

    List<String>[] arrayOfLists = new List[]{new ArrayList<String>()};
    expression = parse("#root instanceof T(java.util.List[])");
    assertEquals(true,expression.getValue(arrayOfLists));
    assertCanCompile(expression);
    assertEquals(true,expression.getValue(arrayOfLists));
   
    int[] intArray = new int[]{1,2,3};
    expression = parse("#root instanceof T(int[])");
    assertEquals(true,expression.getValue(intArray));
    assertCanCompile(expression);
    assertEquals(true,expression.getValue(intArray));

    String root = null;
    expression = parse("#root instanceof T(Integer)");
    assertEquals(false,expression.getValue(root));
    assertCanCompile(expression);
    assertEquals(false,expression.getValue(root));

    // root still null
    expression = parse("#root instanceof T(java.lang.Object)");
    assertEquals(false,expression.getValue(root));
    assertCanCompile(expression);
    assertEquals(false,expression.getValue(root));

    root = "howdy!";
    expression = parse("#root instanceof T(java.lang.Object)");
    assertEquals(true,expression.getValue(root));
    assertCanCompile(expression);
    assertEquals(true,expression.getValue(root));
  }

  @Test
  public void stringLiteral() throws Exception {
    expression = parser.parseExpression("'abcde'");   
    assertEquals("abcde",expression.getValue(new TestClass1(),String.class));
    assertCanCompile(expression);
    String resultC = expression.getValue(new TestClass1(),String.class);
    assertEquals("abcde",resultC);
    assertEquals("abcde",expression.getValue(String.class));
    assertEquals("abcde",expression.getValue());
    assertEquals("abcde",expression.getValue(new StandardEvaluationContext()));
    expression = parser.parseExpression("\"abcde\"");
    assertCanCompile(expression);
    assertEquals("abcde",expression.getValue(String.class));
  }
 
  @Test
  public void nullLiteral() throws Exception {
    expression = parser.parseExpression("null");
    Object resultI = expression.getValue(new TestClass1(),Object.class);
    assertCanCompile(expression);
    Object resultC = expression.getValue(new TestClass1(),Object.class);
    assertEquals(null,resultI);
    assertEquals(null,resultC);
    assertEquals(null,resultC);
  }
 
  @Test
  public void realLiteral() throws Exception {
    expression = parser.parseExpression("3.4d");
    double resultI = expression.getValue(new TestClass1(),Double.TYPE);
    assertCanCompile(expression);
    double resultC = expression.getValue(new TestClass1(),Double.TYPE);
    assertEquals(3.4d,resultI,0.1d);
    assertEquals(3.4d,resultC,0.1d);

    assertEquals(3.4d,expression.getValue());
  }
 
  @SuppressWarnings("rawtypes")
  @Test
  public void inlineList() throws Exception {
    expression = parser.parseExpression("'abcde'.substring({1,3,4}[0])");
    Object o = expression.getValue();
    assertEquals("bcde",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("bcde", o);
   
    expression = parser.parseExpression("{'abc','def'}");
    List<?> l = (List) expression.getValue();
    assertEquals("[abc, def]", l.toString());
    assertCanCompile(expression);
    l = (List) expression.getValue();
    assertEquals("[abc, def]", l.toString());
   
    expression = parser.parseExpression("{'abc','def'}[0]");
    o = expression.getValue();
    assertEquals("abc",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("abc", o);
   
    expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0])");
    o = expression.getValue();
    assertEquals("bcde",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("bcde", o);

    expression = parser.parseExpression("{'abcde','ijklm'}[0].substring({1,3,4}[0],{1,3,4}[1])");
    o = expression.getValue();
    assertEquals("bc",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("bc", o);
  }

  @SuppressWarnings("rawtypes")
  @Test
  public void nestedInlineLists() throws Exception {
    Object o = null;
   
    expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}");
    o = expression.getValue();
    assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString());
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o.toString());

    expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}.toString()");
    o = expression.getValue();
    assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("[[1, 2, 3], [4, 5, 6], [7, 8, 9]]",o);

    expression = parser.parseExpression("{{1,2,3},{4,5,6},{7,8,9}}[1][0]");
    o = expression.getValue();
    assertEquals(4,o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals(4,o);
   
    expression = parser.parseExpression("{{1,2,3},'abc',{7,8,9}}[1]");
    o = expression.getValue();
    assertEquals("abc",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("abc",o);

    expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[0][1])");
    o = expression.getValue();
    assertEquals("de",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("de", o);

    expression = parser.parseExpression("'abcde'.substring({{1,3},1,3,4}[1])");
    o = expression.getValue();
    assertEquals("bcde",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("bcde", o);
   
    expression = parser.parseExpression("{'abc',{'def','ghi'}}");
    List<?> l = (List) expression.getValue();
    assertEquals("[abc, [def, ghi]]", l.toString());
    assertCanCompile(expression);
    l = (List) expression.getValue();
    assertEquals("[abc, [def, ghi]]", l.toString());

    expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[0].substring({1,3,4}[0])");
    o = expression.getValue();
    assertEquals("bcde",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("bcde", o);
   
    expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][0].substring({1,3,4}[0])");
    o = expression.getValue();
    assertEquals("jklm",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("jklm", o);

    expression = parser.parseExpression("{'abcde',{'ijklm','nopqr'}}[1][1].substring({1,3,4}[0],{1,3,4}[1])");
    o = expression.getValue();
    assertEquals("op",o);
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals("op", o);
  }

  @Test
  public void intLiteral() throws Exception {
    expression = parser.parseExpression("42");
    int resultI = expression.getValue(new TestClass1(),Integer.TYPE);
    assertCanCompile(expression);
    int resultC = expression.getValue(new TestClass1(),Integer.TYPE);
    assertEquals(42,resultI);
    assertEquals(42,resultC);

    expression = parser.parseExpression("T(Integer).valueOf(42)");
    expression.getValue(Integer.class);
    assertCanCompile(expression);
    assertEquals(new Integer(42),expression.getValue(null,Integer.class));
   
    // Code gen is different for -1 .. 6 because there are bytecode instructions specifically for those
    // values
   
    // Not an int literal but an opminus with one operand:
//    expression = parser.parseExpression("-1");
//    assertCanCompile(expression);
//    assertEquals(-1,expression.getValue());
    expression = parser.parseExpression("0");
    assertCanCompile(expression);
    assertEquals(0,expression.getValue());
    expression = parser.parseExpression("2");
    assertCanCompile(expression);
    assertEquals(2,expression.getValue());
    expression = parser.parseExpression("7");
    assertCanCompile(expression);
    assertEquals(7,expression.getValue());
  }
 
  @Test
  public void longLiteral() throws Exception {
    expression = parser.parseExpression("99L");
    long resultI = expression.getValue(new TestClass1(),Long.TYPE);
    assertCanCompile(expression);
    long resultC = expression.getValue(new TestClass1(),Long.TYPE);
    assertEquals(99L,resultI);
    assertEquals(99L,resultC);   
  }
   
  @Test
  public void booleanLiteral() throws Exception {
    expression = parser.parseExpression("true");
    boolean resultI = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultI);
    assertTrue(SpelCompiler.compile(expression));
    boolean resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultC);
   
    expression = parser.parseExpression("false");
    resultI = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultI);
    assertTrue(SpelCompiler.compile(expression));
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultC);
  }
 
  @Test
  public void floatLiteral() throws Exception {
    expression = parser.parseExpression("3.4f");
    float resultI = expression.getValue(new TestClass1(),Float.TYPE);
    assertCanCompile(expression);
    float resultC = expression.getValue(new TestClass1(),Float.TYPE);
    assertEquals(3.4f,resultI,0.1f);
    assertEquals(3.4f,resultC,0.1f);

    assertEquals(3.4f,expression.getValue());
  }
 
  @Test
  public void opOr() throws Exception {
    Expression expression = parser.parseExpression("false or false");
    boolean resultI = expression.getValue(1,Boolean.TYPE);
    SpelCompiler.compile(expression);
    boolean resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultI);
    assertEquals(false,resultC);
   
    expression = parser.parseExpression("false or true");
    resultI = expression.getValue(1,Boolean.TYPE);
    assertCanCompile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultI);
    assertEquals(true,resultC);
   
    expression = parser.parseExpression("true or false");
    resultI = expression.getValue(1,Boolean.TYPE);
    assertCanCompile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultI);
    assertEquals(true,resultC);
   
    expression = parser.parseExpression("true or true");
    resultI = expression.getValue(1,Boolean.TYPE);
    assertCanCompile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultI);
    assertEquals(true,resultC);

    TestClass4 tc = new TestClass4();
    expression = parser.parseExpression("getfalse() or gettrue()");
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCanCompile(expression);
    resultC = expression.getValue(tc,Boolean.TYPE);
    assertEquals(true,resultI);
    assertEquals(true,resultC);

    // Can't compile this as we aren't going down the getfalse() branch in our evaluation
    expression = parser.parseExpression("gettrue() or getfalse()");
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCantCompile(expression);
   
    expression = parser.parseExpression("getA() or getB()");
    tc.a = true;
    tc.b = true;
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCantCompile(expression); // Haven't yet been into second branch
    tc.a = false;
    tc.b = true;
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCanCompile(expression); // Now been down both
    assertTrue(resultI);
   
    boolean b = false;
    expression = parse("#root or #root");
    Object resultI2 = expression.getValue(b);
    assertCanCompile(expression);
    assertFalse((Boolean)resultI2);
    assertFalse((Boolean)expression.getValue(b));
  }
 
  @Test
  public void opAnd() throws Exception {
    Expression expression = parser.parseExpression("false and false");
    boolean resultI = expression.getValue(1,Boolean.TYPE);
    SpelCompiler.compile(expression);
    boolean resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultI);
    assertEquals(false,resultC);

    expression = parser.parseExpression("false and true");
    resultI = expression.getValue(1,Boolean.TYPE);
    SpelCompiler.compile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultI);
    assertEquals(false,resultC);
   
    expression = parser.parseExpression("true and false");
    resultI = expression.getValue(1,Boolean.TYPE);
    SpelCompiler.compile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(false,resultI);
    assertEquals(false,resultC);

    expression = parser.parseExpression("true and true");
    resultI = expression.getValue(1,Boolean.TYPE);
    SpelCompiler.compile(expression);
    resultC = expression.getValue(1,Boolean.TYPE);
    assertEquals(true,resultI);
    assertEquals(true,resultC);
   
    TestClass4 tc = new TestClass4();

    // Can't compile this as we aren't going down the gettrue() branch in our evaluation
    expression = parser.parseExpression("getfalse() and gettrue()");
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCantCompile(expression);
   
    expression = parser.parseExpression("getA() and getB()");
    tc.a = false;
    tc.b = false;
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCantCompile(expression); // Haven't yet been into second branch
    tc.a = true;
    tc.b = false;
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertCanCompile(expression); // Now been down both
    assertFalse(resultI);
    tc.a = true;
    tc.b = true;
    resultI = expression.getValue(tc,Boolean.TYPE);
    assertTrue(resultI);
   
    boolean b = true;
    expression = parse("#root and #root");
    Object resultI2 = expression.getValue(b);
    assertCanCompile(expression);
    assertTrue((Boolean)resultI2);
    assertTrue((Boolean)expression.getValue(b));
  }
 
  @Test
  public void operatorNot() throws Exception {
    expression = parse("!true");
    assertEquals(false,expression.getValue());
    assertCanCompile(expression);
    assertEquals(false,expression.getValue());

    expression = parse("!false");
    assertEquals(true,expression.getValue());
    assertCanCompile(expression);
    assertEquals(true,expression.getValue());

    boolean b = true;
    expression = parse("!#root");
    assertEquals(false,expression.getValue(b));
    assertCanCompile(expression);
    assertEquals(false,expression.getValue(b));

    b = false;
    expression = parse("!#root");
    assertEquals(true,expression.getValue(b));
    assertCanCompile(expression);
    assertEquals(true,expression.getValue(b));
  }

  @Test
  public void ternary() throws Exception {
    Expression expression = parser.parseExpression("true?'a':'b'");
    String resultI = expression.getValue(String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(String.class);
    assertEquals("a",resultI);
    assertEquals("a",resultC);
   
    expression = parser.parseExpression("false?'a':'b'");
    resultI = expression.getValue(String.class);
    assertCanCompile(expression);
    resultC = expression.getValue(String.class);
    assertEquals("b",resultI);
    assertEquals("b",resultC);

    expression = parser.parseExpression("false?1:'b'");
    // All literals so we can do this straight away
    assertCanCompile(expression);
    assertEquals("b",expression.getValue());

    boolean root = true;
    expression = parser.parseExpression("(#root and true)?T(Integer).valueOf(1):T(Long).valueOf(3L)");
    assertEquals(1,expression.getValue(root));
    assertCantCompile(expression); // Have not gone down false branch
    root = false;
    assertEquals(3L,expression.getValue(root));
    assertCanCompile(expression);
    assertEquals(3L,expression.getValue(root));
    root = true;
    assertEquals(1,expression.getValue(root));   
  }
 
  @Test
  public void ternaryWithBooleanReturn() { // SPR-12271
    expression = parser.parseExpression("T(Boolean).TRUE?'abc':'def'");
    assertEquals("abc",expression.getValue());
    assertCanCompile(expression);
    assertEquals("abc",expression.getValue());

    expression = parser.parseExpression("T(Boolean).FALSE?'abc':'def'");
    assertEquals("def",expression.getValue());
    assertCanCompile(expression);
    assertEquals("def",expression.getValue());
  }
 
  @Test
  public void elvis() throws Exception {
    Expression expression = parser.parseExpression("'a'?:'b'");
    String resultI = expression.getValue(String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(String.class);
    assertEquals("a",resultI);
    assertEquals("a",resultC);
   
    expression = parser.parseExpression("null?:'a'");
    resultI = expression.getValue(String.class);
    assertCanCompile(expression);
    resultC = expression.getValue(String.class);
    assertEquals("a",resultI);
    assertEquals("a",resultC);
   
    String s = "abc";
    expression = parser.parseExpression("#root?:'b'");
    assertCantCompile(expression);
    resultI = expression.getValue(s,String.class);
    assertEquals("abc",resultI);
    assertCanCompile(expression);
  }
 
  @Test
  public void variableReference_root() throws Exception {
    String s = "hello";
    Expression expression = parser.parseExpression("#root");
    String resultI = expression.getValue(s,String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(s,String.class);
    assertEquals(s,resultI);
    assertEquals(s,resultC);   

    expression = parser.parseExpression("#root");
    int i = (Integer)expression.getValue(42);
    assertEquals(42,i);
    assertCanCompile(expression);
    i = (Integer)expression.getValue(42);
    assertEquals(42,i);
  }
 
  public static String concat(String a, String b) {
    return a+b;
  }
 
  public static String join(String...strings) {
    StringBuilder buf = new StringBuilder();
    for (String string: strings) {
      buf.append(string);
    }
    return buf.toString();
  }
 
  @Test
  public void compiledExpressionShouldWorkWhenUsingCustomFunctionWithVarargs() throws Exception {
    StandardEvaluationContext context = null;

    // Here the target method takes Object... and we are passing a string
    expression = parser.parseExpression("#doFormat('hey %s', 'there')");
    context = new StandardEvaluationContext();
    context.registerFunction("doFormat",
        DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
            Object[].class));
    ((SpelExpression) expression).setEvaluationContext(context);

    assertEquals("hey there", expression.getValue(String.class));
    assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("hey there", expression.getValue(String.class));

    expression = parser.parseExpression("#doFormat([0], 'there')");
    context = new StandardEvaluationContext(new Object[] { "hey %s" });
    context.registerFunction("doFormat",
        DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
            Object[].class));
    ((SpelExpression) expression).setEvaluationContext(context);

    assertEquals("hey there", expression.getValue(String.class));
    assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("hey there", expression.getValue(String.class));

    expression = parser.parseExpression("#doFormat([0], #arg)");
    context = new StandardEvaluationContext(new Object[] { "hey %s" });
    context.registerFunction("doFormat",
        DelegatingStringFormat.class.getDeclaredMethod("format", String.class,
            Object[].class));
    context.setVariable("arg", "there");
    ((SpelExpression) expression).setEvaluationContext(context);

    assertEquals("hey there", expression.getValue(String.class));
    assertTrue(((SpelNodeImpl) ((SpelExpression) expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("hey there", expression.getValue(String.class));
  }
  
  @Test
  public void functionReference() throws Exception {
    EvaluationContext ctx = new StandardEvaluationContext();
    Method m = this.getClass().getDeclaredMethod("concat",String.class,String.class);
    ctx.setVariable("concat",m);
   
    expression = parser.parseExpression("#concat('a','b')");
    assertEquals("ab",expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals("ab",expression.getValue(ctx));
   
    expression = parser.parseExpression("#concat(#concat('a','b'),'c').charAt(1)");
    assertEquals('b',expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals('b',expression.getValue(ctx));
   
    expression = parser.parseExpression("#concat(#a,#b)");
    ctx.setVariable("a", "foo");
    ctx.setVariable("b", "bar");
    assertEquals("foobar",expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals("foobar",expression.getValue(ctx));
    ctx.setVariable("b", "boo");
    assertEquals("fooboo",expression.getValue(ctx));
   
    m = Math.class.getDeclaredMethod("pow",Double.TYPE,Double.TYPE);
    ctx.setVariable("kapow",m);
    expression = parser.parseExpression("#kapow(2.0d,2.0d)");
    assertEquals("4.0",expression.getValue(ctx).toString());
    assertCanCompile(expression);
    assertEquals("4.0",expression.getValue(ctx).toString());
  }

  // Confirms visibility of what is being called.
  @Test
  public void functionReferenceVisibility_SPR12359() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext(new  Object[] { "1" });
    context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod(
        "compare", Object.class, Object.class));
    context.setVariable("arg", "2");
    // type nor method are public
    expression = parser.parseExpression("#doCompare([0],#arg)");
    assertEquals("-1",expression.getValue(context, Integer.class).toString());
    assertCantCompile(expression);
   
    // type not public but method is
    context = new StandardEvaluationContext(new  Object[] { "1" });
    context.registerFunction("doCompare", SomeCompareMethod.class.getDeclaredMethod(
        "compare2", Object.class, Object.class));
    context.setVariable("arg", "2");
    expression = parser.parseExpression("#doCompare([0],#arg)");
    assertEquals("-1",expression.getValue(context, Integer.class).toString());
    assertCantCompile(expression);
  }
 
  @Test
  public void functionReferenceNonCompilableArguments_SPR12359() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext(new  Object[] { "1" });
    context.registerFunction("negate", SomeCompareMethod2.class.getDeclaredMethod(
        "negate", Integer.TYPE));
    context.setVariable("arg", "2");
    int[] ints = new int[]{1,2,3};
    context.setVariable("ints",ints);

    expression = parser.parseExpression("#negate(#ints.?[#this<2][0])");
    assertEquals("-1",expression.getValue(context, Integer.class).toString());
    // Selection isn't compilable.
    assertFalse(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
  }
 
  @Test 
  public void functionReferenceVarargs_SPR12359() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.registerFunction("append",
        SomeCompareMethod2.class.getDeclaredMethod("append", String[].class));
    context.registerFunction("append2",
        SomeCompareMethod2.class.getDeclaredMethod("append2", Object[].class));
    context.registerFunction("append3",
        SomeCompareMethod2.class.getDeclaredMethod("append3", String[].class));
    context.registerFunction("append4",
        SomeCompareMethod2.class.getDeclaredMethod("append4", String.class, String[].class));
    context.registerFunction("appendChar",
        SomeCompareMethod2.class.getDeclaredMethod("appendChar", char[].class));
    context.registerFunction("sum",
        SomeCompareMethod2.class.getDeclaredMethod("sum", int[].class));
    context.registerFunction("sumDouble",
        SomeCompareMethod2.class.getDeclaredMethod("sumDouble", double[].class));
    context.registerFunction("sumFloat",
        SomeCompareMethod2.class.getDeclaredMethod("sumFloat", float[].class));
    context.setVariable("stringArray", new String[]{"x","y","z"});
    context.setVariable("intArray", new int[]{5,6,9});
    context.setVariable("doubleArray", new double[]{5.0d,6.0d,9.0d});
    context.setVariable("floatArray", new float[]{5.0f,6.0f,9.0f});

    expression = parser.parseExpression("#append('a','b','c')");
    assertEquals("abc",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("abc",expression.getValue(context).toString());

    expression = parser.parseExpression("#append('a')");
    assertEquals("a",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("a",expression.getValue(context).toString());

    expression = parser.parseExpression("#append()");
    assertEquals("",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("",expression.getValue(context).toString());
   
    expression = parser.parseExpression("#append(#stringArray)");
    assertEquals("xyz",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("xyz",expression.getValue(context).toString());
   
    // This is a methodreference invocation, to compare with functionreference
    expression = parser.parseExpression("append(#stringArray)");
    assertEquals("xyz",expression.getValue(context,new SomeCompareMethod2()).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("xyz",expression.getValue(context,new SomeCompareMethod2()).toString());
   
    expression = parser.parseExpression("#append2('a','b','c')");
    assertEquals("abc",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("abc",expression.getValue(context).toString());

    expression = parser.parseExpression("append2('a','b')");
    assertEquals("ab",expression.getValue(context, new SomeCompareMethod2()).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("ab",expression.getValue(context, new SomeCompareMethod2()).toString());

    expression = parser.parseExpression("#append2('a','b')");
    assertEquals("ab",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("ab",expression.getValue(context).toString());

    expression = parser.parseExpression("#append2()");
    assertEquals("",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("",expression.getValue(context).toString());
   
    expression = parser.parseExpression("#append3(#stringArray)");
    assertEquals("xyz",expression.getValue(context, new SomeCompareMethod2()).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("xyz",expression.getValue(context, new SomeCompareMethod2()).toString());

    // TODO fails due to conversionservice handling of String[] to Object...
//    expression = parser.parseExpression("#append2(#stringArray)");
//    assertEquals("xyz",expression.getValue(context).toString());
//    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
//    assertCanCompile(expression);
//    assertEquals("xyz",expression.getValue(context).toString());
   
    expression = parser.parseExpression("#sum(1,2,3)");
    assertEquals(6,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(6,expression.getValue(context));

    expression = parser.parseExpression("#sum(2)");
    assertEquals(2,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(context));

    expression = parser.parseExpression("#sum()");
    assertEquals(0,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(0,expression.getValue(context));
   
    expression = parser.parseExpression("#sum(#intArray)");
    assertEquals(20,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(20,expression.getValue(context));
   
    expression = parser.parseExpression("#sumDouble(1.0d,2.0d,3.0d)");
    assertEquals(6,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(6,expression.getValue(context));

    expression = parser.parseExpression("#sumDouble(2.0d)");
    assertEquals(2,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(context));

    expression = parser.parseExpression("#sumDouble()");
    assertEquals(0,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(0,expression.getValue(context));
   
    expression = parser.parseExpression("#sumDouble(#doubleArray)");
    assertEquals(20,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(20,expression.getValue(context));

    expression = parser.parseExpression("#sumFloat(1.0f,2.0f,3.0f)");
    assertEquals(6,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(6,expression.getValue(context));

    expression = parser.parseExpression("#sumFloat(2.0f)");
    assertEquals(2,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(context));

    expression = parser.parseExpression("#sumFloat()");
    assertEquals(0,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(0,expression.getValue(context));
   
    expression = parser.parseExpression("#sumFloat(#floatArray)");
    assertEquals(20,expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals(20,expression.getValue(context));
   
   
    expression = parser.parseExpression("#appendChar('abc'.charAt(0),'abc'.charAt(1))");
    assertEquals("ab",expression.getValue(context));
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("ab",expression.getValue(context));
   
   
    expression = parser.parseExpression("#append4('a','b','c')");
    assertEquals("a::bc",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("a::bc",expression.getValue(context).toString());

    expression = parser.parseExpression("#append4('a','b')");
    assertEquals("a::b",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("a::b",expression.getValue(context).toString());

    expression = parser.parseExpression("#append4('a')");
    assertEquals("a::",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("a::",expression.getValue(context).toString());
   
    expression = parser.parseExpression("#append4('a',#stringArray)");
    assertEquals("a::xyz",expression.getValue(context).toString());
    assertTrue(((SpelNodeImpl)((SpelExpression)expression).getAST()).isCompilable());
    assertCanCompile(expression);
    assertEquals("a::xyz",expression.getValue(context).toString());
  }
 
  @Test
  public void functionReferenceVarargs() throws Exception {
    EvaluationContext ctx = new StandardEvaluationContext();
    Method m = this.getClass().getDeclaredMethod("join", String[].class);
    ctx.setVariable("join", m);
    expression = parser.parseExpression("#join('a','b','c')");
    assertEquals("abc",expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals("abc",expression.getValue(ctx));
  }
 
  @Test
  public void variableReference_userDefined() throws Exception {
    EvaluationContext ctx = new StandardEvaluationContext();
    ctx.setVariable("target", "abc");
    expression = parser.parseExpression("#target");
    assertEquals("abc",expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals("abc",expression.getValue(ctx))
    ctx.setVariable("target", "123");
    assertEquals("123",expression.getValue(ctx))
    ctx.setVariable("target", 42);
    try {
      assertEquals(42,expression.getValue(ctx));
      fail();
    } catch (SpelEvaluationException see) {
      assertTrue(see.getCause() instanceof ClassCastException);
    }
 
    ctx.setVariable("target", "abc");
    expression = parser.parseExpression("#target.charAt(0)");
    assertEquals('a',expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals('a',expression.getValue(ctx))
    ctx.setVariable("target", "1");
    assertEquals('1',expression.getValue(ctx))
    ctx.setVariable("target", 42);
    try {
      assertEquals('4',expression.getValue(ctx));
      fail();
    } catch (SpelEvaluationException see) {
      assertTrue(see.getCause() instanceof ClassCastException);
    }
  }
 
  @Test
  public void opLt() throws Exception {
    expression = parse("3.0d < 4.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3446.0d < 1123.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("3 < 1");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("2 < 4");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("3.0f < 1.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("1.0f < 5.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("30L < 30L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("15L < 20L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    // Differing types of number, not yet supported
    expression = parse("1 < 3.0d");
    assertCantCompile(expression);
   
    expression = parse("T(Integer).valueOf(3) < 4");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("T(Integer).valueOf(3) < T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("5 < T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
  }
 
  @Test
  public void opLe() throws Exception {
    expression = parse("3.0d <= 4.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3446.0d <= 1123.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3446.0d <= 3446.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("3 <= 1");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("2 <= 4");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3 <= 3");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("3.0f <= 1.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("1.0f <= 5.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("2.0f <= 2.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("30L <= 30L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("15L <= 20L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    // Differing types of number, not yet supported
    expression = parse("1 <= 3.0d");
    assertCantCompile(expression);

    expression = parse("T(Integer).valueOf(3) <= 4");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("T(Integer).valueOf(3) <= T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5 <= T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
  }
 
 
  @Test
  public void opGt() throws Exception {
    expression = parse("3.0d > 4.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3446.0d > 1123.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("3 > 1");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("2 > 4");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("3.0f > 1.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("1.0f > 5.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("30L > 30L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("15L > 20L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    // Differing types of number, not yet supported
    expression = parse("1 > 3.0d");
    assertCantCompile(expression);

    expression = parse("T(Integer).valueOf(3) > 4");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Integer).valueOf(3) > T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("5 > T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
  }
 
  @Test
  public void opGe() throws Exception {
    expression = parse("3.0d >= 4.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3446.0d >= 1123.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3446.0d >= 3446.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("3 >= 1");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("2 >= 4");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3 >= 3");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("3.0f >= 1.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("1.0f >= 5.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3.0f >= 3.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("40L >= 30L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("15L >= 20L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("30L >= 30L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    // Differing types of number, not yet supported
    expression = parse("1 >= 3.0d");
    assertCantCompile(expression);

    expression = parse("T(Integer).valueOf(3) >= 4");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Integer).valueOf(3) >= T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5 >= T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
  }

  @Test
  public void opEq() throws Exception {
   
    TestClass7 tc7 = new TestClass7();
    expression = parse("property == 'UK'");
    assertTrue((Boolean)expression.getValue(tc7));
    TestClass7.property = null;
    assertFalse((Boolean)expression.getValue(tc7));
    assertCanCompile(expression);
    TestClass7.reset();
    assertTrue((Boolean)expression.getValue(tc7));
    TestClass7.property = "UK";
    assertTrue((Boolean)expression.getValue(tc7));
    TestClass7.reset();
    TestClass7.property = null;
    assertFalse((Boolean)expression.getValue(tc7));
    expression = parse("property == null");
    assertTrue((Boolean)expression.getValue(tc7));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(tc7));
   
   
    expression = parse("3.0d == 4.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3446.0d == 3446.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("3 == 1");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("3 == 3");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("3.0f == 1.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("2.0f == 2.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("30L == 30L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("15L == 20L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    // number types are not the same
    expression = parse("1 == 3.0d");
    assertCantCompile(expression);
   
    Double d = 3.0d;
    expression = parse("#root==3.0d");
    assertTrue((Boolean)expression.getValue(d));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(d));
   
    Integer i = 3;
    expression = parse("#root==3");
    assertTrue((Boolean)expression.getValue(i));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(i));

    Float f = 3.0f;
    expression = parse("#root==3.0f");
    assertTrue((Boolean)expression.getValue(f));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(f));
   
    long l = 300l;
    expression = parse("#root==300l");
    assertTrue((Boolean)expression.getValue(l));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(l));
   
    boolean b = true;
    expression = parse("#root==true");
    assertTrue((Boolean)expression.getValue(b));
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue(b));

    expression = parse("T(Integer).valueOf(3) == 4");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Integer).valueOf(3) == T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5 == T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("T(Float).valueOf(3.0f) == 4.0f");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Float).valueOf(3.0f) == T(Float).valueOf(3.0f)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5.0f == T(Float).valueOf(3.0f)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Long).valueOf(3L) == 4L");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Long).valueOf(3L) == T(Long).valueOf(3L)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5L == T(Long).valueOf(3L)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue())
   
    expression = parse("T(Double).valueOf(3.0d) == 4.0d");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5.0d == T(Double).valueOf(3.0d)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("false == true");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("T(Boolean).valueOf('true') == true");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("false == T(Boolean).valueOf('false')");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
  }

  @Test
  public void opNe() throws Exception {
    expression = parse("3.0d != 4.0d");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3446.0d != 3446.0d");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("3 != 1");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("3 != 3");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("3.0f != 1.0f");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
    expression = parse("2.0f != 2.0f");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("30L != 30L");
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
    expression = parse("15L != 20L");
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    // not compatible number types
    expression = parse("1 != 3.0d")
    assertCantCompile(expression);

    expression = parse("T(Integer).valueOf(3) != 4");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("T(Integer).valueOf(3) != T(Integer).valueOf(3)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("5 != T(Integer).valueOf(3)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("T(Float).valueOf(3.0f) != 4.0f");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("T(Float).valueOf(3.0f) != T(Float).valueOf(3.0f)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("5.0f != T(Float).valueOf(3.0f)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("T(Long).valueOf(3L) != 4L");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
   
    expression = parse("T(Long).valueOf(3L) != T(Long).valueOf(3L)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("5L != T(Long).valueOf(3L)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue())
   
    expression = parse("T(Double).valueOf(3.0d) == 4.0d");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Double).valueOf(3.0d) == T(Double).valueOf(3.0d)");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("5.0d == T(Double).valueOf(3.0d)");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());

    expression = parse("false == true");
    assertFalse((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertFalse((Boolean)expression.getValue());
   
    expression = parse("T(Boolean).valueOf('true') == T(Boolean).valueOf('true')");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("T(Boolean).valueOf('true') == true");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());

    expression = parse("false == T(Boolean).valueOf('false')");
    assertTrue((Boolean)expression.getValue());
    assertCanCompile(expression);
    assertTrue((Boolean)expression.getValue());
  }
 
  @Test
  public void opPlus() throws Exception {
    expression = parse("2+2");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4,expression.getValue());
   
    expression = parse("2L+2L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4L,expression.getValue());

    expression = parse("2.0f+2.0f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4.0f,expression.getValue());

    expression = parse("3.0d+4.0d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(7.0d,expression.getValue());
   
    expression = parse("+1");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1,expression.getValue());   

    expression = parse("+1L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());   

    expression = parse("+1.5f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1.5f,expression.getValue());   

    expression = parse("+2.5d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(2.5d,expression.getValue())

    expression = parse("+T(Double).valueOf(2.5d)");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(2.5d,expression.getValue())
   
    expression = parse("T(Integer).valueOf(2)+6");
    assertEquals(8,expression.getValue());
    assertCanCompile(expression);
    assertEquals(8,expression.getValue());
   
    expression = parse("T(Integer).valueOf(1)+T(Integer).valueOf(3)");
    assertEquals(4,expression.getValue());
    assertCanCompile(expression);
    assertEquals(4,expression.getValue());

    expression = parse("1+T(Integer).valueOf(3)");
    assertEquals(4,expression.getValue());
    assertCanCompile(expression);
    assertEquals(4,expression.getValue());

    expression = parse("T(Float).valueOf(2.0f)+6");
    assertEquals(8.0f,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Float).valueOf(2.0f)+T(Float).valueOf(3.0f)");
    assertEquals(5.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(5.0f,expression.getValue());

    expression = parse("3L+T(Long).valueOf(4L)");
    assertEquals(7L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(7L,expression.getValue());

    expression = parse("T(Long).valueOf(2L)+6");
    assertEquals(8L,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Long).valueOf(2L)+T(Long).valueOf(3L)");
    assertEquals(5L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(5L,expression.getValue());

    expression = parse("1L+T(Long).valueOf(2L)");
    assertEquals(3L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(3L,expression.getValue());
  }
 
  @Test
  public void opPlusString() throws Exception {
    expression = parse("'hello' + 'world'");
    assertEquals("helloworld",expression.getValue());
    assertCanCompile(expression);
    assertEquals("helloworld",expression.getValue());

    // Method with string return
    expression = parse("'hello' + getWorld()");
    assertEquals("helloworld",expression.getValue(new Greeter()));
    assertCanCompile(expression);
    assertEquals("helloworld",expression.getValue(new Greeter()));
   
    // Method with string return
    expression = parse("getWorld() + 'hello'");
    assertEquals("worldhello",expression.getValue(new Greeter()));
    assertCanCompile(expression);
    assertEquals("worldhello",expression.getValue(new Greeter()));

    // Three strings, optimal bytecode would only use one StringBuilder
    expression = parse("'hello' + getWorld() + ' spring'");
    assertEquals("helloworld spring",expression.getValue(new Greeter()));
    assertCanCompile(expression);
    assertEquals("helloworld spring",expression.getValue(new Greeter()));
   
    // Three strings, optimal bytecode would only use one StringBuilder
    expression = parse("'hello' + 3 + ' spring'");
    assertEquals("hello3 spring",expression.getValue(new Greeter()));
    assertCantCompile(expression);
  }
 
  public static class Greeter {
    public String getWorld() {
      return "world";
    }
  }

  @Test
  public void opMinus() throws Exception {
    expression = parse("2-2");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(0,expression.getValue());
   
    expression = parse("4L-2L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(2L,expression.getValue());

    expression = parse("4.0f-2.0f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(2.0f,expression.getValue());

    expression = parse("3.0d-4.0d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(-1.0d,expression.getValue());
   
    expression = parse("-1");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(-1,expression.getValue());   

    expression = parse("-1L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(-1L,expression.getValue());   

    expression = parse("-1.5f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(-1.5f,expression.getValue());   

    expression = parse("-2.5d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(-2.5d,expression.getValue())
   
    expression = parse("T(Integer).valueOf(2)-6");
    assertEquals(-4,expression.getValue());
    assertCanCompile(expression);
    assertEquals(-4,expression.getValue());
   
    expression = parse("T(Integer).valueOf(1)-T(Integer).valueOf(3)");
    assertEquals(-2,expression.getValue());
    assertCanCompile(expression);
    assertEquals(-2,expression.getValue());

    expression = parse("4-T(Integer).valueOf(3)");
    assertEquals(1,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1,expression.getValue());

    expression = parse("T(Float).valueOf(2.0f)-6");
    assertEquals(-4.0f,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Float).valueOf(8.0f)-T(Float).valueOf(3.0f)");
    assertEquals(5.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(5.0f,expression.getValue());

    expression = parse("11L-T(Long).valueOf(4L)");
    assertEquals(7L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(7L,expression.getValue());

    expression = parse("T(Long).valueOf(9L)-6");
    assertEquals(3L,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Long).valueOf(4L)-T(Long).valueOf(3L)");
    assertEquals(1L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());

    expression = parse("8L-T(Long).valueOf(2L)");
    assertEquals(6L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(6L,expression.getValue());
  }
 
 
  @Test
  public void opMultiply() throws Exception {
    expression = parse("2*2");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4,expression.getValue());
   
    expression = parse("2L*2L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4L,expression.getValue());

    expression = parse("2.0f*2.0f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(4.0f,expression.getValue());

    expression = parse("3.0d*4.0d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(12.0d,expression.getValue());

    expression = parse("T(Float).valueOf(2.0f)*6");
    assertEquals(12.0f,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Float).valueOf(8.0f)*T(Float).valueOf(3.0f)");
    assertEquals(24.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(24.0f,expression.getValue());

    expression = parse("11L*T(Long).valueOf(4L)");
    assertEquals(44L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(44L,expression.getValue());

    expression = parse("T(Long).valueOf(9L)*6");
    assertEquals(54L,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Long).valueOf(4L)*T(Long).valueOf(3L)");
    assertEquals(12L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(12L,expression.getValue());

    expression = parse("8L*T(Long).valueOf(2L)");
    assertEquals(16L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(16L,expression.getValue());

    expression = parse("T(Float).valueOf(8.0f)*-T(Float).valueOf(3.0f)");
    assertEquals(-24.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(-24.0f,expression.getValue());
  }
 
  @Test
  public void opDivide() throws Exception {
    expression = parse("2/2");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1,expression.getValue());
   
    expression = parse("2L/2L");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());

    expression = parse("2.0f/2.0f");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(1.0f,expression.getValue());

    expression = parse("3.0d/4.0d");
    expression.getValue();
    assertCanCompile(expression);
    assertEquals(0.75d,expression.getValue());

    expression = parse("T(Float).valueOf(6.0f)/2");
    assertEquals(3.0f,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Float).valueOf(8.0f)/T(Float).valueOf(2.0f)");
    assertEquals(4.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(4.0f,expression.getValue());

    expression = parse("12L/T(Long).valueOf(4L)");
    assertEquals(3L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(3L,expression.getValue());

    expression = parse("T(Long).valueOf(44L)/11");
    assertEquals(4L,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Long).valueOf(4L)/T(Long).valueOf(2L)");
    assertEquals(2L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(2L,expression.getValue());

    expression = parse("8L/T(Long).valueOf(2L)");
    assertEquals(4L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(4L,expression.getValue());

    expression = parse("T(Float).valueOf(8.0f)/-T(Float).valueOf(4.0f)");
    assertEquals(-2.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(-2.0f,expression.getValue());
  }
 
  @Test
  public void opModulus_12041() throws Exception {
    expression = parse("2%2");
    assertEquals(0,expression.getValue());
    assertCanCompile(expression);
    assertEquals(0,expression.getValue());

    expression = parse("payload%2==0");
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.TYPE));
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(5),Boolean.TYPE));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.TYPE));
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(5),Boolean.TYPE));

    expression = parse("8%3");
    assertEquals(2,expression.getValue());
    assertCanCompile(expression);
    assertEquals(2,expression.getValue());
   
    expression = parse("17L%5L");
    assertEquals(2L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(2L,expression.getValue());

    expression = parse("3.0f%2.0f");
    assertEquals(1.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1.0f,expression.getValue());

    expression = parse("3.0d%4.0d");
    assertEquals(3.0d,expression.getValue());
    assertCanCompile(expression);
    assertEquals(3.0d,expression.getValue());

    expression = parse("T(Float).valueOf(6.0f)%2");
    assertEquals(0.0f,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Float).valueOf(6.0f)%4");
    assertEquals(2.0f,expression.getValue());
    assertCantCompile(expression);

    expression = parse("T(Float).valueOf(8.0f)%T(Float).valueOf(3.0f)");
    assertEquals(2.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(2.0f,expression.getValue());

    expression = parse("13L%T(Long).valueOf(4L)");
    assertEquals(1L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());

    expression = parse("T(Long).valueOf(44L)%12");
    assertEquals(8L,expression.getValue());
    assertCantCompile(expression);
   
    expression = parse("T(Long).valueOf(9L)%T(Long).valueOf(2L)");
    assertEquals(1L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());

    expression = parse("7L%T(Long).valueOf(2L)");
    assertEquals(1L,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1L,expression.getValue());

    expression = parse("T(Float).valueOf(9.0f)%-T(Float).valueOf(4.0f)");
    assertEquals(1.0f,expression.getValue());
    assertCanCompile(expression);
    assertEquals(1.0f,expression.getValue());
  }

  @Test
  public void failsWhenSettingContextForExpression_SPR12326() {
      SpelExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE, this
              .getClass().getClassLoader()));
      Person3 person = new Person3("foo", 1);
      SpelExpression expression = parser.parseRaw("#it?.age?.equals([0])");
      StandardEvaluationContext context = new StandardEvaluationContext(new Object[] { 1 });
      context.setVariable("it", person);
      expression.setEvaluationContext(context);
      assertTrue(expression.getValue(Boolean.class));
      assertTrue(expression.getValue(Boolean.class));      
      assertCanCompile(expression);
      assertTrue(expression.getValue(Boolean.class));
  }
 
  @Test
  public void constructorReference_SPR12326() {
    String type = this.getClass().getName();
    String prefix = "new "+type+".Obj";

    expression = parser.parseExpression(prefix+"([0])");
    assertEquals("test", ((Obj) expression.getValue(new Object[] { "test" })).param1);
    assertCanCompile(expression);
    assertEquals("test", ((Obj) expression.getValue(new Object[] { "test" })).param1);
   
    expression = parser.parseExpression(prefix+"2('foo','bar').output");
    assertEquals("foobar", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("foobar", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"2('foo').output");
    assertEquals("foo", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("foo", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"2().output");
    assertEquals("", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("", expression.getValue(String.class));
   
    expression = parser.parseExpression(prefix+"3(1,2,3).output");
    assertEquals("123", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("123", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"3(1).output");
    assertEquals("1", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("1", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"3().output");
    assertEquals("", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("", expression.getValue(String.class));
   
    expression = parser.parseExpression(prefix+"3('abc',5.0f,1,2,3).output");
    assertEquals("abc:5.0:123", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("abc:5.0:123", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"3('abc',5.0f,1).output");
    assertEquals("abc:5.0:1", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("abc:5.0:1", expression.getValue(String.class));

    expression = parser.parseExpression(prefix+"3('abc',5.0f).output");
    assertEquals("abc:5.0:", expression.getValue(String.class));
    assertCanCompile(expression);
    assertEquals("abc:5.0:", expression.getValue(String.class));
   
    expression = parser.parseExpression(prefix+"4(#root).output");
    assertEquals("123", expression.getValue(new int[]{1,2,3},String.class));
    assertCanCompile(expression);
    assertEquals("123", expression.getValue(new int[]{1,2,3},String.class));
  }
 
  @Test
  public void methodReferenceMissingCastAndRootObjectAccessing_SPR12326() {
    // Need boxing code on the 1 so that toString() can be called
    expression = parser.parseExpression("1.toString()");
    assertEquals("1", expression.getValue());
    assertCanCompile(expression);
    assertEquals("1", expression.getValue());

    expression = parser.parseExpression("#it?.age.equals([0])");
    Person person = new Person(1);
    StandardEvaluationContext context =
        new StandardEvaluationContext(new Object[] { person.getAge() });
    context.setVariable("it", person);
    assertTrue(expression.getValue(context, Boolean.class));
    assertCanCompile(expression);
    assertTrue(expression.getValue(context, Boolean.class));

    // Variant of above more like what was in the bug report:
    SpelExpressionParser parser = new SpelExpressionParser(
        new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,
            this.getClass().getClassLoader()));

    SpelExpression ex = parser.parseRaw("#it?.age.equals([0])");
    context = new StandardEvaluationContext(new Object[] { person.getAge() });
    context.setVariable("it", person);
    assertTrue(ex.getValue(context, Boolean.class));
    assertTrue(ex.getValue(context, Boolean.class));
   
    PersonInOtherPackage person2 = new PersonInOtherPackage(1);
    ex = parser.parseRaw("#it?.age.equals([0])");
    context =
        new StandardEvaluationContext(new Object[] { person2.getAge() });
    context.setVariable("it", person2);
    assertTrue(ex.getValue(context, Boolean.class));
    assertTrue(ex.getValue(context, Boolean.class));
   
    ex = parser.parseRaw("#it?.age.equals([0])");
    context =
        new StandardEvaluationContext(new Object[] { person2.getAge() });
    context.setVariable("it", person2);
    assertTrue((Boolean)ex.getValue(context));
    assertTrue((Boolean)ex.getValue(context));
  }
    
  public class Person {
  
      private int age;
  
      public Person(int age) {
          this.age = age;
      }
  
      public int getAge() {
          return age;
      }
  
      public void setAge(int age) {
          this.age = age;
      }
  }
 
  public class Person3 {
    
      private int age;
  
      public Person3(String name, int age) {
          this.age = age;
      }
  
      public int getAge() {
          return age;
      }
  
      public void setAge(int age) {
          this.age = age;
      }
  }

  @Test
  public void constructorReference() throws Exception {
    // simple ctor
    expression = parser.parseExpression("new String('123')");
    assertEquals("123",expression.getValue());
    assertCanCompile(expression);
    assertEquals("123",expression.getValue());

    String testclass8 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass8";
    // multi arg ctor that includes primitives
    expression = parser.parseExpression("new "+testclass8+"(42,'123',4.0d,true)");
    assertEquals(testclass8,expression.getValue().getClass().getName());
    assertCanCompile(expression);
    Object o = expression.getValue();
    assertEquals(testclass8,o.getClass().getName());
    TestClass8 tc8 = (TestClass8)o;
    assertEquals(42,tc8.i);
    assertEquals("123",tc8.s);
    assertEquals(4.0d,tc8.d,0.5d);
    assertEquals(true,tc8.z);
   
    // no-arg ctor
    expression = parser.parseExpression("new "+testclass8+"()");
    assertEquals(testclass8,expression.getValue().getClass().getName());
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals(testclass8,o.getClass().getName());
   
    // pass primitive to reference type ctor
    expression = parser.parseExpression("new "+testclass8+"(42)");
    assertEquals(testclass8,expression.getValue().getClass().getName());
    assertCanCompile(expression);
    o = expression.getValue();
    assertEquals(testclass8,o.getClass().getName());
    tc8 = (TestClass8)o;
    assertEquals(42,tc8.i);

    // private class, can't compile it
    String testclass9 = "org.springframework.expression.spel.SpelCompilationCoverageTests$TestClass9";
    expression = parser.parseExpression("new "+testclass9+"(42)");
    assertEquals(testclass9,expression.getValue().getClass().getName());
    assertCantCompile(expression);
  }
 
  @Test
  public void methodReferenceReflectiveMethodSelectionWithVarargs() throws Exception {
    TestClass10 tc = new TestClass10();
   
    // Should call the non varargs version of concat
    // (which causes the '::' prefix in test output)
    expression = parser.parseExpression("concat('test')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("::test",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("::test",tc.s);
    tc.reset();   

    // This will call the varargs concat with an empty array
    expression = parser.parseExpression("concat()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("",tc.s);
    tc.reset();   
   
    // Should call the non varargs version of concat
    // (which causes the '::' prefix in test output)
    expression = parser.parseExpression("concat2('test')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("::test",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("::test",tc.s);
    tc.reset();   

    // This will call the varargs concat with an empty array
    expression = parser.parseExpression("concat2()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("",tc.s);
    tc.reset();   
  }

  @Test
  public void methodReferenceVarargs() throws Exception {
    TestClass5 tc = new TestClass5();
   
    // varargs string
    expression = parser.parseExpression("eleven()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("",tc.s);
    tc.reset();
   
    // varargs string
    expression = parser.parseExpression("eleven('aaa')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaa",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaa",tc.s);
    tc.reset();
   
    // varargs string
    expression = parser.parseExpression("eleven(stringArray)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    tc.reset();

    // varargs string
    expression = parser.parseExpression("eleven('aaa','bbb','ccc')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    tc.reset();
   
    expression = parser.parseExpression("sixteen('aaa','bbb','ccc')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaabbbccc",tc.s);
    tc.reset();
   
    // TODO Fails related to conversion service converting a String[] to satisfy Object...
//    expression = parser.parseExpression("sixteen(stringArray)");
//    assertCantCompile(expression);
//    expression.getValue(tc);
//    assertEquals("aaabbbccc",tc.s);
//    assertCanCompile(expression);
//    tc.reset();
//    expression.getValue(tc);
//    assertEquals("aaabbbccc",tc.s);
//    tc.reset();

    // varargs int
    expression = parser.parseExpression("twelve(1,2,3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals(6,tc.i);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(6,tc.i);
    tc.reset();
   
    expression = parser.parseExpression("twelve(1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals(1,tc.i);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(1,tc.i);
    tc.reset();

    // one string then varargs string
    expression = parser.parseExpression("thirteen('aaa','bbb','ccc')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaa::bbbccc",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaa::bbbccc",tc.s);
    tc.reset();
   
    // nothing passed to varargs parameter
    expression = parser.parseExpression("thirteen('aaa')");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaa::",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaa::",tc.s);
    tc.reset();
   
    // nested arrays
    expression = parser.parseExpression("fourteen('aaa',stringArray,stringArray)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaa::{aaabbbccc}{aaabbbccc}",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaa::{aaabbbccc}{aaabbbccc}",tc.s);
    tc.reset();
   
    // nested primitive array
    expression = parser.parseExpression("fifteen('aaa',intArray,intArray)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("aaa::{112233}{112233}",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("aaa::{112233}{112233}",tc.s);
    tc.reset();
   
    // varargs boolean
    expression = parser.parseExpression("arrayz(true,true,false)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("truetruefalse",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("truetruefalse",tc.s);
    tc.reset();
   
    expression = parser.parseExpression("arrayz(true)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("true",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("true",tc.s);
    tc.reset();
   
    // varargs short
    expression = parser.parseExpression("arrays(s1,s2,s3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("123",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("123",tc.s);
    tc.reset();
   
    expression = parser.parseExpression("arrays(s1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1",tc.s);
    tc.reset();
   
    // varargs double
    expression = parser.parseExpression("arrayd(1.0d,2.0d,3.0d)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1.02.03.0",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1.02.03.0",tc.s);
    tc.reset();

    expression = parser.parseExpression("arrayd(1.0d)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1.0",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1.0",tc.s);
    tc.reset();
   
    // varargs long
    expression = parser.parseExpression("arrayj(l1,l2,l3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("123",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("123",tc.s);
    tc.reset();

    expression = parser.parseExpression("arrayj(l1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1",tc.s);
    tc.reset();

    // varargs char
    expression = parser.parseExpression("arrayc(c1,c2,c3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("abc",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("abc",tc.s);
    tc.reset();

    expression = parser.parseExpression("arrayc(c1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("a",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("a",tc.s);
    tc.reset();

    // varargs byte
    expression = parser.parseExpression("arrayb(b1,b2,b3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("656667",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("656667",tc.s);
    tc.reset();
   
    expression = parser.parseExpression("arrayb(b1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("65",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("65",tc.s);
    tc.reset();

    // varargs float
    expression = parser.parseExpression("arrayf(f1,f2,f3)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1.02.03.0",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1.02.03.0",tc.s);
    tc.reset();
   
    expression = parser.parseExpression("arrayf(f1)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("1.0",tc.s);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("1.0",tc.s);
    tc.reset();
  }
 
  @Test
  public void methodReference() throws Exception {
    TestClass5 tc = new TestClass5();
   
    // non-static method, no args, void return
    expression = parser.parseExpression("one()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(1,tc.i);
    tc.reset();
   
    // static method, no args, void return
    expression = parser.parseExpression("two()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(1,TestClass5._i);
    tc.reset();
   
    // non-static method, reference type return
    expression = parser.parseExpression("three()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    assertEquals("hello",expression.getValue(tc));
    tc.reset();

    // non-static method, primitive type return
    expression = parser.parseExpression("four()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    assertEquals(3277700L,expression.getValue(tc));
    tc.reset();
   
    // static method, reference type return
    expression = parser.parseExpression("five()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    assertEquals("hello",expression.getValue(tc));
    tc.reset();

    // static method, primitive type return
    expression = parser.parseExpression("six()");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    assertEquals(3277700L,expression.getValue(tc));
    tc.reset();
   
    // non-static method, one parameter of reference type
    expression = parser.parseExpression("seven(\"foo\")");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("foo",tc.s);
    tc.reset();
   
    // static method, one parameter of reference type
    expression = parser.parseExpression("eight(\"bar\")");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals("bar",TestClass5._s);
    tc.reset();

    // non-static method, one parameter of primitive type
    expression = parser.parseExpression("nine(231)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(231,tc.i);
    tc.reset();

    // static method, one parameter of primitive type
    expression = parser.parseExpression("ten(111)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertCanCompile(expression);
    tc.reset();
    expression.getValue(tc);
    assertEquals(111,TestClass5._i);
    tc.reset();
   
    // method that gets type converted parameters
   
    // Converting from an int to a string
    expression = parser.parseExpression("seven(123)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("123",tc.s);
    assertCantCompile(expression); // Uncompilable as argument conversion is occurring
   
    Expression expression = parser.parseExpression("'abcd'.substring(index1,index2)");
    String resultI = expression.getValue(new TestClass1(),String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(new TestClass1(),String.class);
    assertEquals("bc",resultI);
    assertEquals("bc",resultC);
   
    // Converting from an int to a Number
    expression = parser.parseExpression("takeNumber(123)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("123",tc.s);
    tc.reset();
    assertCanCompile(expression); // The generated code should include boxing of the int to a Number
    expression.getValue(tc);
    assertEquals("123",tc.s);

    // Passing a subtype
    expression = parser.parseExpression("takeNumber(T(Integer).valueOf(42))");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("42",tc.s);
    tc.reset();
    assertCanCompile(expression); // The generated code should include boxing of the int to a Number
    expression.getValue(tc);
    assertEquals("42",tc.s);

    // Passing a subtype
    expression = parser.parseExpression("takeString(T(Integer).valueOf(42))");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("42",tc.s);
    tc.reset();
    assertCantCompile(expression); // method takes a string and we are passing an Integer
  }
   
 
  @Test
  public void errorHandling() throws Exception {
    TestClass5 tc = new TestClass5();
   
    // changing target
   
    // from primitive array to reference type array
    int[] is = new int[]{1,2,3};
    String[] strings = new String[]{"a","b","c"};
    expression = parser.parseExpression("[1]");
    assertEquals(2,expression.getValue(is));
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(is));
   
    try {
      assertEquals(2,expression.getValue(strings));
      fail();
    } catch (SpelEvaluationException see) {
      assertTrue(see.getCause() instanceof ClassCastException);
    }
    SpelCompiler.revertToInterpreted(expression);
    assertEquals("b",expression.getValue(strings));
    assertCanCompile(expression);
    assertEquals("b",expression.getValue(strings));
   
   
    tc.field = "foo";
    expression = parser.parseExpression("seven(field)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("foo",tc.s);
    assertCanCompile(expression);
    tc.reset();
    tc.field="bar";
    expression.getValue(tc);
   
    // method with changing parameter types (change reference type)
    tc.obj = "foo";
    expression = parser.parseExpression("seven(obj)");
    assertCantCompile(expression);
    expression.getValue(tc);
    assertEquals("foo",tc.s);
    assertCanCompile(expression);
    tc.reset();
    tc.obj=new Integer(42);
    try {
      expression.getValue(tc);
      fail();
    } catch (SpelEvaluationException see) {
      assertTrue(see.getCause() instanceof ClassCastException);
    }
   
   
    // method with changing target
    expression = parser.parseExpression("#root.charAt(0)");
    assertEquals('a',expression.getValue("abc"));
    assertCanCompile(expression);
    try {
      expression.getValue(new Integer(42));
      fail();
    } catch (SpelEvaluationException see) {
      // java.lang.Integer cannot be cast to java.lang.String
      assertTrue(see.getCause() instanceof ClassCastException);
    }   
  }
 
  @Test
  public void methodReference_staticMethod() throws Exception {
    Expression expression = parser.parseExpression("T(Integer).valueOf(42)");
    int resultI = expression.getValue(new TestClass1(),Integer.TYPE);
    assertCanCompile(expression);
    int resultC = expression.getValue(new TestClass1(),Integer.TYPE);
    assertEquals(42,resultI);
    assertEquals(42,resultC);   
  }
 
  @Test
  public void methodReference_literalArguments_int() throws Exception {
    Expression expression = parser.parseExpression("'abcd'.substring(1,3)");
    String resultI = expression.getValue(new TestClass1(),String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(new TestClass1(),String.class);
    assertEquals("bc",resultI);
    assertEquals("bc",resultC);
  }

  @Test
  public void methodReference_simpleInstanceMethodNoArg() throws Exception {
    Expression expression = parser.parseExpression("toString()");
    String resultI = expression.getValue(42,String.class);
    assertCanCompile(expression);
    String resultC = expression.getValue(42,String.class);
    assertEquals("42",resultI);
    assertEquals("42",resultC);
  }

  @Test
  public void methodReference_simpleInstanceMethodNoArgReturnPrimitive() throws Exception {
    expression = parser.parseExpression("intValue()");
    int resultI = expression.getValue(new Integer(42),Integer.TYPE);
    assertEquals(42,resultI);
    assertCanCompile(expression);
    int resultC = expression.getValue(new Integer(42),Integer.TYPE);
    assertEquals(42,resultC);
  }
 
  @Test
  public void methodReference_simpleInstanceMethodOneArgReturnPrimitive1() throws Exception {
    Expression expression = parser.parseExpression("indexOf('b')");
    int resultI = expression.getValue("abc",Integer.TYPE);
    assertCanCompile(expression);
    int resultC = expression.getValue("abc",Integer.TYPE);
    assertEquals(1,resultI);
    assertEquals(1,resultC);
  }

  @Test
  public void methodReference_simpleInstanceMethodOneArgReturnPrimitive2() throws Exception {
    expression = parser.parseExpression("charAt(2)");
    char resultI = expression.getValue("abc",Character.TYPE);
    assertEquals('c',resultI);
    assertCanCompile(expression);
    char resultC = expression.getValue("abc",Character.TYPE);
    assertEquals('c',resultC);
  }

  @Test
  public void compoundExpression() throws Exception {
    Payload payload = new Payload();
    expression = parser.parseExpression("DR[0]");
    assertEquals("instanceof Two",expression.getValue(payload).toString());
    assertCanCompile(expression);
    assertEquals("instanceof Two",expression.getValue(payload).toString());
    ast = getAst();
    assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two",ast.getExitDescriptor());

    expression = parser.parseExpression("holder.three");
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
    assertCanCompile(expression);
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
    ast = getAst();
    assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",ast.getExitDescriptor());

    expression = parser.parseExpression("DR[0]");
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two",expression.getValue(payload).getClass().getName());
    assertCanCompile(expression);
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Two",expression.getValue(payload).getClass().getName());
    assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Two",getAst().getExitDescriptor());

    expression = parser.parseExpression("DR[0].three");
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
    assertCanCompile(expression);
    assertEquals("org.springframework.expression.spel.SpelCompilationCoverageTests$Three",expression.getValue(payload).getClass().getName());
    ast = getAst();
    assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",ast.getExitDescriptor());

    expression = parser.parseExpression("DR[0].three.four");
    assertEquals(0.04d,expression.getValue(payload));
    assertCanCompile(expression);
    assertEquals(0.04d,expression.getValue(payload));
    assertEquals("D",getAst().getExitDescriptor());
  }
 
 
  @Test
  public void mixingItUp_indexerOpEqTernary() throws Exception {
    Map<String, String> m = new HashMap<String,String>();
    m.put("andy","778");

    expression = parse("['andy']==null?1:2");
    System.out.println(expression.getValue(m));
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(m));
    m.remove("andy");
    assertEquals(1,expression.getValue(m));
  }
 
  @Test
  public void propertyReference() throws Exception {
    TestClass6 tc = new TestClass6();
   
    // non static field
    expression = parser.parseExpression("orange");
    assertCantCompile(expression);
    assertEquals("value1",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value1",expression.getValue(tc));
   
    // static field
    expression = parser.parseExpression("apple");
    assertCantCompile(expression);
    assertEquals("value2",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value2",expression.getValue(tc))
   
    // non static getter
    expression = parser.parseExpression("banana");
    assertCantCompile(expression);
    assertEquals("value3",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value3",expression.getValue(tc));

    // static getter
    expression = parser.parseExpression("plum");
    assertCantCompile(expression);
    assertEquals("value4",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value4",expression.getValue(tc));
  }

  @Test
  public void propertyReferenceVisibility() { // SPR-12771
    StandardEvaluationContext ctx = new StandardEvaluationContext();
    ctx.setVariable("httpServletRequest", HttpServlet3RequestFactory.getOne());
    // Without a fix compilation was inserting a checkcast to a private type
    expression = parser.parseExpression("#httpServletRequest.servletPath");
    assertEquals("wibble",expression.getValue(ctx));
    assertCanCompile(expression);
    assertEquals("wibble",expression.getValue(ctx));
  }
   
  @SuppressWarnings("unchecked")
  @Test
  public void indexer() throws Exception {
    String[] sss = new String[]{"a","b","c"};
    Number[] ns = new Number[]{2,8,9};
    int[] is = new int[]{8,9,10};
    double[] ds = new double[]{3.0d,4.0d,5.0d};
    long[] ls = new long[]{2L,3L,4L};
    short[] ss = new short[]{(short)33,(short)44,(short)55};
    float[] fs = new float[]{6.0f,7.0f,8.0f};
    byte[] bs = new byte[]{(byte)2,(byte)3,(byte)4};
    char[] cs = new char[]{'a','b','c'};
       
    // Access String (reference type) array
    expression = parser.parseExpression("[0]");
    assertEquals("a",expression.getValue(sss));
    assertCanCompile(expression);
    assertEquals("a",expression.getValue(sss));
    assertEquals("Ljava/lang/String",getAst().getExitDescriptor());

    expression = parser.parseExpression("[1]");
    assertEquals(8,expression.getValue(ns));
    assertCanCompile(expression);
    assertEquals(8,expression.getValue(ns));
    assertEquals("Ljava/lang/Number",getAst().getExitDescriptor());
   
    // Access int array
    expression = parser.parseExpression("[2]");
    assertEquals(10,expression.getValue(is));
    assertCanCompile(expression);
    assertEquals(10,expression.getValue(is));
    assertEquals("I",getAst().getExitDescriptor());

    // Access double array
    expression = parser.parseExpression("[1]");
    assertEquals(4.0d,expression.getValue(ds));
    assertCanCompile(expression);
    assertEquals(4.0d,expression.getValue(ds));
    assertEquals("D",getAst().getExitDescriptor());

    // Access long array
    expression = parser.parseExpression("[0]");
    assertEquals(2L,expression.getValue(ls));
    assertCanCompile(expression);
    assertEquals(2L,expression.getValue(ls));
    assertEquals("J",getAst().getExitDescriptor());

    // Access short array
    expression = parser.parseExpression("[2]");
    assertEquals((short)55,expression.getValue(ss));
    assertCanCompile(expression);
    assertEquals((short)55,expression.getValue(ss));
    assertEquals("S",getAst().getExitDescriptor());

    // Access float array
    expression = parser.parseExpression("[0]");
    assertEquals(6.0f,expression.getValue(fs));
    assertCanCompile(expression);
    assertEquals(6.0f,expression.getValue(fs));
    assertEquals("F",getAst().getExitDescriptor());

    // Access byte array
    expression = parser.parseExpression("[2]");
    assertEquals((byte)4,expression.getValue(bs));
    assertCanCompile(expression);
    assertEquals((byte)4,expression.getValue(bs));
    assertEquals("B",getAst().getExitDescriptor());

    // Access char array
    expression = parser.parseExpression("[1]");
    assertEquals('b',expression.getValue(cs));
    assertCanCompile(expression);
    assertEquals('b',expression.getValue(cs));
    assertEquals("C",getAst().getExitDescriptor());
   
    // Collections
    List<String> strings = new ArrayList<String>();
    strings.add("aaa");
    strings.add("bbb");
    strings.add("ccc");
    expression = parser.parseExpression("[1]");
    assertEquals("bbb",expression.getValue(strings));
    assertCanCompile(expression);
    assertEquals("bbb",expression.getValue(strings));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    List<Integer> ints = new ArrayList<Integer>();
    ints.add(123);
    ints.add(456);
    ints.add(789);
    expression = parser.parseExpression("[2]");
    assertEquals(789,expression.getValue(ints));
    assertCanCompile(expression);
    assertEquals(789,expression.getValue(ints));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    // Maps
    Map<String,Integer> map1 = new HashMap<String,Integer>();
    map1.put("aaa", 111);
    map1.put("bbb", 222);
    map1.put("ccc", 333);
    expression = parser.parseExpression("['aaa']");
    assertEquals(111,expression.getValue(map1));
    assertCanCompile(expression);
    assertEquals(111,expression.getValue(map1));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    // Object
    TestClass6 tc = new TestClass6();
    expression = parser.parseExpression("['orange']");
    assertEquals("value1",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value1",expression.getValue(tc));
    assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("['peach']");
    assertEquals(34L,expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals(34L,expression.getValue(tc));
    assertEquals("J",getAst().getExitDescriptor());

    // getter
    expression = parser.parseExpression("['banana']");
    assertEquals("value3",expression.getValue(tc));
    assertCanCompile(expression);
    assertEquals("value3",expression.getValue(tc));
    assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
   
    // list of arrays
   
    List<String[]> listOfStringArrays = new ArrayList<String[]>();
    listOfStringArrays.add(new String[]{"a","b","c"});
    listOfStringArrays.add(new String[]{"d","e","f"});
    expression = parser.parseExpression("[1]");
    assertEquals("d e f",stringify(expression.getValue(listOfStringArrays)));
    assertCanCompile(expression);
    assertEquals("d e f",stringify(expression.getValue(listOfStringArrays)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[1][0]");
    assertEquals("d",stringify(expression.getValue(listOfStringArrays)));
    assertCanCompile(expression);
    assertEquals("d",stringify(expression.getValue(listOfStringArrays)));
    assertEquals("Ljava/lang/String",getAst().getExitDescriptor());

    List<Integer[]> listOfIntegerArrays = new ArrayList<Integer[]>();
    listOfIntegerArrays.add(new Integer[]{1,2,3});
    listOfIntegerArrays.add(new Integer[]{4,5,6});
    expression = parser.parseExpression("[0]");
    assertEquals("1 2 3",stringify(expression.getValue(listOfIntegerArrays)));
    assertCanCompile(expression);
    assertEquals("1 2 3",stringify(expression.getValue(listOfIntegerArrays)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());

    expression = parser.parseExpression("[0][1]");
    assertEquals(2,expression.getValue(listOfIntegerArrays));
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(listOfIntegerArrays));
    assertEquals("Ljava/lang/Integer",getAst().getExitDescriptor());
   
    // array of lists
    List<String>[] stringArrayOfLists = new ArrayList[2];
    stringArrayOfLists[0] = new ArrayList<String>();
    stringArrayOfLists[0].add("a");
    stringArrayOfLists[0].add("b");
    stringArrayOfLists[0].add("c");
    stringArrayOfLists[1] = new ArrayList<String>();
    stringArrayOfLists[1].add("d");
    stringArrayOfLists[1].add("e");
    stringArrayOfLists[1].add("f");
    expression = parser.parseExpression("[1]");
    assertEquals("d e f",stringify(expression.getValue(stringArrayOfLists)));
    assertCanCompile(expression);
    assertEquals("d e f",stringify(expression.getValue(stringArrayOfLists)));
    assertEquals("Ljava/util/ArrayList",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[1][2]");
    assertEquals("f",stringify(expression.getValue(stringArrayOfLists)));
    assertCanCompile(expression);
    assertEquals("f",stringify(expression.getValue(stringArrayOfLists)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    // array of arrays
    String[][] referenceTypeArrayOfArrays = new String[][]{new String[]{"a","b","c"},new String[]{"d","e","f"}};
    expression = parser.parseExpression("[1]");
    assertEquals("d e f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
    assertCanCompile(expression);
    assertEquals("[Ljava/lang/String",getAst().getExitDescriptor());
    assertEquals("d e f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
    assertEquals("[Ljava/lang/String",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[1][2]");
    assertEquals("f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
    assertCanCompile(expression);
    assertEquals("f",stringify(expression.getValue(referenceTypeArrayOfArrays)));
    assertEquals("Ljava/lang/String",getAst().getExitDescriptor());
   
    int[][] primitiveTypeArrayOfArrays = new int[][]{new int[]{1,2,3},new int[]{4,5,6}};
    expression = parser.parseExpression("[1]");
    assertEquals("4 5 6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
    assertCanCompile(expression);
    assertEquals("4 5 6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
    assertEquals("[I",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[1][2]");
    assertEquals("6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
    assertCanCompile(expression);
    assertEquals("6",stringify(expression.getValue(primitiveTypeArrayOfArrays)));
    assertEquals("I",getAst().getExitDescriptor());
   
    // list of lists of reference types
    List<List<String>> listOfListOfStrings = new ArrayList<List<String>>();
    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    listOfListOfStrings.add(list);
    list = new ArrayList<String>();
    list.add("d");
    list.add("e");
    list.add("f");
    listOfListOfStrings.add(list);
   
    expression = parser.parseExpression("[1]");
    assertEquals("d e f",stringify(expression.getValue(listOfListOfStrings)));
    assertCanCompile(expression);
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
    assertEquals("d e f",stringify(expression.getValue(listOfListOfStrings)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[1][2]");
    assertEquals("f",stringify(expression.getValue(listOfListOfStrings)));
    assertCanCompile(expression);
    assertEquals("f",stringify(expression.getValue(listOfListOfStrings)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    // Map of lists
    Map<String,List<String>> mapToLists = new HashMap<String,List<String>>();
    list = new ArrayList<String>();
    list.add("a");
    list.add("b");
    list.add("c");
    mapToLists.put("foo", list);
    expression = parser.parseExpression("['foo']");
    assertEquals("a b c",stringify(expression.getValue(mapToLists)));
    assertCanCompile(expression);
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
    assertEquals("a b c",stringify(expression.getValue(mapToLists)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("['foo'][2]");
    assertEquals("c",stringify(expression.getValue(mapToLists)));
    assertCanCompile(expression);
    assertEquals("c",stringify(expression.getValue(mapToLists)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    // Map to array
    Map<String,int[]> mapToIntArray = new HashMap<String,int[]>();
    StandardEvaluationContext ctx = new StandardEvaluationContext();
    ctx.addPropertyAccessor(new CompilableMapAccessor());
    mapToIntArray.put("foo",new int[]{1,2,3});
    expression = parser.parseExpression("['foo']");
    assertEquals("1 2 3",stringify(expression.getValue(mapToIntArray)));
    assertCanCompile(expression);
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
    assertEquals("1 2 3",stringify(expression.getValue(mapToIntArray)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("['foo'][1]");
    assertEquals(2,expression.getValue(mapToIntArray));
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(mapToIntArray));
   
    expression = parser.parseExpression("foo");
    assertEquals("1 2 3",stringify(expression.getValue(ctx,mapToIntArray)));
    assertCanCompile(expression);
    assertEquals("1 2 3",stringify(expression.getValue(ctx,mapToIntArray)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());

    expression = parser.parseExpression("foo[1]");
    assertEquals(2,expression.getValue(ctx,mapToIntArray));
    assertCanCompile(expression);
    assertEquals(2,expression.getValue(ctx,mapToIntArray));

    expression = parser.parseExpression("['foo'][2]");
    assertEquals("3",stringify(expression.getValue(ctx,mapToIntArray)));
    assertCanCompile(expression);
    assertEquals("3",stringify(expression.getValue(ctx,mapToIntArray)));
    assertEquals("I",getAst().getExitDescriptor());
   
    // Map array
    Map<String,String>[] mapArray = new Map[1];
    mapArray[0] = new HashMap<String,String>();
    mapArray[0].put("key", "value1");
    expression = parser.parseExpression("[0]");
    assertEquals("{key=value1}",stringify(expression.getValue(mapArray)));
    assertCanCompile(expression);
    assertEquals("Ljava/util/Map",getAst().getExitDescriptor());
    assertEquals("{key=value1}",stringify(expression.getValue(mapArray)));
    assertEquals("Ljava/util/Map",getAst().getExitDescriptor());
   
    expression = parser.parseExpression("[0]['key']");
    assertEquals("value1",stringify(expression.getValue(mapArray)));
    assertCanCompile(expression);
    assertEquals("value1",stringify(expression.getValue(mapArray)));
    assertEquals("Ljava/lang/Object",getAst().getExitDescriptor());
  }
 
  @Test
  public void mixingItUp_propertyAccessIndexerOpLtTernaryRootNull() throws Exception {
    Payload payload = new Payload();
   
    expression = parser.parseExpression("DR[0].three");
    Object v = expression.getValue(payload);
    assertEquals("Lorg/springframework/expression/spel/SpelCompilationCoverageTests$Three",getAst().getExitDescriptor());
   
    Expression expression = parser.parseExpression("DR[0].three.four lt 0.1d?#root:null");
    v = expression.getValue(payload);
   
    SpelExpression sExpr = (SpelExpression)expression;
    Ternary ternary = (Ternary)sExpr.getAST();
    OpLT oplt = (OpLT)ternary.getChild(0);
    CompoundExpression cExpr = (CompoundExpression)oplt.getLeftOperand();
    String cExprExitDescriptor = cExpr.getExitDescriptor();
    assertEquals("D",cExprExitDescriptor);
    assertEquals("Z",oplt.getExitDescriptor());
   
    assertCanCompile(expression);
    Object vc = expression.getValue(payload);
    assertEquals(payload,v);
    assertEquals(payload,vc);
    payload.DR[0].three.four = 0.13d;
    vc = expression.getValue(payload);
    assertNull(vc);
  }

  @Test
  public void variantGetter() throws Exception {
    Payload2Holder holder = new Payload2Holder();
    StandardEvaluationContext ctx = new StandardEvaluationContext();
    ctx.addPropertyAccessor(new MyAccessor());
    expression = parser.parseExpression("payload2.var1");
    Object v = expression.getValue(ctx,holder);
    assertEquals("abc",v);
   
//    // time it interpreted
//    long stime = System.currentTimeMillis();
//    for (int i=0;i<100000;i++) {
//      v = expression.getValue(ctx,holder);
//    }
//    System.out.println((System.currentTimeMillis()-stime));
//
    assertCanCompile(expression);
    v = expression.getValue(ctx,holder);
    assertEquals("abc",v);
//   
//    // time it compiled
//    stime = System.currentTimeMillis();
//    for (int i=0;i<100000;i++) {
//      v = expression.getValue(ctx,holder);
//    }
//    System.out.println((System.currentTimeMillis()-stime));
  }
 
  @Test
  public void compilerWithGenerics_12040() {
    expression = parser.parseExpression("payload!=2");
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
   
    expression = parser.parseExpression("2!=payload");
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));

    expression = parser.parseExpression("payload!=6L");
    assertTrue(expression.getValue(new GenericMessageTestHelper<Long>(4L),Boolean.class));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper<Long>(6L),Boolean.class));
   
    expression = parser.parseExpression("payload==2");
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));
   
    expression = parser.parseExpression("2==payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));

    expression = parser.parseExpression("payload==6L");
    assertFalse(expression.getValue(new GenericMessageTestHelper<Long>(4L),Boolean.class));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper<Long>(6L),Boolean.class));

    expression = parser.parseExpression("2==payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper<Integer>(4),Boolean.class));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper<Integer>(2),Boolean.class));

    expression = parser.parseExpression("payload/2");
    assertEquals(2,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(3,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
   
    expression = parser.parseExpression("100/payload");
    assertEquals(25,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(10,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
   
    expression = parser.parseExpression("payload+2");
    assertEquals(6,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(8,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
   
    expression = parser.parseExpression("100+payload");
    assertEquals(104,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(110,expression.getValue(new GenericMessageTestHelper<Integer>(10)));
   
    expression = parser.parseExpression("payload-2");
    assertEquals(2,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(4,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
   
    expression = parser.parseExpression("100-payload");
    assertEquals(96,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(90,expression.getValue(new GenericMessageTestHelper<Integer>(10)));

    expression = parser.parseExpression("payload*2");
    assertEquals(8,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(12,expression.getValue(new GenericMessageTestHelper<Integer>(6)));
   
    expression = parser.parseExpression("100*payload");
    assertEquals(400,expression.getValue(new GenericMessageTestHelper<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(1000,expression.getValue(new GenericMessageTestHelper<Integer>(10)));

    expression = parser.parseExpression("payload/2L");
    assertEquals(2L,expression.getValue(new GenericMessageTestHelper<Long>(4L)));
    assertCanCompile(expression);
    assertEquals(3L,expression.getValue(new GenericMessageTestHelper<Long>(6L)));
   
    expression = parser.parseExpression("100L/payload");
    assertEquals(25L,expression.getValue(new GenericMessageTestHelper<Long>(4L)));
    assertCanCompile(expression);
    assertEquals(10L,expression.getValue(new GenericMessageTestHelper<Long>(10L)));

    expression = parser.parseExpression("payload/2f");
    assertEquals(2f,expression.getValue(new GenericMessageTestHelper<Float>(4f)));
    assertCanCompile(expression);
    assertEquals(3f,expression.getValue(new GenericMessageTestHelper<Float>(6f)));
   
    expression = parser.parseExpression("100f/payload");
    assertEquals(25f,expression.getValue(new GenericMessageTestHelper<Float>(4f)));
    assertCanCompile(expression);
    assertEquals(10f,expression.getValue(new GenericMessageTestHelper<Float>(10f)));

    expression = parser.parseExpression("payload/2d");
    assertEquals(2d,expression.getValue(new GenericMessageTestHelper<Double>(4d)));
    assertCanCompile(expression);
    assertEquals(3d,expression.getValue(new GenericMessageTestHelper<Double>(6d)));
   
    expression = parser.parseExpression("100d/payload");
    assertEquals(25d,expression.getValue(new GenericMessageTestHelper<Double>(4d)));
    assertCanCompile(expression);
    assertEquals(10d,expression.getValue(new GenericMessageTestHelper<Double>(10d)));
  }
 
  // The new helper class here uses an upper bound on the generic
  @Test
  public void compilerWithGenerics_12040_2() {
    expression = parser.parseExpression("payload/2");
    assertEquals(2,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(3,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));

    expression = parser.parseExpression("9/payload");
    assertEquals(1,expression.getValue(new GenericMessageTestHelper2<Integer>(9)));
    assertCanCompile(expression);
    assertEquals(3,expression.getValue(new GenericMessageTestHelper2<Integer>(3)));

    expression = parser.parseExpression("payload+2");
    assertEquals(6,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(8,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
   
    expression = parser.parseExpression("100+payload");
    assertEquals(104,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(110,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));
   
    expression = parser.parseExpression("payload-2");
    assertEquals(2,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(4,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
   
    expression = parser.parseExpression("100-payload");
    assertEquals(96,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(90,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));

    expression = parser.parseExpression("payload*2");
    assertEquals(8,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(12,expression.getValue(new GenericMessageTestHelper2<Integer>(6)));
   
    expression = parser.parseExpression("100*payload");
    assertEquals(400,expression.getValue(new GenericMessageTestHelper2<Integer>(4)));
    assertCanCompile(expression);
    assertEquals(1000,expression.getValue(new GenericMessageTestHelper2<Integer>(10)));
  }
 
  // The other numeric operators
  @Test
  public void compilerWithGenerics_12040_3() {
    expression = parser.parseExpression("payload >= 2");
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(4),Boolean.TYPE));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));

    expression = parser.parseExpression("2 >= payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(5),Boolean.TYPE));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));

    expression = parser.parseExpression("payload > 2");
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(4),Boolean.TYPE));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));

    expression = parser.parseExpression("2 > payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(5),Boolean.TYPE));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));

    expression = parser.parseExpression("payload <=2");
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));

    expression = parser.parseExpression("2 <= payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));

    expression = parser.parseExpression("payload < 2");
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
    assertCanCompile(expression);
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));

    expression = parser.parseExpression("2 < payload");
    assertFalse(expression.getValue(new GenericMessageTestHelper2<Integer>(1),Boolean.TYPE));
    assertCanCompile(expression);
    assertTrue(expression.getValue(new GenericMessageTestHelper2<Integer>(6),Boolean.TYPE));
  }

  @Test
  public void indexerMapAccessor_12045() throws Exception {
    SpelParserConfiguration spc = new SpelParserConfiguration(SpelCompilerMode.IMMEDIATE,this.getClass().getClassLoader());
    SpelExpressionParser sep = new SpelExpressionParser(spc);
    expression=sep.parseExpression("headers[command]");
    MyMessage root = new MyMessage();
    assertEquals("wibble",expression.getValue(root));
    // This next call was failing because the isCompilable check in Indexer did not check on the key being compilable
    // (and also generateCode in the Indexer was missing the optimization that it didn't need necessarily need to call
    // generateCode for that accessor)
    assertEquals("wibble",expression.getValue(root));
    assertCanCompile(expression);

    // What about a map key that is an expression - ensure the getKey() is evaluated in the right scope
    expression=sep.parseExpression("headers[getKey()]");
    assertEquals("wobble",expression.getValue(root));
    assertEquals("wobble",expression.getValue(root));
   
    expression=sep.parseExpression("list[getKey2()]");
    assertEquals("wobble",expression.getValue(root));
    assertEquals("wobble",expression.getValue(root));
   
    expression = sep.parseExpression("ia[getKey2()]");
    assertEquals(3,expression.getValue(root));
    assertEquals(3,expression.getValue(root));
  }

  // ---

  public static interface Message<T> {
    MessageHeaders getHeaders();
    @SuppressWarnings("rawtypes")
    List getList();
    int[] getIa();
  }
 
  public static class MyMessage implements Message<String> {
    public MessageHeaders getHeaders() {
      MessageHeaders mh = new MessageHeaders();
      mh.put("command", "wibble");
      mh.put("command2", "wobble");
      return mh;
    }
    public int[] getIa() { return new int[]{5,3}; }
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public List getList() {
      List l = new ArrayList();
      l.add("wibble");
      l.add("wobble");
      return l;
    }
   
    public String getKey() {
      return "command2";
    }
   
    public int getKey2() {
      return 1;
    }
  }

  @SuppressWarnings("serial")
  public static class MessageHeaders extends HashMap<String,Object> {  }

  public static class GenericMessageTestHelper<T> {
    private T payload;
   
    GenericMessageTestHelper(T value) {
      this.payload = value;
    }
   
    public T getPayload() {
      return payload;
    }
  }
 
  // This test helper has a bound on the type variable
  public static class GenericMessageTestHelper2<T extends Number> {
    private T payload;
   
    GenericMessageTestHelper2(T value) {
      this.payload = value;
    }
   
    public T getPayload() {
      return payload;
    }
  }
 
  static class MyAccessor implements CompilablePropertyAccessor {

    private Method method;

    public Class<?>[] getSpecificTargetClasses() {
      return new Class[]{Payload2.class};
    }

    public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
      // target is a Payload2 instance
      return true;
    }

    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
      Payload2 payload2 = (Payload2)target;
      return new TypedValue(payload2.getField(name));
    }

    public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
      return false;
    }

    public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
    }

    @Override
    public boolean isCompilable() {
      return true;
    }

    @Override
    public Class<?> getPropertyType() {
      return Object.class;
    }

    @Override
    public void generateCode(String propertyName, MethodVisitor mv,CodeFlow cf) {
      if (method == null) {
        try {
          method = Payload2.class.getDeclaredMethod("getField", String.class);
        }
        catch (Exception e) {
        }
      }
      String descriptor = cf.lastDescriptor();
      String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/');
      if (descriptor == null) {
        cf.loadTarget(mv);
      }
      if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
        mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
      }
      mv.visitLdcInsn(propertyName);
      mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createSignatureDescriptor(method),false);
    }
  }


  static class CompilableMapAccessor implements CompilablePropertyAccessor {

    @Override
    public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
      Map<?,?> map = (Map<?,?>) target;
      return map.containsKey(name);
    }

    @Override
    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
      Map<?,?> map = (Map<?,?>) target;
      Object value = map.get(name);
      if (value == null && !map.containsKey(name)) {
        throw new MapAccessException(name);
      }
      return new TypedValue(value);
    }

    @Override
    public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException {
      return true;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
      Map<String,Object> map = (Map<String,Object>) target;
      map.put(name, newValue);
    }

    @Override
    public Class<?>[] getSpecificTargetClasses() {
      return new Class[] {Map.class};
    }

    @Override
    public boolean isCompilable() {
      return true;
    }

    @Override
    public Class<?> getPropertyType() {
      return Object.class;
    }

    @Override
    public void generateCode(String propertyName, MethodVisitor mv, CodeFlow cf) {
      String descriptor = cf.lastDescriptor();
      if (descriptor == null) {
        cf.loadTarget(mv);
      }
      mv.visitLdcInsn(propertyName);
      mv.visitMethodInsn(INVOKEINTERFACE, "java/util/Map", "get","(Ljava/lang/Object;)Ljava/lang/Object;",true);

//      if (method == null) {
//        try {
//          method = Payload2.class.getDeclaredMethod("getField", String.class);
//        } catch (Exception e) {}
//      }
//      String descriptor = codeflow.lastDescriptor();
//      String memberDeclaringClassSlashedDescriptor = method.getDeclaringClass().getName().replace('.','/');
//      if (descriptor == null) {
//        codeflow.loadTarget(mv);
//      }
//      if (descriptor == null || !memberDeclaringClassSlashedDescriptor.equals(descriptor.substring(1))) {
//        mv.visitTypeInsn(CHECKCAST, memberDeclaringClassSlashedDescriptor);
//      }
//      mv.visitLdcInsn(propertyReference.getName());
//      mv.visitMethodInsn(INVOKEVIRTUAL, memberDeclaringClassSlashedDescriptor, method.getName(),CodeFlow.createDescriptor(method));
//         6:  invokeinterface  #6,  2; //InterfaceMethod java/util/Map.get:(Ljava/lang/Object;)Ljava/lang/Object;
    }
  }


  /**
   * Exception thrown from {@code read} in order to reset a cached
   * PropertyAccessor, allowing other accessors to have a try.
   */
  @SuppressWarnings("serial")
  private static class MapAccessException extends AccessException {

    private final String key;

    public MapAccessException(String key) {
      super(null);
      this.key = key;
    }

    @Override
    public String getMessage() {
      return "Map does not contain a value for key '" + this.key + "'";
    }
  }

 
  // helpers

  private SpelNodeImpl getAst() {
    SpelExpression spelExpression = (SpelExpression)expression;
    SpelNode ast = spelExpression.getAST();
    return (SpelNodeImpl)ast;
  }

  private String stringify(Object object) {
    StringBuilder s = new StringBuilder();
    if (object instanceof List) {
      List<?> ls = (List<?>)object;
      for (Object l: ls) {
        s.append(l);
        s.append(" ");
      }
    }
    else if (object instanceof Object[]) {
      Object[] os = (Object[])object;
      for (Object o: os) {
        s.append(o);
        s.append(" ");
      }
    }
    else if (object instanceof int[]) {
      int[] is = (int[])object;
      for (int i: is) {
        s.append(i);
        s.append(" ");
      }
    }
    else {
      s.append(object.toString());
    }
    return s.toString().trim();
  }
 
  private void assertCanCompile(Expression expression) {
    assertTrue(SpelCompiler.compile(expression));
  }
 
  private void assertCantCompile(Expression expression) {
    assertFalse(SpelCompiler.compile(expression));
  }
 
  private Expression parse(String expression) {
    return parser.parseExpression(expression);
  }
 
  private void assertGetValueFail(Expression expression) {
    try {
      Object o = expression.getValue();
      fail("Calling getValue on the expression should have failed but returned "+o);
    } catch (Exception ex) {
      // success!
    }
  }
 
  // test classes
   
  public static class Payload {
    Two[] DR = new Two[]{new Two()};
    public Two holder = new Two();
   
    public Two[] getDR() {
      return DR;
    }
  }
 
  public static class Payload2 {
    String var1 = "abc";
    String var2 = "def";
    public Object getField(String name) {
      if (name.equals("var1")) {
        return var1;
      } else if (name.equals("var2")) {
        return var2;
      }
      return null;
    }
  }

  public static class Payload2Holder {
    public Payload2 payload2 = new Payload2();
  }
 
  public static class Two {
    Three three = new Three();
    public Three getThree() {
      return three;
    }
    public String toString() {
      return "instanceof Two";
    }
  }
 
  public static class Three {
    double four = 0.04d;
    public double getFour() {
      return four;
    }
  }

  public static class TestClass1 {
    public int index1 = 1;
    public int index2 = 3;
    public String word = "abcd";   
  }
 
  public static class TestClass4 {
    public boolean a,b;
    public boolean gettrue() { return true; }
    public boolean getfalse() { return false; }
    public boolean getA() { return a; }
    public boolean getB() { return b; }
  }
 
  public static class TestClass10 {
    public String s = null;
   
    public void reset() {
      s = null;
    }
   
    public void concat(String arg) {
      s = "::"+arg;
    }

    public void concat(String... vargs) {
      if (vargs==null) {
        s = "";
      }
      else {
        s = "";
        for (String varg: vargs) {
          s+=varg;
        }
      }
    }
   
    public void concat2(Object arg) {
      s = "::"+arg;
    }

    public void concat2(Object... vargs) {
      if (vargs==null) {
        s = "";
      }
      else {
        s = "";
        for (Object varg: vargs) {
          s+=varg;
        }
      }
    }
  }
 
  public static class TestClass5 {
    public int i = 0;
    public String s = null;
    public static int _i = 0;
    public static String _s = null;
   
    public static short s1 = (short)1;
    public static short s2 = (short)2;
    public static short s3 = (short)3;

    public static long l1 = 1L;
    public static long l2 = 2L;
    public static long l3 = 3L;

    public static float f1 = 1f;
    public static float f2 = 2f;
    public static float f3 = 3f;

    public static char c1 = 'a';
    public static char c2 = 'b';
    public static char c3 = 'c';
   
    public static byte b1 = (byte)65;
    public static byte b2 = (byte)66;
    public static byte b3 = (byte)67;

    public static String[] stringArray = new String[]{"aaa","bbb","ccc"};
    public static int[] intArray = new int[]{11,22,33};
   
    public Object obj = null;
   
    public String field = null;
   
    public void reset() {
      i = 0;
      _i=0;
      s = null;
      _s = null;
      field = null;
    }
   
    public void one() { i = 1; }
   
    public static void two() { _i = 1; }
   
    public String three() { return "hello"; }
    public long four() { return 3277700L; }

    public static String five() { return "hello"; }
    public static long six() { return 3277700L; }
   
    public void seven(String toset) { s = toset; }
//    public void seven(Number n) { s = n.toString(); }
   
    public void takeNumber(Number n) { s = n.toString(); }
    public void takeString(String s) { this.s = s; }
    public static void eight(String toset) { _s = toset; }
   
    public void nine(int toset) { i = toset; }
    public static void ten(int toset) { _i = toset; }
   
    public void eleven(String... vargs) {
      if (vargs==null) {
        s = "";
      }
      else {
        s = "";
        for (String varg: vargs) {
          s+=varg;
        }
      }
    }
   
    public void twelve(int... vargs) {
      if (vargs==null) {
        i = 0;
      }
      else {
        i = 0;
        for (int varg: vargs) {
          i+=varg;
        }
      }
    }
   
    public void thirteen(String a, String... vargs) {
      if (vargs==null) {
        s = a+"::";
      }
      else {
        s = a+"::";
        for (String varg: vargs) {
          s+=varg;
        }
      }
    }
   
    public void arrayz(boolean... bs) {
      s = "";
      if (bs != null) {
        s = "";
        for (boolean b: bs) {
          s+=Boolean.toString(b);
        }
      }
    }
   
    public void arrays(short... ss) {
      s = "";
      if (ss != null) {
        s = "";
        for (short s: ss) {
          this.s+=Short.toString(s);
        }
      }
    }
   
    public void arrayd(double... vargs) {
      s = "";
      if (vargs != null) {
        s = "";
        for (double v: vargs) {
          this.s+=Double.toString(v);
        }
      }
    }

    public void arrayf(float... vargs) {
      s = "";
      if (vargs != null) {
        s = "";
        for (float v: vargs) {
          this.s+=Float.toString(v);
        }
      }
    }

    public void arrayj(long... vargs) {
      s = "";
      if (vargs != null) {
        s = "";
        for (long v: vargs) {
          this.s+=Long.toString(v);
        }
      }
    }

    public void arrayb(byte... vargs) {
      s = "";
      if (vargs != null) {
        s = "";
        for (Byte v: vargs) {
          this.s+=Byte.toString(v);
        }
      }
    }
   
    public void arrayc(char... vargs) {
      s = "";
      if (vargs != null) {
        s = "";
        for (char v: vargs) {
          this.s+=Character.toString(v);
        }
      }
    }

    public void fourteen(String a, String[]... vargs) {
      if (vargs==null) {
        s = a+"::";
      }
      else {
        s = a+"::";
        for (String[] varg: vargs) {
          s+="{";
          for (String v: varg) {
            s+=v;           
          }
          s+="}";
        }
      }
    }
   
    public void fifteen(String a, int[]... vargs) {
      if (vargs==null) {
        s = a+"::";
      }
      else {
        s = a+"::";
        for (int[] varg: vargs) {
          s+="{";
          for (int v: varg) {
            s+=Integer.toString(v);           
          }
          s+="}";
        }
      }
    }
   
    public void sixteen(Object... vargs) {
      if (vargs==null) {
        s = "";
      }
      else {
        s = "";
        for (Object varg: vargs) {
          s+=varg;
        }
      }
    }
   
  }
 
  public static class TestClass6 {
    public String orange = "value1";
    public static String apple = "value2";
   
    public long peach = 34L;
   
    public String getBanana() {
      return "value3";
    }

    public static String getPlum() {
      return "value4";
    }
  }
 
  public static class TestClass7 {
    public static String property;
    static {
      String s = "UK 123";
      StringTokenizer st = new StringTokenizer(s);
      property = st.nextToken();
    }
   
    public static void reset() {
      String s = "UK 123";
      StringTokenizer st = new StringTokenizer(s);
      property = st.nextToken();
    }
   
  }

  public static class TestClass8 {
    public int i;
    public String s;
    public double d;
    public boolean z;
   
    public TestClass8(int i, String s, double d, boolean z) {
      this.i = i;
      this.s = s;
      this.d = d;
      this.z = z;
    }
   
    public TestClass8() {
     
    }
   
    public TestClass8(Integer i) {
      this.i = i;
    }
   
    @SuppressWarnings("unused")
    private TestClass8(String a, String b) {
      this.s = a+b;
    }
  }

    public static class Obj {
        private final String param1;
        public Obj(String param1){
            this.param1 = param1;
        }
    }

    public static class Obj2 {
        public final String output;
        public Obj2(String... params){
          StringBuilder b = new StringBuilder();
          for (String param: params) {
            b.append(param);
          }
          output = b.toString();
        }
    }

    public static class Obj3 {
        public final String output;
        public Obj3(int... params) {
          StringBuilder b = new StringBuilder();
          for (int param: params) {
            b.append(Integer.toString(param));
          }
          output = b.toString();
        }
       
        public Obj3(String s, Float f, int... ints) {
          StringBuilder b = new StringBuilder();
          b.append(s);
          b.append(":");
          b.append(Float.toString(f));
          b.append(":");
          for (int param: ints) {
            b.append(Integer.toString(param));
          }
          output = b.toString();
        }
    }
   
    public static class Obj4 {
      
        public final String output;
        public Obj4(int[] params) {
          StringBuilder b = new StringBuilder();
          for (int param: params) {
            b.append(Integer.toString(param));
          }
          output = b.toString();
        }
    }
 
  @SuppressWarnings("unused")
  private static class TestClass9 {
    public TestClass9(int i) {}
  }
 
  // These test classes simulate a pattern of public/private classes seen in Spring Security
 
  // final class HttpServlet3RequestFactory implements HttpServletRequestFactory
  static class HttpServlet3RequestFactory {
 
    static Servlet3SecurityContextHolderAwareRequestWrapper getOne() {
      HttpServlet3RequestFactory outer = new HttpServlet3RequestFactory();
      return outer.new Servlet3SecurityContextHolderAwareRequestWrapper();
    }
    // private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper
    private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper {
    }
  }
 
  // public class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper
  static class SecurityContextHolderAwareRequestWrapper extends HttpServletRequestWrapper {
  }
 
  public static class HttpServletRequestWrapper {
    public String getServletPath() {
      return "wibble";
    }
  }
 
  // Here the declaring class is not public
  static class SomeCompareMethod {

    // method not public
    static int compare(Object o1, Object o2) {
      return -1;
    }

    // public
    public static int compare2(Object o1, Object o2) {
      return -1;
    }
  }
 
  public static class SomeCompareMethod2 {
    public static int negate(int i1) {
      return -i1;
    }

    public static String append(String... strings) {
      StringBuilder b = new StringBuilder();
      for (String string: strings) {
        b.append(string);
      }
      return b.toString();
    }
   
    public static String append2(Object... objects) {
      StringBuilder b = new StringBuilder();
      for (Object object: objects) {
        b.append(object.toString());
      }
      return b.toString();
    }
   
    public static String append3(String[] strings) {
      StringBuilder b = new StringBuilder();
      for (String string: strings) {
        b.append(string);
      }
      return b.toString();
    }
   
    public static String append4(String s, String... strings) {
      StringBuilder b = new StringBuilder();
      b.append(s).append("::");
      for (String string: strings) {
        b.append(string);
      }
      return b.toString();
    }

    public static String appendChar(char... values) {
      StringBuilder b = new StringBuilder();
      for (char ch: values) {
        b.append(ch);
      }
      return b.toString();
    }
   
    public static int sum(int... ints) {
      int total = 0;
      for (int i: ints) {
        total+=i;
      }
      return total;
    }

    public static int sumDouble(double... values) {
      int total = 0;
      for (double i: values) {
        total+=i;
      }
      return total;
    }

    public static int sumFloat(float... values) {
      int total = 0;
      for (float i: values) {
        total+=i;
      }
      return total;
    }

  }
 
  public static class DelegatingStringFormat {
    public static String format(String s, Object... args) {
      return String.format(s, args);
    }
  }
   
}
TOP

Related Classes of org.springframework.expression.spel.SpelCompilationCoverageTests$SomeCompareMethod2

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.
ew');