Package org.springframework.expression.spel

Source Code of org.springframework.expression.spel.EvaluationTests$MyBeanResolver

/*
* Copyright 2002-2013 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.lang.reflect.Method;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.AccessException;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodFilter;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.ParseException;
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.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.TestPerson;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;

/**
* Tests the evaluation of real expressions in a real context.
*
* @author Andy Clement
* @author Mark Fisher
* @author Sam Brannen
* @author Phillip Webb
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
public class EvaluationTests extends AbstractExpressionTests {

  @Test
  public void testCreateListsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression expression = parser.parseExpression("list[0]");
    TestClass testClass = new TestClass();
    Object o = null;
    o = expression.getValue(new StandardEvaluationContext(testClass));
    assertEquals("", o);
    o = parser.parseExpression("list[3]").getValue(new StandardEvaluationContext(testClass));
    assertEquals("", o);
    assertEquals(4, testClass.list.size());
    try {
      o = parser.parseExpression("list2[3]").getValue(new StandardEvaluationContext(testClass));
      fail();
    } catch (EvaluationException ee) {
      ee.printStackTrace();
      // success!
    }
    o = parser.parseExpression("foo[3]").getValue(new StandardEvaluationContext(testClass));
    assertEquals("", o);
    assertEquals(4, testClass.getFoo().size());
  }

  @Test(expected = SpelEvaluationException.class)
  public void testCreateMapsOnAttemptToIndexNull01() throws Exception {
    TestClass testClass = new TestClass();
    StandardEvaluationContext ctx = new StandardEvaluationContext(testClass);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Object o = null;
    o = parser.parseExpression("map['a']").getValue(ctx);
    assertNull(o);
    o = parser.parseExpression("map").getValue(ctx);
    assertNotNull(o);

    o = parser.parseExpression("map2['a']").getValue(ctx);
    // map2 should be null, there is no setter
  }

  // wibble2 should be null (cannot be initialized dynamically), there is no setter
  @Test(expected = SpelEvaluationException.class)
  public void testCreateObjectsOnAttemptToReferenceNull() throws Exception {
    TestClass testClass = new TestClass();
    StandardEvaluationContext ctx = new StandardEvaluationContext(testClass);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Object o = null;
    o = parser.parseExpression("wibble.bar").getValue(ctx);
    assertEquals("hello", o);
    o = parser.parseExpression("wibble").getValue(ctx);
    assertNotNull(o);

    o = parser.parseExpression("wibble2.bar").getValue(ctx);
  }


  @SuppressWarnings("rawtypes")
  static class TestClass {
    public Foo wibble;
    private Foo wibble2;
    public Map map;
    public Map<String, Integer> mapStringToInteger;
    public List<String> list;
    public List list2;
    private Map map2;
    private List<String> foo;

    public Map getMap2() { return this.map2; }
    public Foo getWibble2() { return this.wibble2; }
    public List<String> getFoo() { return this.foo; }
    public void setFoo(List<String> newfoo) { this.foo = newfoo; }
  }

  public static class Foo {
    public Foo() {}
    public String bar = "hello";
  }


  @Test
  public void testElvis01() {
    evaluate("'Andy'?:'Dave'", "Andy", String.class);
    evaluate("null?:'Dave'", "Dave", String.class);
  }

  @Test
  public void testSafeNavigation() {
    evaluate("null?.null?.null", null, null);
  }

  @Test
  public void testRelOperatorGT01() {
    evaluate("3 > 6", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorLT01() {
    evaluate("3 < 6", "true", Boolean.class);
  }

  @Test
  public void testRelOperatorLE01() {
    evaluate("3 <= 6", "true", Boolean.class);
  }

  @Test
  public void testRelOperatorGE01() {
    evaluate("3 >= 6", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorGE02() {
    evaluate("3 >= 3", "true", Boolean.class);
  }

  @Test
  public void testRelOperatorsInstanceof01() {
    evaluate("'xyz' instanceof T(int)", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorsInstanceof04() {
    evaluate("null instanceof T(String)", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorsInstanceof05() {
    evaluate("null instanceof T(Integer)", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorsInstanceof06() {
    evaluateAndCheckError("'A' instanceof null", SpelMessage.INSTANCEOF_OPERATOR_NEEDS_CLASS_OPERAND, 15, "null");
  }

  @Test
  public void testRelOperatorsMatches01() {
    evaluate("'5.0067' matches '^-?\\d+(\\.\\d{2})?$'", "false", Boolean.class);
  }

  @Test
  public void testRelOperatorsMatches02() {
    evaluate("'5.00' matches '^-?\\d+(\\.\\d{2})?$'", "true", Boolean.class);
  }

  @Test
  public void testRelOperatorsMatches03() {
    evaluateAndCheckError("null matches '^.*$'", SpelMessage.INVALID_FIRST_OPERAND_FOR_MATCHES_OPERATOR, 0, null);
  }

  @Test
  public void testRelOperatorsMatches04() {
    evaluateAndCheckError("'abc' matches null", SpelMessage.INVALID_SECOND_OPERAND_FOR_MATCHES_OPERATOR, 14, null);
  }

  @Test
  public void testRelOperatorsMatches05() {
    evaluate("27 matches '^.*2.*$'", true, Boolean.class); // conversion int>string
  }

  // mixing operators
  @Test
  public void testMixingOperators01() {
    evaluate("true and 5>3", "true", Boolean.class);
  }

  // property access
  @Test
  public void testPropertyField01() {
    evaluate("name", "Nikola Tesla", String.class, false);
    // not writable because (1) name is private (2) there is no setter, only a getter
    evaluateAndCheckError("madeup", SpelMessage.PROPERTY_OR_FIELD_NOT_READABLE, 0, "madeup",
      "org.springframework.expression.spel.testresources.Inventor");
  }

  @Test
  public void testPropertyField02_SPR7100() {
    evaluate("_name", "Nikola Tesla", String.class);
    evaluate("_name_", "Nikola Tesla", String.class);
  }

  @Test
  public void testRogueTrailingDotCausesNPE_SPR6866() {
    try {
      new SpelExpressionParser().parseExpression("placeOfBirth.foo.");
      fail("Should have failed to parse");
    } catch (ParseException e) {
      assertTrue(e instanceof SpelParseException);
      SpelParseException spe = (SpelParseException) e;
      assertEquals(SpelMessage.OOD, spe.getMessageCode());
      assertEquals(16, spe.getPosition());
    }
  }

  // nested properties
  @Test
  public void testPropertiesNested01() {
    evaluate("placeOfBirth.city", "SmilJan", String.class, true);
  }

  @Test
  public void testPropertiesNested02() {
    evaluate("placeOfBirth.doubleIt(12)", "24", Integer.class);
  }

  @Test
  public void testPropertiesNested03() throws ParseException {
    try {
      new SpelExpressionParser().parseRaw("placeOfBirth.23");
      fail();
    } catch (SpelParseException spe) {
      assertEquals(spe.getMessageCode(), SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
      assertEquals("23", spe.getInserts()[0]);
    }
  }

  // methods
  @Test
  public void testMethods01() {
    evaluate("echo(12)", "12", String.class);
  }

  @Test
  public void testMethods02() {
    evaluate("echo(name)", "Nikola Tesla", String.class);
  }

  // constructors
  @Test
  public void testConstructorInvocation01() {
    evaluate("new String('hello')", "hello", String.class);
  }

  @Test
  public void testConstructorInvocation05() {
    evaluate("new java.lang.String('foobar')", "foobar", String.class);
  }

  @Test
  public void testConstructorInvocation06() throws Exception {
    // repeated evaluation to drive use of cached executor
    SpelExpression expr = (SpelExpression) parser.parseExpression("new String('wibble')");
    String newString = expr.getValue(String.class);
    assertEquals("wibble", newString);
    newString = expr.getValue(String.class);
    assertEquals("wibble", newString);

    // not writable
    assertFalse(expr.isWritable(new StandardEvaluationContext()));

    // ast
    assertEquals("new String('wibble')", expr.toStringAST());
  }

  // unary expressions
  @Test
  public void testUnaryMinus01() {
    evaluate("-5", "-5", Integer.class);
  }

  @Test
  public void testUnaryPlus01() {
    evaluate("+5", "5", Integer.class);
  }

  @Test
  public void testUnaryNot01() {
    evaluate("!true", "false", Boolean.class);
  }

  @Test
  public void testUnaryNot02() {
    evaluate("!false", "true", Boolean.class);
  }

  @Test(expected = EvaluationException.class)
  public void testUnaryNotWithNullValue() {
    parser.parseExpression("!null").getValue();
  }

  @Test(expected = EvaluationException.class)
  public void testAndWithNullValueOnLeft() {
    parser.parseExpression("null and true").getValue();
  }

  @Test(expected = EvaluationException.class)
  public void testAndWithNullValueOnRight() {
    parser.parseExpression("true and null").getValue();
  }

  @Test(expected = EvaluationException.class)
  public void testOrWithNullValueOnLeft() {
    parser.parseExpression("null or false").getValue();
  }

  @Test(expected = EvaluationException.class)
  public void testOrWithNullValueOnRight() {
    parser.parseExpression("false or null").getValue();
  }

  // assignment
  @Test
  public void testAssignmentToVariables01() {
    evaluate("#var1='value1'", "value1", String.class);
  }

  @Test
  public void testTernaryOperator01() {
    evaluate("2>4?1:2", 2, Integer.class);
  }

  @Test
  public void testTernaryOperator02() {
    evaluate("'abc'=='abc'?1:2", 1, Integer.class);
  }

  @Test
  public void testTernaryOperator03() {
    // cannot convert String to boolean
    evaluateAndCheckError("'hello'?1:2", SpelMessage.TYPE_CONVERSION_ERROR);
  }

  @Test
  public void testTernaryOperator04() throws Exception {
    Expression expr = parser.parseExpression("1>2?3:4");
    assertFalse(expr.isWritable(eContext));
  }

  @Test
  public void testTernaryOperator05() {
    evaluate("1>2?#var=4:#var=5", 5, Integer.class);
    evaluate("3?:#var=5", 3, Integer.class);
    evaluate("null?:#var=5", 5, Integer.class);
    evaluate("2>4?(3>2?true:false):(5<3?true:false)", false, Boolean.class);
  }

  @Test(expected = EvaluationException.class)
  public void testTernaryOperatorWithNullValue() {
    parser.parseExpression("null ? 0 : 1").getValue();
  }

  @Test
  public void methodCallWithRootReferenceThroughParameter() {
    evaluate("placeOfBirth.doubleIt(inventions.length)", 18, Integer.class);
  }

  @Test
  public void ctorCallWithRootReferenceThroughParameter() {
    evaluate("new org.springframework.expression.spel.testresources.PlaceOfBirth(inventions[0].toString()).city",
      "Telephone repeater", String.class);
  }

  @Test
  public void fnCallWithRootReferenceThroughParameter() {
    evaluate("#reverseInt(inventions.length, inventions.length, inventions.length)", "int[3]{9,9,9}", int[].class);
  }

  @Test
  public void methodCallWithRootReferenceThroughParameterThatIsAFunctionCall() {
    evaluate("placeOfBirth.doubleIt(#reverseInt(inventions.length,2,3)[2])", 18, Integer.class);
  }

  @Test
  public void testIndexer03() {
    evaluate("'christian'[8]", "n", String.class);
  }

  @Test
  public void testIndexerError() {
    evaluateAndCheckError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",
      SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
  }

  @Test
  public void testStaticRef02() {
    evaluate("T(java.awt.Color).green.getRGB()!=0", "true", Boolean.class);
  }

  // variables and functions
  @Test
  public void testVariableAccess01() {
    evaluate("#answer", "42", Integer.class, true);
  }

  @Test
  public void testFunctionAccess01() {
    evaluate("#reverseInt(1,2,3)", "int[3]{3,2,1}", int[].class);
  }

  @Test
  public void testFunctionAccess02() {
    evaluate("#reverseString('hello')", "olleh", String.class);
  }

  // type references
  @Test
  public void testTypeReferences01() {
    evaluate("T(java.lang.String)", "class java.lang.String", Class.class);
  }

  @Test
  public void testTypeReferencesAndQualifiedIdentifierCaching() throws Exception {
    SpelExpression expr = (SpelExpression) parser.parseExpression("T(java.lang.String)");
    assertFalse(expr.isWritable(new StandardEvaluationContext()));
    assertEquals("T(java.lang.String)", expr.toStringAST());
    assertEquals(String.class, expr.getValue(Class.class));
    // use cached QualifiedIdentifier:
    assertEquals("T(java.lang.String)", expr.toStringAST());
    assertEquals(String.class, expr.getValue(Class.class));
  }
 
  @Test
  public void operatorVariants() throws Exception {
    SpelExpression expr = (SpelExpression)parser.parseExpression("#a < #b");
    EvaluationContext ctx = new StandardEvaluationContext();
    ctx.setVariable("a", (short)3);
    ctx.setVariable("b", (short)6);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("b", (byte)6);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", (byte)9);
    ctx.setVariable("b", (byte)6);
    assertFalse(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", 10L);
    ctx.setVariable("b", (short)30);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", (byte)3);
    ctx.setVariable("b", (short)30);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", (byte)3);
    ctx.setVariable("b", 30L);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", (byte)3);
    ctx.setVariable("b", 30f);
    assertTrue(expr.getValue(ctx, Boolean.class));
    ctx.setVariable("a", new BigInteger("10"));
    ctx.setVariable("b", new BigInteger("20"));
    assertTrue(expr.getValue(ctx, Boolean.class));
  }

  @Test
  public void testTypeReferencesPrimitive() {
    evaluate("T(int)", "int", Class.class);
    evaluate("T(byte)", "byte", Class.class);
    evaluate("T(char)", "char", Class.class);
    evaluate("T(boolean)", "boolean", Class.class);
    evaluate("T(long)", "long", Class.class);
    evaluate("T(short)", "short", Class.class);
    evaluate("T(double)", "double", Class.class);
    evaluate("T(float)", "float", Class.class);
  }

  @Test
  public void testTypeReferences02() {
    evaluate("T(String)", "class java.lang.String", Class.class);
  }

  @Test
  public void testStringType() {
    evaluateAndAskForReturnType("getPlaceOfBirth().getCity()", "SmilJan", String.class);
  }

  @Test
  public void testNumbers01() {
    evaluateAndAskForReturnType("3*4+5", 17, Integer.class);
    evaluateAndAskForReturnType("3*4+5", 17L, Long.class);
    evaluateAndAskForReturnType("65", 'A', Character.class);
    evaluateAndAskForReturnType("3*4+5", (short) 17, Short.class);
    evaluateAndAskForReturnType("3*4+5", "17", String.class);
  }

  @Test
  public void testAdvancedNumerics() throws Exception {
    int twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Integer.class);
    assertEquals(24, twentyFour);
    double one = parser.parseExpression("8.0 / 5e0 % 2").getValue(Double.class);
    assertEquals(1.6d, one, 0);
    int o = parser.parseExpression("8.0 / 5e0 % 2").getValue(Integer.class);
    assertEquals(1, o);
    int sixteen = parser.parseExpression("-2 ^ 4").getValue(Integer.class);
    assertEquals(16, sixteen);
    int minusFortyFive = parser.parseExpression("1+2-3*8^2/2/2").getValue(Integer.class);
    assertEquals(-45, minusFortyFive);
  }

  @Test
  public void testComparison() throws Exception {
    EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
    boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context,
      Boolean.class);
    assertTrue(trueValue);
  }

  @Test
  public void testResolvingList() throws Exception {
    StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
    try {
      assertFalse(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
      fail("should have failed to find List");
    } catch (EvaluationException ee) {
      // success - List not found
    }
    ((StandardTypeLocator) context.getTypeLocator()).registerImport("java.util");
    assertTrue(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
  }

  @Test
  public void testResolvingString() throws Exception {
    Class<?> stringClass = parser.parseExpression("T(String)").getValue(Class.class);
    assertEquals(String.class, stringClass);
  }

  /**
   * SPR-6984: attempting to index a collection on write using an index that
   * doesn't currently exist in the collection (address.crossStreets[0] below)
   */
  @Test
  public void initializingCollectionElementsOnWrite() throws Exception {
    TestPerson person = new TestPerson();
    EvaluationContext context = new StandardEvaluationContext(person);
    SpelParserConfiguration config = new SpelParserConfiguration(true, true);
    ExpressionParser parser = new SpelExpressionParser(config);
    Expression expression = parser.parseExpression("name");
    expression.setValue(context, "Oleg");
    assertEquals("Oleg", person.getName());

    expression = parser.parseExpression("address.street");
    expression.setValue(context, "123 High St");
    assertEquals("123 High St", person.getAddress().getStreet());

    expression = parser.parseExpression("address.crossStreets[0]");
    expression.setValue(context, "Blah");
    assertEquals("Blah", person.getAddress().getCrossStreets().get(0));

    expression = parser.parseExpression("address.crossStreets[3]");
    expression.setValue(context, "Wibble");
    assertEquals("Blah", person.getAddress().getCrossStreets().get(0));
    assertEquals("Wibble", person.getAddress().getCrossStreets().get(3));
  }

  /**
   * Verifies behavior requested in SPR-9613.
   */
  @Test
  public void caseInsensitiveNullLiterals() {
    ExpressionParser parser = new SpelExpressionParser();
    Expression exp;

    exp = parser.parseExpression("null");
    assertNull(exp.getValue());

    exp = parser.parseExpression("NULL");
    assertNull(exp.getValue());

    exp = parser.parseExpression("NuLl");
    assertNull(exp.getValue());
  }

  /**
   * Verifies behavior requested in SPR-9621.
   */
  @Test
  public void customMethodFilter() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext();

    // Register a custom MethodResolver...
    List<MethodResolver> customResolvers = new ArrayList<MethodResolver>();
    customResolvers.add(new CustomMethodResolver());
    context.setMethodResolvers(customResolvers);

    // or simply...
    // context.setMethodResolvers(new ArrayList<MethodResolver>());

    // Register a custom MethodFilter...
    MethodFilter filter = new CustomMethodFilter();
    try {
      context.registerMethodFilter(String.class, filter);
      fail("should have failed");
    } catch (IllegalStateException ise) {
      assertEquals(
          "Method filter cannot be set as the reflective method resolver is not in use",
          ise.getMessage());
    }
  }

  static class CustomMethodResolver implements MethodResolver {

    @Override
    public MethodExecutor resolve(EvaluationContext context,
        Object targetObject, String name,
        List<TypeDescriptor> argumentTypes) throws AccessException {
      return null;
    }
  }

  static class CustomMethodFilter implements MethodFilter {

    @Override
    public List<Method> filter(List<Method> methods) {
      return null;
    }

  }

  // increment/decrement operators - SPR-9751

  static class Spr9751 {
    public String type = "hello";
    public BigDecimal bd = new BigDecimal("2");
    public double ddd = 2.0d;
    public float fff = 3.0f;
    public long lll = 66666L;
    public int iii = 42;
    public short sss = (short)15;
    public Spr9751_2 foo = new Spr9751_2();

    public void m() {}

    public int[] intArray = new int[]{1,2,3,4,5};
    public int index1 = 2;

    public Integer[] integerArray;
    public int index2 = 2;

    public List<String> listOfStrings;
    public int index3 = 0;

    public Spr9751() {
      integerArray = new Integer[5];
      integerArray[0] = 1;
      integerArray[1] = 2;
      integerArray[2] = 3;
      integerArray[3] = 4;
      integerArray[4] = 5;
      listOfStrings = new ArrayList<String>();
      listOfStrings.add("abc");
    }

    public static boolean isEven(int i) {
      return (i%2)==0;
    }
  }

  static class Spr9751_2 {
    public int iii = 99;
  }

  /**
   * This test is checking that with the changes for 9751 that the refactoring in Indexer is
   * coping correctly for references beyond collection boundaries.
   */
  @Test
  public void collectionGrowingViaIndexer() {
    Spr9751 instance = new Spr9751();

    // Add a new element to the list
    StandardEvaluationContext ctx = new StandardEvaluationContext(instance);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e =  parser.parseExpression("listOfStrings[++index3]='def'");
    e.getValue(ctx);
    assertEquals(2,instance.listOfStrings.size());
    assertEquals("def",instance.listOfStrings.get(1));

    // Check reference beyond end of collection
    ctx = new StandardEvaluationContext(instance);
    parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    e =  parser.parseExpression("listOfStrings[0]");
    String value = e.getValue(ctx,String.class);
    assertEquals("abc",value);
    e =  parser.parseExpression("listOfStrings[1]");
    value = e.getValue(ctx,String.class);
    assertEquals("def",value);
    e =  parser.parseExpression("listOfStrings[2]");
    value = e.getValue(ctx,String.class);
    assertEquals("",value);

    // Now turn off growing and reference off the end
    ctx = new StandardEvaluationContext(instance);
    parser = new SpelExpressionParser(new SpelParserConfiguration(false, false));
    e =  parser.parseExpression("listOfStrings[3]");
    try {
      e.getValue(ctx,String.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.COLLECTION_INDEX_OUT_OF_BOUNDS,see.getMessageCode());
    }
  }

  @Test
  public void limitCollectionGrowing() throws Exception {
    TestClass instance = new TestClass();
    StandardEvaluationContext ctx = new StandardEvaluationContext(instance);
    SpelExpressionParser parser = new SpelExpressionParser( new SpelParserConfiguration(true, true, 3));
    Expression expression = parser.parseExpression("foo[2]");
    expression.setValue(ctx, "2");
    assertThat(instance.getFoo().size(), equalTo(3));
    expression = parser.parseExpression("foo[3]");
    try {
      expression.setValue(ctx, "3");
    } catch(SpelEvaluationException see) {
      assertEquals(SpelMessage.UNABLE_TO_GROW_COLLECTION, see.getMessageCode());
      assertThat(instance.getFoo().size(), equalTo(3));
    }
  }

  // For now I am making #this not assignable
  @Test
  public void increment01root() {
    Integer i = 42;
    StandardEvaluationContext ctx = new StandardEvaluationContext(i);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e =  parser.parseExpression("#this++");
    assertEquals(42,i.intValue());
    try {
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
  }

  @Test
  public void increment02postfix() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    // BigDecimal
    e = parser.parseExpression("bd++");
    assertTrue(new BigDecimal("2").equals(helper.bd));
    BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
    assertTrue(new BigDecimal("2").equals(return_bd));
    assertTrue(new BigDecimal("3").equals(helper.bd));

    // double
    e = parser.parseExpression("ddd++");
    assertEquals(2.0d,helper.ddd,0d);
    double return_ddd = e.getValue(ctx,Double.TYPE);
    assertEquals(2.0d,return_ddd,0d);
    assertEquals(3.0d,helper.ddd,0d);

    // float
    e = parser.parseExpression("fff++");
    assertEquals(3.0f,helper.fff,0d);
    float return_fff = e.getValue(ctx,Float.TYPE);
    assertEquals(3.0f,return_fff,0d);
    assertEquals(4.0f,helper.fff,0d);

    // long
    e = parser.parseExpression("lll++");
    assertEquals(66666L,helper.lll);
    long return_lll = e.getValue(ctx,Long.TYPE);
    assertEquals(66666L,return_lll);
    assertEquals(66667L,helper.lll);

    // int
    e = parser.parseExpression("iii++");
    assertEquals(42,helper.iii);
    int return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,return_iii);
    assertEquals(43,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(43,return_iii);
    assertEquals(44,helper.iii);

    // short
    e = parser.parseExpression("sss++");
    assertEquals(15,helper.sss);
    short return_sss = e.getValue(ctx,Short.TYPE);
    assertEquals(15,return_sss);
    assertEquals(16,helper.sss);
  }

  @Test
  public void increment02prefix() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;


    // BigDecimal
    e = parser.parseExpression("++bd");
    assertTrue(new BigDecimal("2").equals(helper.bd));
    BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
    assertTrue(new BigDecimal("3").equals(return_bd));
    assertTrue(new BigDecimal("3").equals(helper.bd));

    // double
    e = parser.parseExpression("++ddd");
    assertEquals(2.0d,helper.ddd,0d);
    double return_ddd = e.getValue(ctx,Double.TYPE);
    assertEquals(3.0d,return_ddd,0d);
    assertEquals(3.0d,helper.ddd,0d);

    // float
    e = parser.parseExpression("++fff");
    assertEquals(3.0f,helper.fff,0d);
    float return_fff = e.getValue(ctx,Float.TYPE);
    assertEquals(4.0f,return_fff,0d);
    assertEquals(4.0f,helper.fff,0d);

    // long
    e = parser.parseExpression("++lll");
    assertEquals(66666L,helper.lll);
    long return_lll = e.getValue(ctx,Long.TYPE);
    assertEquals(66667L,return_lll);
    assertEquals(66667L,helper.lll);

    // int
    e = parser.parseExpression("++iii");
    assertEquals(42,helper.iii);
    int return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(43,return_iii);
    assertEquals(43,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(44,return_iii);
    assertEquals(44,helper.iii);

    // short
    e = parser.parseExpression("++sss");
    assertEquals(15,helper.sss);
    int return_sss = (Integer)e.getValue(ctx);
    assertEquals(16,return_sss);
    assertEquals(16,helper.sss);
  }

  @Test
  public void increment03() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    e = parser.parseExpression("m()++");
    try {
      e.getValue(ctx,Double.TYPE);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.OPERAND_NOT_INCREMENTABLE,see.getMessageCode());
    }

    e = parser.parseExpression("++m()");
    try {
      e.getValue(ctx,Double.TYPE);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.OPERAND_NOT_INCREMENTABLE,see.getMessageCode());
    }
  }


  @Test
  public void increment04() {
    Integer i = 42;
    StandardEvaluationContext ctx = new StandardEvaluationContext(i);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    try {
      Expression e =  parser.parseExpression("++1");
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
    try {
      Expression e =  parser.parseExpression("1++");
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
  }
  @Test
  public void decrement01root() {
    Integer i = 42;
    StandardEvaluationContext ctx = new StandardEvaluationContext(i);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e =  parser.parseExpression("#this--");
    assertEquals(42,i.intValue());
    try {
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
  }

  @Test
  public void decrement02postfix() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    // BigDecimal
    e = parser.parseExpression("bd--");
    assertTrue(new BigDecimal("2").equals(helper.bd));
    BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
    assertTrue(new BigDecimal("2").equals(return_bd));
    assertTrue(new BigDecimal("1").equals(helper.bd));

    // double
    e = parser.parseExpression("ddd--");
    assertEquals(2.0d,helper.ddd,0d);
    double return_ddd = e.getValue(ctx,Double.TYPE);
    assertEquals(2.0d,return_ddd,0d);
    assertEquals(1.0d,helper.ddd,0d);

    // float
    e = parser.parseExpression("fff--");
    assertEquals(3.0f,helper.fff,0d);
    float return_fff = e.getValue(ctx,Float.TYPE);
    assertEquals(3.0f,return_fff,0d);
    assertEquals(2.0f,helper.fff,0d);

    // long
    e = parser.parseExpression("lll--");
    assertEquals(66666L,helper.lll);
    long return_lll = e.getValue(ctx,Long.TYPE);
    assertEquals(66666L,return_lll);
    assertEquals(66665L,helper.lll);

    // int
    e = parser.parseExpression("iii--");
    assertEquals(42,helper.iii);
    int return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,return_iii);
    assertEquals(41,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(41,return_iii);
    assertEquals(40,helper.iii);

    // short
    e = parser.parseExpression("sss--");
    assertEquals(15,helper.sss);
    short return_sss = e.getValue(ctx,Short.TYPE);
    assertEquals(15,return_sss);
    assertEquals(14,helper.sss);
  }

  @Test
  public void decrement02prefix() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    // BigDecimal
    e = parser.parseExpression("--bd");
    assertTrue(new BigDecimal("2").equals(helper.bd));
    BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
    assertTrue(new BigDecimal("1").equals(return_bd));
    assertTrue(new BigDecimal("1").equals(helper.bd));

    // double
    e = parser.parseExpression("--ddd");
    assertEquals(2.0d,helper.ddd,0d);
    double return_ddd = e.getValue(ctx,Double.TYPE);
    assertEquals(1.0d,return_ddd,0d);
    assertEquals(1.0d,helper.ddd,0d);

    // float
    e = parser.parseExpression("--fff");
    assertEquals(3.0f,helper.fff,0d);
    float return_fff = e.getValue(ctx,Float.TYPE);
    assertEquals(2.0f,return_fff,0d);
    assertEquals(2.0f,helper.fff,0d);

    // long
    e = parser.parseExpression("--lll");
    assertEquals(66666L,helper.lll);
    long return_lll = e.getValue(ctx,Long.TYPE);
    assertEquals(66665L,return_lll);
    assertEquals(66665L,helper.lll);

    // int
    e = parser.parseExpression("--iii");
    assertEquals(42,helper.iii);
    int return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(41,return_iii);
    assertEquals(41,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(40,return_iii);
    assertEquals(40,helper.iii);

    // short
    e = parser.parseExpression("--sss");
    assertEquals(15,helper.sss);
    int return_sss = (Integer)e.getValue(ctx);
    assertEquals(14,return_sss);
    assertEquals(14,helper.sss);
  }

  @Test
  public void decrement03() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    e = parser.parseExpression("m()--");
    try {
      e.getValue(ctx,Double.TYPE);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.OPERAND_NOT_DECREMENTABLE,see.getMessageCode());
    }

    e = parser.parseExpression("--m()");
    try {
      e.getValue(ctx,Double.TYPE);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.OPERAND_NOT_DECREMENTABLE,see.getMessageCode());
    }
  }


  @Test
  public void decrement04() {
    Integer i = 42;
    StandardEvaluationContext ctx = new StandardEvaluationContext(i);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    try {
      Expression e =  parser.parseExpression("--1");
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
    try {
      Expression e =  parser.parseExpression("1--");
      e.getValue(ctx,Integer.class);
      fail();
    } catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NOT_ASSIGNABLE,see.getMessageCode());
    }
  }

  @Test
  public void incdecTogether() {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    // index1 is 2 at the start - the 'intArray[#root.index1++]' should not be evaluated twice!
    // intArray[2] is 3
    e = parser.parseExpression("intArray[#root.index1++]++");
    e.getValue(ctx,Integer.class);
    assertEquals(3,helper.index1);
    assertEquals(4,helper.intArray[2]);

    // index1 is 3 intArray[3] is 4
    e =  parser.parseExpression("intArray[#root.index1++]--");
    assertEquals(4,e.getValue(ctx,Integer.class).intValue());
    assertEquals(4,helper.index1);
    assertEquals(3,helper.intArray[3]);

    // index1 is 4, intArray[3] is 3
    e =  parser.parseExpression("intArray[--#root.index1]++");
    assertEquals(3,e.getValue(ctx,Integer.class).intValue());
    assertEquals(3,helper.index1);
    assertEquals(4,helper.intArray[3]);
  }




  private void expectFail(ExpressionParser parser, EvaluationContext eContext, String expressionString, SpelMessage messageCode) {
    try {
      Expression e = parser.parseExpression(expressionString);
       SpelUtilities.printAbstractSyntaxTree(System.out, e);
      e.getValue(eContext);
      fail();
    } catch (SpelEvaluationException see) {
      see.printStackTrace();
      assertEquals(messageCode,see.getMessageCode());
    }
  }

  private void expectFailNotAssignable(ExpressionParser parser, EvaluationContext eContext, String expressionString) {
    expectFail(parser,eContext,expressionString,SpelMessage.NOT_ASSIGNABLE);
  }

  private void expectFailSetValueNotSupported(ExpressionParser parser, EvaluationContext eContext, String expressionString) {
    expectFail(parser,eContext,expressionString,SpelMessage.SETVALUE_NOT_SUPPORTED);
  }

  private void expectFailNotIncrementable(ExpressionParser parser, EvaluationContext eContext, String expressionString) {
    expectFail(parser,eContext,expressionString,SpelMessage.OPERAND_NOT_INCREMENTABLE);
  }

  private void expectFailNotDecrementable(ExpressionParser parser, EvaluationContext eContext, String expressionString) {
    expectFail(parser,eContext,expressionString,SpelMessage.OPERAND_NOT_DECREMENTABLE);
  }

  // Verify how all the nodes behave with assignment (++, --, =)
  @Test
  public void incrementAllNodeTypes() throws SecurityException, NoSuchMethodException {
    Spr9751 helper = new Spr9751();
    StandardEvaluationContext ctx = new StandardEvaluationContext(helper);
    ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
    Expression e = null;

    // BooleanLiteral
    expectFailNotAssignable(parser, ctx, "true++");
    expectFailNotAssignable(parser, ctx, "--false");
    expectFailSetValueNotSupported(parser, ctx, "true=false");

    // IntLiteral
    expectFailNotAssignable(parser, ctx, "12++");
    expectFailNotAssignable(parser, ctx, "--1222");
    expectFailSetValueNotSupported(parser, ctx, "12=16");

    // LongLiteral
    expectFailNotAssignable(parser, ctx, "1.0d++");
    expectFailNotAssignable(parser, ctx, "--3.4d");
    expectFailSetValueNotSupported(parser, ctx, "1.0d=3.2d");

    // NullLiteral
    expectFailNotAssignable(parser, ctx, "null++");
    expectFailNotAssignable(parser, ctx, "--null");
    expectFailSetValueNotSupported(parser, ctx, "null=null");
    expectFailSetValueNotSupported(parser, ctx, "null=123");

    // OpAnd
    expectFailNotAssignable(parser, ctx, "(true && false)++");
    expectFailNotAssignable(parser, ctx, "--(false AND true)");
    expectFailSetValueNotSupported(parser, ctx, "(true && false)=(false && true)");

    // OpDivide
    expectFailNotAssignable(parser, ctx, "(3/4)++");
    expectFailNotAssignable(parser, ctx, "--(2/5)");
    expectFailSetValueNotSupported(parser, ctx, "(1/2)=(3/4)");

    // OpEq
    expectFailNotAssignable(parser, ctx, "(3==4)++");
    expectFailNotAssignable(parser, ctx, "--(2==5)");
    expectFailSetValueNotSupported(parser, ctx, "(1==2)=(3==4)");

    // OpGE
    expectFailNotAssignable(parser, ctx, "(3>=4)++");
    expectFailNotAssignable(parser, ctx, "--(2>=5)");
    expectFailSetValueNotSupported(parser, ctx, "(1>=2)=(3>=4)");

    // OpGT
    expectFailNotAssignable(parser, ctx, "(3>4)++");
    expectFailNotAssignable(parser, ctx, "--(2>5)");
    expectFailSetValueNotSupported(parser, ctx, "(1>2)=(3>4)");

    // OpLE
    expectFailNotAssignable(parser, ctx, "(3<=4)++");
    expectFailNotAssignable(parser, ctx, "--(2<=5)");
    expectFailSetValueNotSupported(parser, ctx, "(1<=2)=(3<=4)");

    // OpLT
    expectFailNotAssignable(parser, ctx, "(3<4)++");
    expectFailNotAssignable(parser, ctx, "--(2<5)");
    expectFailSetValueNotSupported(parser, ctx, "(1<2)=(3<4)");

    // OpMinus
    expectFailNotAssignable(parser, ctx, "(3-4)++");
    expectFailNotAssignable(parser, ctx, "--(2-5)");
    expectFailSetValueNotSupported(parser, ctx, "(1-2)=(3-4)");

    // OpModulus
    expectFailNotAssignable(parser, ctx, "(3%4)++");
    expectFailNotAssignable(parser, ctx, "--(2%5)");
    expectFailSetValueNotSupported(parser, ctx, "(1%2)=(3%4)");

    // OpMultiply
    expectFailNotAssignable(parser, ctx, "(3*4)++");
    expectFailNotAssignable(parser, ctx, "--(2*5)");
    expectFailSetValueNotSupported(parser, ctx, "(1*2)=(3*4)");

    // OpNE
    expectFailNotAssignable(parser, ctx, "(3!=4)++");
    expectFailNotAssignable(parser, ctx, "--(2!=5)");
    expectFailSetValueNotSupported(parser, ctx, "(1!=2)=(3!=4)");

    // OpOr
    expectFailNotAssignable(parser, ctx, "(true || false)++");
    expectFailNotAssignable(parser, ctx, "--(false OR true)");
    expectFailSetValueNotSupported(parser, ctx, "(true || false)=(false OR true)");

    // OpPlus
    expectFailNotAssignable(parser, ctx, "(3+4)++");
    expectFailNotAssignable(parser, ctx, "--(2+5)");
    expectFailSetValueNotSupported(parser, ctx, "(1+2)=(3+4)");

    // RealLiteral
    expectFailNotAssignable(parser, ctx, "1.0d++");
    expectFailNotAssignable(parser, ctx, "--2.0d");
    expectFailSetValueNotSupported(parser, ctx, "(1.0d)=(3.0d)");
    expectFailNotAssignable(parser, ctx, "1.0f++");
    expectFailNotAssignable(parser, ctx, "--2.0f");
    expectFailSetValueNotSupported(parser, ctx, "(1.0f)=(3.0f)");

    // StringLiteral
    expectFailNotAssignable(parser, ctx, "'abc'++");
    expectFailNotAssignable(parser, ctx, "--'def'");
    expectFailSetValueNotSupported(parser, ctx, "'abc'='def'");

    // Ternary
    expectFailNotAssignable(parser, ctx, "(true?true:false)++");
    expectFailNotAssignable(parser, ctx, "--(true?true:false)");
    expectFailSetValueNotSupported(parser, ctx, "(true?true:false)=(true?true:false)");

    // TypeReference
    expectFailNotAssignable(parser, ctx, "T(String)++");
    expectFailNotAssignable(parser, ctx, "--T(Integer)");
    expectFailSetValueNotSupported(parser, ctx, "T(String)=T(Integer)");

    // OperatorBetween
    expectFailNotAssignable(parser, ctx, "(3 between {1,5})++");
    expectFailNotAssignable(parser, ctx, "--(3 between {1,5})");
    expectFailSetValueNotSupported(parser, ctx, "(3 between {1,5})=(3 between {1,5})");

    // OperatorInstanceOf
    expectFailNotAssignable(parser, ctx, "(type instanceof T(String))++");
    expectFailNotAssignable(parser, ctx, "--(type instanceof T(String))");
    expectFailSetValueNotSupported(parser, ctx, "(type instanceof T(String))=(type instanceof T(String))");

    // Elvis
    expectFailNotAssignable(parser, ctx, "(true?:false)++");
    expectFailNotAssignable(parser, ctx, "--(true?:false)");
    expectFailSetValueNotSupported(parser, ctx, "(true?:false)=(true?:false)");

    // OpInc
    expectFailNotAssignable(parser, ctx, "(iii++)++");
    expectFailNotAssignable(parser, ctx, "--(++iii)");
    expectFailSetValueNotSupported(parser, ctx, "(iii++)=(++iii)");

    // OpDec
    expectFailNotAssignable(parser, ctx, "(iii--)++");
    expectFailNotAssignable(parser, ctx, "--(--iii)");
    expectFailSetValueNotSupported(parser, ctx, "(iii--)=(--iii)");

    // OperatorNot
    expectFailNotAssignable(parser, ctx, "(!true)++");
    expectFailNotAssignable(parser, ctx, "--(!false)");
    expectFailSetValueNotSupported(parser, ctx, "(!true)=(!false)");

    // OperatorPower
    expectFailNotAssignable(parser, ctx, "(iii^2)++");
    expectFailNotAssignable(parser, ctx, "--(iii^2)");
    expectFailSetValueNotSupported(parser, ctx, "(iii^2)=(iii^3)");

    // Assign
    // iii=42
    e = parser.parseExpression("iii=iii++");
    assertEquals(42,helper.iii);
    int return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,helper.iii);
    assertEquals(42,return_iii);

    // Identifier
    e = parser.parseExpression("iii++");
    assertEquals(42,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,return_iii);
    assertEquals(43,helper.iii);

    e = parser.parseExpression("--iii");
    assertEquals(43,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,return_iii);
    assertEquals(42,helper.iii);

    e = parser.parseExpression("iii=99");
    assertEquals(42,helper.iii);
    return_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(99,return_iii);
    assertEquals(99,helper.iii);

    // CompoundExpression
    // foo.iii == 99
    e = parser.parseExpression("foo.iii++");
    assertEquals(99,helper.foo.iii);
    int return_foo_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(99,return_foo_iii);
    assertEquals(100,helper.foo.iii);

    e = parser.parseExpression("--foo.iii");
    assertEquals(100,helper.foo.iii);
    return_foo_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(99,return_foo_iii);
    assertEquals(99,helper.foo.iii);

    e = parser.parseExpression("foo.iii=999");
    assertEquals(99,helper.foo.iii);
    return_foo_iii = e.getValue(ctx,Integer.TYPE);
    assertEquals(999,return_foo_iii);
    assertEquals(999,helper.foo.iii);

    // ConstructorReference
    expectFailNotAssignable(parser, ctx, "(new String('abc'))++");
    expectFailNotAssignable(parser, ctx, "--(new String('abc'))");
    expectFailSetValueNotSupported(parser, ctx, "(new String('abc'))=(new String('abc'))");

    // MethodReference
    expectFailNotIncrementable(parser, ctx, "m()++");
    expectFailNotDecrementable(parser, ctx, "--m()");
    expectFailSetValueNotSupported(parser, ctx, "m()=m()");

    // OperatorMatches
    expectFailNotAssignable(parser, ctx, "('abc' matches '^a..')++");
    expectFailNotAssignable(parser, ctx, "--('abc' matches '^a..')");
    expectFailSetValueNotSupported(parser, ctx, "('abc' matches '^a..')=('abc' matches '^a..')");

    // Selection
    ctx.registerFunction("isEven", Spr9751.class.getDeclaredMethod("isEven", Integer.TYPE));

    expectFailNotIncrementable(parser, ctx, "({1,2,3}.?[#isEven(#this)])++");
    expectFailNotDecrementable(parser, ctx, "--({1,2,3}.?[#isEven(#this)])");
    expectFailNotAssignable(parser, ctx, "({1,2,3}.?[#isEven(#this)])=({1,2,3}.?[#isEven(#this)])");

    // slightly diff here because return value isn't a list, it is a single entity
    expectFailNotAssignable(parser, ctx, "({1,2,3}.^[#isEven(#this)])++");
    expectFailNotAssignable(parser, ctx, "--({1,2,3}.^[#isEven(#this)])");
    expectFailNotAssignable(parser, ctx, "({1,2,3}.^[#isEven(#this)])=({1,2,3}.^[#isEven(#this)])");

    expectFailNotAssignable(parser, ctx, "({1,2,3}.$[#isEven(#this)])++");
    expectFailNotAssignable(parser, ctx, "--({1,2,3}.$[#isEven(#this)])");
    expectFailNotAssignable(parser, ctx, "({1,2,3}.$[#isEven(#this)])=({1,2,3}.$[#isEven(#this)])");

    // FunctionReference
    expectFailNotAssignable(parser, ctx, "#isEven(3)++");
    expectFailNotAssignable(parser, ctx, "--#isEven(4)");
    expectFailSetValueNotSupported(parser, ctx, "#isEven(3)=#isEven(5)");

    // VariableReference
    ctx.setVariable("wibble", "hello world");
    expectFailNotIncrementable(parser, ctx, "#wibble++");
    expectFailNotDecrementable(parser, ctx, "--#wibble");
    e = parser.parseExpression("#wibble=#wibble+#wibble");
    String s = e.getValue(ctx,String.class);
    assertEquals("hello worldhello world",s);
    assertEquals("hello worldhello world",ctx.lookupVariable("wibble"));

    ctx.setVariable("wobble", 3);
    e = parser.parseExpression("#wobble++");
    assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());
    int r = e.getValue(ctx,Integer.TYPE);
    assertEquals(3,r);
    assertEquals(4,((Integer)ctx.lookupVariable("wobble")).intValue());

    e = parser.parseExpression("--#wobble");
    assertEquals(4,((Integer)ctx.lookupVariable("wobble")).intValue());
    r = e.getValue(ctx,Integer.TYPE);
    assertEquals(3,r);
    assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());

    e = parser.parseExpression("#wobble=34");
    assertEquals(3,((Integer)ctx.lookupVariable("wobble")).intValue());
    r = e.getValue(ctx,Integer.TYPE);
    assertEquals(34,r);
    assertEquals(34,((Integer)ctx.lookupVariable("wobble")).intValue());

    // Projection
    expectFailNotIncrementable(parser, ctx, "({1,2,3}.![#isEven(#this)])++"); // projection would be {false,true,false}
    expectFailNotDecrementable(parser, ctx, "--({1,2,3}.![#isEven(#this)])"); // projection would be {false,true,false}
    expectFailNotAssignable(parser, ctx, "({1,2,3}.![#isEven(#this)])=({1,2,3}.![#isEven(#this)])");

    // InlineList
    expectFailNotAssignable(parser, ctx, "({1,2,3})++");
    expectFailNotAssignable(parser, ctx, "--({1,2,3})");
    expectFailSetValueNotSupported(parser, ctx, "({1,2,3})=({1,2,3})");

    // InlineMap
    expectFailNotAssignable(parser, ctx, "({'a':1,'b':2,'c':3})++");
    expectFailNotAssignable(parser, ctx, "--({'a':1,'b':2,'c':3})");
    expectFailSetValueNotSupported(parser, ctx, "({'a':1,'b':2,'c':3})=({'a':1,'b':2,'c':3})");

    // BeanReference
    ctx.setBeanResolver(new MyBeanResolver());
    expectFailNotAssignable(parser, ctx, "@foo++");
    expectFailNotAssignable(parser, ctx, "--@foo");
    expectFailSetValueNotSupported(parser, ctx, "@foo=@bar");

    // PropertyOrFieldReference
    helper.iii = 42;
    e = parser.parseExpression("iii++");
    assertEquals(42,helper.iii);
    r = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,r);
    assertEquals(43,helper.iii);

    e = parser.parseExpression("--iii");
    assertEquals(43,helper.iii);
    r = e.getValue(ctx,Integer.TYPE);
    assertEquals(42,r);
    assertEquals(42,helper.iii);

    e = parser.parseExpression("iii=100");
    assertEquals(42,helper.iii);
    r = e.getValue(ctx,Integer.TYPE);
    assertEquals(100,r);
    assertEquals(100,helper.iii);

  }

  static class MyBeanResolver implements BeanResolver {

    @Override
    public Object resolve(EvaluationContext context, String beanName)
        throws AccessException {
      if (beanName.equals("foo") || beanName.equals("bar")) {
        return new Spr9751_2();
      }
      throw new AccessException("not heard of "+beanName);
    }

  }


}
TOP

Related Classes of org.springframework.expression.spel.EvaluationTests$MyBeanResolver

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.