Package org.springframework.expression.spel

Source Code of org.springframework.expression.spel.SpelReproTests$Message

/*
* Copyright 2002-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.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.atomic.AtomicInteger;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import org.springframework.core.MethodParameter;
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.ExpressionException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.MethodExecutor;
import org.springframework.expression.MethodResolver;
import org.springframework.expression.ParserContext;
import org.springframework.expression.PropertyAccessor;
import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.standard.SpelExpression;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
import org.springframework.expression.spel.support.ReflectivePropertyAccessor;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.expression.spel.support.StandardTypeLocator;
import org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver;

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

/**
* Reproduction tests cornering various SpEL JIRA issues.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Clark Duplichien
* @author Phillip Webb
* @author Sam Brannen
*/
public class SpelReproTests extends AbstractExpressionTests {

  @Rule
  public ExpectedException thrown = ExpectedException.none();


  @Test
  public void NPE_SPR5661() {
    evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
  }

  @Test
  public void SWF1086() {
    evaluate("printDouble(T(java.math.BigDecimal).valueOf(14.35))", "14.35", String.class);
  }

  @Test
  public void doubleCoercion() {
    evaluate("printDouble(14.35)", "14.35", String.class);
  }

  @Test
  public void doubleArrayCoercion() {
    evaluate("printDoubles(getDoublesAsStringList())", "{14.35, 15.45}", String.class);
  }

  @Test
  public void SPR5899() throws Exception {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Spr5899Class());
    Expression expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull(12)");
    assertEquals(12, expr.getValue(eContext));
    expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull(null)");
    assertEquals(null, expr.getValue(eContext));
    try {
      expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull2(null)");
      expr.getValue();
      fail("Should have failed to find a method to which it could pass null");
    }
    catch (EvaluationException see) {
      // success
    }
    eContext.setTypeLocator(new MyTypeLocator());

    // varargs
    expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull3(null,'a','b')");
    assertEquals("ab", expr.getValue(eContext));

    // varargs 2 - null is packed into the varargs
    expr = new SpelExpressionParser().parseRaw("tryToInvokeWithNull3(12,'a',null,'c')");
    assertEquals("anullc", expr.getValue(eContext));

    // check we can find the ctor ok
    expr = new SpelExpressionParser().parseRaw("new Spr5899Class().toString()");
    assertEquals("instance", expr.getValue(eContext));

    expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null).toString()");
    assertEquals("instance", expr.getValue(eContext));

    // ctor varargs
    expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null,'a','b').toString()");
    assertEquals("instance", expr.getValue(eContext));

    // ctor varargs 2
    expr = new SpelExpressionParser().parseRaw("new Spr5899Class(null,'a', null, 'b').toString()");
    assertEquals("instance", expr.getValue(eContext));
  }


  static class MyTypeLocator extends StandardTypeLocator {

    @Override
    public Class<?> findType(String typeName) throws EvaluationException {
      if (typeName.equals("Spr5899Class")) {
        return Spr5899Class.class;
      }
      if (typeName.equals("Outer")) {
        return Outer.class;
      }
      return super.findType(typeName);
    }
  }


  static class Spr5899Class {

    public Spr5899Class() {
    }

    public Spr5899Class(Integer i) {
    }

    public Spr5899Class(Integer i, String... s) {
    }

    public Integer tryToInvokeWithNull(Integer value) {
      return value;
    }

    public Integer tryToInvokeWithNull2(int i) {
      return new Integer(i);
    }

    public String tryToInvokeWithNull3(Integer value, String... strings) {
      StringBuilder sb = new StringBuilder();
      for (String string : strings) {
        if (string == null) {
          sb.append("null");
        }
        else {
          sb.append(string);
        }
      }
      return sb.toString();
    }

    @Override
    public String toString() {
      return "instance";
    }
  }


  @Test
  public void SPR5905_InnerTypeReferences() throws Exception {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Spr5899Class());
    Expression expr = new SpelExpressionParser().parseRaw("T(java.util.Map$Entry)");
    assertEquals(Map.Entry.class, expr.getValue(eContext));

    expr = new SpelExpressionParser().parseRaw("T(org.springframework.expression.spel.SpelReproTests$Outer$Inner).run()");
    assertEquals(12, expr.getValue(eContext));

    expr = new SpelExpressionParser().parseRaw("new org.springframework.expression.spel.SpelReproTests$Outer$Inner().run2()");
    assertEquals(13, expr.getValue(eContext));
  }


  static class Outer {

    static class Inner {

      public Inner() {
      }

      public static int run() {
        return 12;
      }

      public int run2() {
        return 13;
      }
    }
  }


  @Test
  public void SPR5804() throws Exception {
    Map<String, String> m = new HashMap<String, String>();
    m.put("foo", "bar");
    StandardEvaluationContext eContext = new StandardEvaluationContext(m); // root is a map instance
    eContext.addPropertyAccessor(new MapAccessor());
    Expression expr = new SpelExpressionParser().parseRaw("['foo']");
    assertEquals("bar", expr.getValue(eContext));
  }

  @Test
  public void SPR5847() throws Exception {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new TestProperties());
    String name = null;
    Expression expr = null;

    expr = new SpelExpressionParser().parseRaw("jdbcProperties['username']");
    name = expr.getValue(eContext, String.class);
    assertEquals("Dave", name);

    expr = new SpelExpressionParser().parseRaw("jdbcProperties[username]");
    name = expr.getValue(eContext, String.class);
    assertEquals("Dave", name);

    // MapAccessor required for this to work
    expr = new SpelExpressionParser().parseRaw("jdbcProperties.username");
    eContext.addPropertyAccessor(new MapAccessor());
    name = expr.getValue(eContext, String.class);
    assertEquals("Dave", name);

    // --- dotted property names

    // lookup foo on the root, then bar on that, then use that as the key into
    // jdbcProperties
    expr = new SpelExpressionParser().parseRaw("jdbcProperties[foo.bar]");
    eContext.addPropertyAccessor(new MapAccessor());
    name = expr.getValue(eContext, String.class);
    assertEquals("Dave2", name);

    // key is foo.bar
    expr = new SpelExpressionParser().parseRaw("jdbcProperties['foo.bar']");
    eContext.addPropertyAccessor(new MapAccessor());
    name = expr.getValue(eContext, String.class);
    assertEquals("Elephant", name);
  }


  static class TestProperties {

    public Properties jdbcProperties = new Properties();
    public Properties foo = new Properties();

    TestProperties() {
      jdbcProperties.put("username", "Dave");
      jdbcProperties.put("alias", "Dave2");
      jdbcProperties.put("foo.bar", "Elephant");
      foo.put("bar", "alias");
    }
  }


  static class MapAccessor implements PropertyAccessor {

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

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

    @Override
    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
      return new TypedValue(((Map<?, ?>) target).get(name));
    }

    @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>) target).put(name, newValue);
    }
  }


  @Test
  public void NPE_SPR5673() throws Exception {
    ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT;
    ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT;

    checkTemplateParsing("abc${'def'} ghi", "abcdef ghi");

    checkTemplateParsingError("abc${ {}( 'abc'", "Missing closing ')' for '(' at position 8");
    checkTemplateParsingError("abc${ {}[ 'abc'", "Missing closing ']' for '[' at position 8");
    checkTemplateParsingError("abc${ {}{ 'abc'", "Missing closing '}' for '{' at position 8");
    checkTemplateParsingError("abc${ ( 'abc' }", "Found closing '}' at position 14 but most recent opening is '(' at position 6");
    checkTemplateParsingError("abc${ '... }", "Found non terminating string literal starting at position 6");
    checkTemplateParsingError("abc${ \"... }", "Found non terminating string literal starting at position 6");
    checkTemplateParsingError("abc${ ) }", "Found closing ')' at position 6 without an opening '('");
    checkTemplateParsingError("abc${ ] }", "Found closing ']' at position 6 without an opening '['");
    checkTemplateParsingError("abc${ } }", "No expression defined within delimiter '${}' at character 3");
    checkTemplateParsingError("abc$[ } ]", DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT, "Found closing '}' at position 6 without an opening '{'");

    checkTemplateParsing("abc ${\"def''g}hi\"} jkl", "abc def'g}hi jkl");
    checkTemplateParsing("abc ${'def''g}hi'} jkl", "abc def'g}hi jkl");
    checkTemplateParsing("}", "}");
    checkTemplateParsing("${'hello'} world", "hello world");
    checkTemplateParsing("Hello ${'}'}]", "Hello }]");
    checkTemplateParsing("Hello ${'}'}", "Hello }");
    checkTemplateParsingError("Hello ${ ( ", "No ending suffix '}' for expression starting at character 6: ${ ( ");
    checkTemplateParsingError("Hello ${ ( }", "Found closing '}' at position 11 but most recent opening is '(' at position 9");
    checkTemplateParsing("#{'Unable to render embedded object: File ({#this == 2}'}", hashes, "Unable to render embedded object: File ({#this == 2}");
    checkTemplateParsing("This is the last odd number in the list: ${listOfNumbersUpToTen.$[#this%2==1]}", dollars, "This is the last odd number in the list: 9");
    checkTemplateParsing("Hello ${'here is a curly bracket }'}", dollars, "Hello here is a curly bracket }");
    checkTemplateParsing("He${'${'}llo ${'here is a curly bracket }'}}", dollars, "He${llo here is a curly bracket }}");
    checkTemplateParsing("Hello ${'()()()}{}{}{][]{}{][}[][][}{()()'} World", dollars, "Hello ()()()}{}{}{][]{}{][}[][][}{()() World");
    checkTemplateParsing("Hello ${'inner literal that''s got {[(])]}an escaped quote in it'} World", "Hello inner literal that's got {[(])]}an escaped quote in it World");
    checkTemplateParsingError("Hello ${", "No ending suffix '}' for expression starting at character 6: ${");
  }

  @Test
  public void accessingNullPropertyViaReflection_SPR5663() throws AccessException {
    PropertyAccessor propertyAccessor = new ReflectivePropertyAccessor();
    EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
    assertFalse(propertyAccessor.canRead(context, null, "abc"));
    assertFalse(propertyAccessor.canWrite(context, null, "abc"));
    try {
      propertyAccessor.read(context, null, "abc");
      fail("Should have failed with an AccessException");
    }
    catch (AccessException ae) {
      // success
    }
    try {
      propertyAccessor.write(context, null, "abc", "foo");
      fail("Should have failed with an AccessException");
    }
    catch (AccessException ae) {
      // success
    }
  }

  @Test
  public void nestedProperties_SPR6923() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Foo());
    Expression expr = new SpelExpressionParser().parseRaw("resource.resource.server");
    String name = expr.getValue(eContext, String.class);
    assertEquals("abc", name);
  }


  static class Foo {

    public ResourceSummary resource = new ResourceSummary();
  }


  static class ResourceSummary {

    private final Resource resource;

    ResourceSummary() {
      this.resource = new Resource();
    }

    public Resource getResource() {
      return resource;
    }
  }


  static class Resource {

    public String getServer() {
      return "abc";
    }
  }


  /** Should be accessing Goo.getKey because 'bar' field evaluates to "key" */
  @Test
  public void indexingAsAPropertyAccess_SPR6968_1() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
    String name = null;
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("instance[bar]");
    name = expr.getValue(eContext, String.class);
    assertEquals("hello", name);
    name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
    assertEquals("hello", name);
  }

  /** Should be accessing Goo.getKey because 'bar' variable evaluates to "key" */
  @Test
  public void indexingAsAPropertyAccess_SPR6968_2() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
    eContext.setVariable("bar", "key");
    String name = null;
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("instance[#bar]");
    name = expr.getValue(eContext, String.class);
    assertEquals("hello", name);
    name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
    assertEquals("hello", name);
  }

  /** $ related identifiers */
  @Test
  public void dollarPrefixedIdentifier_SPR7100() {
    Holder h = new Holder();
    StandardEvaluationContext eContext = new StandardEvaluationContext(h);
    eContext.addPropertyAccessor(new MapAccessor());
    h.map.put("$foo", "wibble");
    h.map.put("foo$bar", "wobble");
    h.map.put("foobar$$", "wabble");
    h.map.put("$", "wubble");
    h.map.put("$$", "webble");
    h.map.put("$_$", "tribble");
    String name = null;
    Expression expr = null;

    expr = new SpelExpressionParser().parseRaw("map.$foo");
    name = expr.getValue(eContext, String.class);
    assertEquals("wibble", name);

    expr = new SpelExpressionParser().parseRaw("map.foo$bar");
    name = expr.getValue(eContext, String.class);
    assertEquals("wobble", name);

    expr = new SpelExpressionParser().parseRaw("map.foobar$$");
    name = expr.getValue(eContext, String.class);
    assertEquals("wabble", name);

    expr = new SpelExpressionParser().parseRaw("map.$");
    name = expr.getValue(eContext, String.class);
    assertEquals("wubble", name);

    expr = new SpelExpressionParser().parseRaw("map.$$");
    name = expr.getValue(eContext, String.class);
    assertEquals("webble", name);

    expr = new SpelExpressionParser().parseRaw("map.$_$");
    name = expr.getValue(eContext, String.class);
    assertEquals("tribble", name);
  }

  /** Should be accessing Goo.wibble field because 'bar' variable evaluates to "wibble" */
  @Test
  public void indexingAsAPropertyAccess_SPR6968_3() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new Goo());
    eContext.setVariable("bar", "wibble");
    String name = null;
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("instance[#bar]");
    // will access the field 'wibble' and not use a getter
    name = expr.getValue(eContext, String.class);
    assertEquals("wobble", name);
    name = expr.getValue(eContext, String.class); // will be using the cached accessor this time
    assertEquals("wobble", name);
  }

  /**
   * Should be accessing (setting) Goo.wibble field because 'bar' variable evaluates to
   * "wibble"
   */
  @Test
  public void indexingAsAPropertyAccess_SPR6968_4() {
    Goo g = Goo.instance;
    StandardEvaluationContext eContext = new StandardEvaluationContext(g);
    eContext.setVariable("bar", "wibble");
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("instance[#bar]='world'");
    // will access the field 'wibble' and not use a getter
    expr.getValue(eContext, String.class);
    assertEquals("world", g.wibble);
    expr.getValue(eContext, String.class); // will be using the cached accessor this time
    assertEquals("world", g.wibble);
  }

  /** Should be accessing Goo.setKey field because 'bar' variable evaluates to "key" */
  @Test
  public void indexingAsAPropertyAccess_SPR6968_5() {
    Goo g = Goo.instance;
    StandardEvaluationContext eContext = new StandardEvaluationContext(g);
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("instance[bar]='world'");
    expr.getValue(eContext, String.class);
    assertEquals("world", g.value);
    expr.getValue(eContext, String.class); // will be using the cached accessor this time
    assertEquals("world", g.value);
  }

  @Test
  public void dollars() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("m['$foo']");
    eContext.setVariable("file_name", "$foo");
    assertEquals("wibble", expr.getValue(eContext, String.class));
  }

  @Test
  public void dollars2() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
    Expression expr = null;
    expr = new SpelExpressionParser().parseRaw("m[$foo]");
    eContext.setVariable("file_name", "$foo");
    assertEquals("wibble", expr.getValue(eContext, String.class));
  }


  static class XX {

    public Map<String, String> m;

    public String floo = "bar";

    public XX() {
      m = new HashMap<String, String>();
      m.put("$foo", "wibble");
      m.put("bar", "siddle");
    }
  }


  static class Goo {

    public static Goo instance = new Goo();

    public String bar = "key";

    public String value = null;

    public String wibble = "wobble";

    public String getKey() {
      return "hello";
    }

    public void setKey(String s) {
      value = s;
    }
  }


  static class Holder {

    public Map<String, String> map = new HashMap<String, String>();
  }


  // ---

  private void checkTemplateParsing(String expression, String expectedValue) throws Exception {
    checkTemplateParsing(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedValue);
  }

  private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) throws Exception {
    SpelExpressionParser parser = new SpelExpressionParser();
    Expression expr = parser.parseExpression(expression, context);
    assertEquals(expectedValue, expr.getValue(TestScenarioCreator.getTestEvaluationContext()));
  }

  private void checkTemplateParsingError(String expression, String expectedMessage) throws Exception {
    checkTemplateParsingError(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedMessage);
  }

  private void checkTemplateParsingError(String expression, ParserContext context, String expectedMessage) throws Exception {
    SpelExpressionParser parser = new SpelExpressionParser();
    try {
      parser.parseExpression(expression, context);
      fail("Should have failed with message: " + expectedMessage);
    }
    catch (Exception ex) {
      String message = ex.getMessage();
      if (ex instanceof ExpressionException) {
        message = ((ExpressionException) ex).getSimpleMessage();
      }
      if (!message.equals(expectedMessage)) {
        ex.printStackTrace();
      }
      assertThat(expectedMessage, equalTo(message));
    }
  }


  private static final ParserContext DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
    @Override
    public String getExpressionPrefix() {
      return "$[";
    }
    @Override
    public String getExpressionSuffix() {
      return "]";
    }
    @Override
    public boolean isTemplate() {
      return true;
    }
  };


  static class Foo2 {

    public void execute(String str) {
      System.out.println("Value: " + str);
    }
  }


  static class Message {

    private String payload;

    public String getPayload() {
      return payload;
    }

    public void setPayload(String payload) {
      this.payload = payload;
    }
  }


  // bean resolver tests

  @Test
  public void beanResolution() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
    Expression expr = null;

    // no resolver registered == exception
    try {
      expr = new SpelExpressionParser().parseRaw("@foo");
      assertEquals("custard", expr.getValue(eContext, String.class));
    }
    catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.NO_BEAN_RESOLVER_REGISTERED, see.getMessageCode());
      assertEquals("foo", see.getInserts()[0]);
    }

    eContext.setBeanResolver(new MyBeanResolver());

    // bean exists
    expr = new SpelExpressionParser().parseRaw("@foo");
    assertEquals("custard", expr.getValue(eContext, String.class));

    // bean does not exist
    expr = new SpelExpressionParser().parseRaw("@bar");
    assertEquals(null, expr.getValue(eContext, String.class));

    // bean name will cause AccessException
    expr = new SpelExpressionParser().parseRaw("@goo");
    try {
      assertEquals(null, expr.getValue(eContext, String.class));
    }
    catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.EXCEPTION_DURING_BEAN_RESOLUTION, see.getMessageCode());
      assertEquals("goo", see.getInserts()[0]);
      assertTrue(see.getCause() instanceof AccessException);
      assertTrue(see.getCause().getMessage().startsWith("DONT"));
    }

    // bean exists
    expr = new SpelExpressionParser().parseRaw("@'foo.bar'");
    assertEquals("trouble", expr.getValue(eContext, String.class));

    // bean exists
    try {
      expr = new SpelExpressionParser().parseRaw("@378");
      assertEquals("trouble", expr.getValue(eContext, String.class));
    }
    catch (SpelParseException spe) {
      assertEquals(SpelMessage.INVALID_BEAN_REFERENCE, spe.getMessageCode());
    }
  }


  static class MyBeanResolver implements BeanResolver {

    @Override
    public Object resolve(EvaluationContext context, String beanName) throws AccessException {
      if (beanName.equals("foo")) {
        return "custard";
      }
      else if (beanName.equals("foo.bar")) {
        return "trouble";
      }
      else if (beanName.equals("goo")) {
        throw new AccessException("DONT ASK ME ABOUT GOO");
      }
      return null;
    }
  }


  // end bean resolver tests

  @Test
  public void elvis_SPR7209_1() {
    StandardEvaluationContext eContext = new StandardEvaluationContext(new XX());
    Expression expr = null;

    // Different parts of elvis expression are null
    expr = new SpelExpressionParser().parseRaw("(?:'default')");
    assertEquals("default", expr.getValue());
    expr = new SpelExpressionParser().parseRaw("?:'default'");
    assertEquals("default", expr.getValue());
    expr = new SpelExpressionParser().parseRaw("?:");
    assertEquals(null, expr.getValue());

    // Different parts of ternary expression are null
    try {
      expr = new SpelExpressionParser().parseRaw("(?'abc':'default')");
      expr.getValue(eContext);
      fail();
    }
    catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.TYPE_CONVERSION_ERROR, see.getMessageCode());
    }
    expr = new SpelExpressionParser().parseRaw("(false?'abc':null)");
    assertEquals(null, expr.getValue());

    // Assignment
    try {
      expr = new SpelExpressionParser().parseRaw("(='default')");
      expr.getValue(eContext);
      fail();
    }
    catch (SpelEvaluationException see) {
      assertEquals(SpelMessage.SETVALUE_NOT_SUPPORTED, see.getMessageCode());
    }
  }

  @Test
  public void elvis_SPR7209_2() {
    Expression expr = null;
    // Have empty string treated as null for elvis
    expr = new SpelExpressionParser().parseRaw("?:'default'");
    assertEquals("default", expr.getValue());
    expr = new SpelExpressionParser().parseRaw("\"\"?:'default'");
    assertEquals("default", expr.getValue());
    expr = new SpelExpressionParser().parseRaw("''?:'default'");
    assertEquals("default", expr.getValue());
  }

  @Test
  public void mapOfMap_SPR7244() throws Exception {
    Map<String, Object> map = new LinkedHashMap<String, Object>();
    map.put("uri", "http:");
    Map<String, String> nameMap = new LinkedHashMap<String, String>();
    nameMap.put("givenName", "Arthur");
    map.put("value", nameMap);

    StandardEvaluationContext ctx = new StandardEvaluationContext(map);
    ExpressionParser parser = new SpelExpressionParser();
    String el1 = "#root['value'].get('givenName')";
    Expression exp = parser.parseExpression(el1);
    Object evaluated = exp.getValue(ctx);
    assertEquals("Arthur", evaluated);

    String el2 = "#root['value']['givenName']";
    exp = parser.parseExpression(el2);
    evaluated = exp.getValue(ctx);
    assertEquals("Arthur", evaluated);
  }

  @Test
  public void projectionTypeDescriptors_1() throws Exception {
    StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
    SpelExpressionParser parser = new SpelExpressionParser();
    String el1 = "ls.![#this.equals('abc')]";
    SpelExpression exp = parser.parseRaw(el1);
    List<?> value = (List<?>) exp.getValue(ctx);
    // value is list containing [true,false]
    assertEquals(Boolean.class, value.get(0).getClass());
    TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
    assertEquals(null, evaluated.getElementTypeDescriptor());
  }

  @Test
  public void projectionTypeDescriptors_2() throws Exception {
    StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
    SpelExpressionParser parser = new SpelExpressionParser();
    String el1 = "as.![#this.equals('abc')]";
    SpelExpression exp = parser.parseRaw(el1);
    Object[] value = (Object[]) exp.getValue(ctx);
    // value is array containing [true,false]
    assertEquals(Boolean.class, value[0].getClass());
    TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
    assertEquals(Boolean.class, evaluated.getElementTypeDescriptor().getType());
  }

  @Test
  public void projectionTypeDescriptors_3() throws Exception {
    StandardEvaluationContext ctx = new StandardEvaluationContext(new C());
    SpelExpressionParser parser = new SpelExpressionParser();
    String el1 = "ms.![key.equals('abc')]";
    SpelExpression exp = parser.parseRaw(el1);
    List<?> value = (List<?>) exp.getValue(ctx);
    // value is list containing [true,false]
    assertEquals(Boolean.class, value.get(0).getClass());
    TypeDescriptor evaluated = exp.getValueTypeDescriptor(ctx);
    assertEquals(null, evaluated.getElementTypeDescriptor());
  }


  static class C {

    public List<String> ls;
    public String[] as;
    public Map<String, String> ms;

    C() {
      ls = new ArrayList<String>();
      ls.add("abc");
      ls.add("def");
      as = new String[] { "abc", "def" };
      ms = new HashMap<String, String>();
      ms.put("abc", "xyz");
      ms.put("def", "pqr");
    }
  }


  static class D {

    public String a;

    private D(String s) {
      a = s;
    }

    @Override
    public String toString() {
      return "D(" + a + ")";
    }
  }


  @Test
  public void greaterThanWithNulls_SPR7840() throws Exception {
    List<D> list = new ArrayList<D>();
    list.add(new D("aaa"));
    list.add(new D("bbb"));
    list.add(new D(null));
    list.add(new D("ccc"));
    list.add(new D(null));
    list.add(new D("zzz"));

    StandardEvaluationContext ctx = new StandardEvaluationContext(list);
    SpelExpressionParser parser = new SpelExpressionParser();

    String el1 = "#root.?[a < 'hhh']";
    SpelExpression exp = parser.parseRaw(el1);
    Object value = exp.getValue(ctx);
    assertEquals("[D(aaa), D(bbb), D(null), D(ccc), D(null)]", value.toString());

    String el2 = "#root.?[a > 'hhh']";
    SpelExpression exp2 = parser.parseRaw(el2);
    Object value2 = exp2.getValue(ctx);
    assertEquals("[D(zzz)]", value2.toString());

    // trim out the nulls first
    String el3 = "#root.?[a!=null].?[a < 'hhh']";
    SpelExpression exp3 = parser.parseRaw(el3);
    Object value3 = exp3.getValue(ctx);
    assertEquals("[D(aaa), D(bbb), D(ccc)]", value3.toString());
  }

  /**
   * Test whether {@link ReflectiveMethodResolver} follows Java Method Invocation
   * Conversion order. And more precisely that widening reference conversion is 'higher'
   * than a unboxing conversion.
   */
  @Test
  public void conversionPriority_8224() throws Exception {

    @SuppressWarnings("unused")
    class ConversionPriority1 {
      public int getX(Number i) {
        return 20;
      }
      public int getX(int i) {
        return 10;
      }
    }

    @SuppressWarnings("unused")
    class ConversionPriority2 {
      public int getX(int i) {
        return 10;
      }
      public int getX(Number i) {
        return 20;
      }
    }

    final Integer INTEGER = Integer.valueOf(7);

    EvaluationContext emptyEvalContext = new StandardEvaluationContext();

    List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();
    args.add(TypeDescriptor.forObject(new Integer(42)));

    ConversionPriority1 target = new ConversionPriority1();
    MethodExecutor me = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target, "getX", args);
    // MethodInvoker chooses getX(int i) when passing Integer
    final int actual = (Integer) me.execute(emptyEvalContext, target, new Integer(42)).getValue();
    // Compiler chooses getX(Number i) when passing Integer
    final int compiler = target.getX(INTEGER);
    // Fails!
    assertEquals(compiler, actual);

    ConversionPriority2 target2 = new ConversionPriority2();
    MethodExecutor me2 = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target2, "getX", args);
    // MethodInvoker chooses getX(int i) when passing Integer
    int actual2 = (Integer) me2.execute(emptyEvalContext, target2, new Integer(42)).getValue();
    // Compiler chooses getX(Number i) when passing Integer
    int compiler2 = target2.getX(INTEGER);
    // Fails!
    assertEquals(compiler2, actual2);

  }

  /**
   * Test whether {@link ReflectiveMethodResolver} handles Widening Primitive Conversion. That's passing an 'int' to a
   * method accepting 'long' is ok.
   */
  @Test
  public void wideningPrimitiveConversion_8224() throws Exception {

    class WideningPrimitiveConversion {
      public int getX(long i) {
        return 10;
      }
    }

    final Integer INTEGER_VALUE = Integer.valueOf(7);
    WideningPrimitiveConversion target = new WideningPrimitiveConversion();
    EvaluationContext emptyEvalContext = new StandardEvaluationContext();

    List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();
    args.add(TypeDescriptor.forObject(INTEGER_VALUE));

    MethodExecutor me = new ReflectiveMethodResolver(true).resolve(emptyEvalContext, target, "getX", args);
    final int actual = (Integer) me.execute(emptyEvalContext, target, INTEGER_VALUE).getValue();

    final int compiler = target.getX(INTEGER_VALUE);
    assertEquals(compiler, actual);
  }

  @Test
  public void varargsAndPrimitives_SPR8174() throws Exception {
    EvaluationContext emptyEvalContext = new StandardEvaluationContext();
    List<TypeDescriptor> args = new ArrayList<TypeDescriptor>();

    args.add(TypeDescriptor.forObject(34L));
    ReflectionUtil<Integer> ru = new ReflectionUtil<Integer>();
    MethodExecutor me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "methodToCall", args);

    args.set(0, TypeDescriptor.forObject(23));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, 45);

    args.set(0, TypeDescriptor.forObject(23f));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, 45f);

    args.set(0, TypeDescriptor.forObject(23d));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, 23d);

    args.set(0, TypeDescriptor.forObject((short) 23));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, (short) 23);

    args.set(0, TypeDescriptor.forObject(23L));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, 23L);

    args.set(0, TypeDescriptor.forObject((char) 65));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, (char) 65);

    args.set(0, TypeDescriptor.forObject((byte) 23));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, (byte) 23);

    args.set(0, TypeDescriptor.forObject(true));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "foo", args);
    me.execute(emptyEvalContext, ru, true);

    // trickier:
    args.set(0, TypeDescriptor.forObject(12));
    args.add(TypeDescriptor.forObject(23f));
    me = new ReflectiveMethodResolver().resolve(emptyEvalContext, ru, "bar", args);
    me.execute(emptyEvalContext, ru, 12, 23f);
  }


  public class ReflectionUtil<T extends Number> {

    public Object methodToCall(T param) {
      System.out.println(param + " " + param.getClass());
      return "Object methodToCall(T param)";
    }

    public void foo(int... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(float... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(double... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(short... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(long... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(boolean... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(char... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void foo(byte... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }

    public void bar(int... array) {
      if (array.length == 0) {
        throw new RuntimeException();
      }
    }
  }


  @Test
  public void reservedWords_8228() throws Exception {
    // "DIV","EQ","GE","GT","LE","LT","MOD","NE","NOT"
    @SuppressWarnings("unused")
    class Reserver {
      public Reserver getReserver() {
        return this;
      }
      public String NE = "abc";
      public String ne = "def";

      public int DIV = 1;
      public int div = 3;

      public Map<String, String> m = new HashMap<String, String>();

      Reserver() {
        m.put("NE", "xyz");
      }
    }

    StandardEvaluationContext ctx = new StandardEvaluationContext(new Reserver());
    SpelExpressionParser parser = new SpelExpressionParser();
    String ex = "getReserver().NE";
    SpelExpression exp = parser.parseRaw(ex);
    String value = (String) exp.getValue(ctx);
    assertEquals("abc", value);

    ex = "getReserver().ne";
    exp = parser.parseRaw(ex);
    value = (String) exp.getValue(ctx);
    assertEquals("def", value);

    ex = "getReserver().m[NE]";
    exp = parser.parseRaw(ex);
    value = (String) exp.getValue(ctx);
    assertEquals("xyz", value);

    ex = "getReserver().DIV";
    exp = parser.parseRaw(ex);
    assertEquals(1, exp.getValue(ctx));

    ex = "getReserver().div";
    exp = parser.parseRaw(ex);
    assertEquals(3, exp.getValue(ctx));

    exp = parser.parseRaw("NE");
    assertEquals("abc", exp.getValue(ctx));
  }

  @Test
  public void reservedWordProperties_9862() throws Exception {
    StandardEvaluationContext ctx = new StandardEvaluationContext();
    SpelExpressionParser parser = new SpelExpressionParser();
    SpelExpression expression = parser.parseRaw("T(org.springframework.expression.spel.testresources.le.div.mod.reserved.Reserver).CONST");
    Object value = expression.getValue(ctx);
    assertEquals(value, Reserver.CONST);
  }

  /**
   * We add property accessors in the order:
   * First, Second, Third, Fourth.
   * They are not utilized in this order; preventing a priority or order of operations
   * in evaluation of SPEL expressions for a given context.
   */
  @Test
  public void propertyAccessorOrder_8211() {
    ExpressionParser expressionParser = new SpelExpressionParser();
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new ContextObject());

    evaluationContext.addPropertyAccessor(new TestPropertyAccessor("firstContext"));
    evaluationContext.addPropertyAccessor(new TestPropertyAccessor("secondContext"));
    evaluationContext.addPropertyAccessor(new TestPropertyAccessor("thirdContext"));
    evaluationContext.addPropertyAccessor(new TestPropertyAccessor("fourthContext"));

    assertEquals("first", expressionParser.parseExpression("shouldBeFirst").getValue(evaluationContext));
    assertEquals("second", expressionParser.parseExpression("shouldBeSecond").getValue(evaluationContext));
    assertEquals("third", expressionParser.parseExpression("shouldBeThird").getValue(evaluationContext));
    assertEquals("fourth", expressionParser.parseExpression("shouldBeFourth").getValue(evaluationContext));
  }


  class TestPropertyAccessor implements PropertyAccessor {

    private String mapName;

    public TestPropertyAccessor(String mapName) {
      this.mapName = mapName;
    }

    @SuppressWarnings("unchecked")
    public Map<String, String> getMap(Object target) {
      try {
        Field f = target.getClass().getDeclaredField(mapName);
        return (Map<String, String>) f.get(target);
      }
      catch (Exception ex) {
      }
      return null;
    }

    @Override
    public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException {
      return getMap(target).containsKey(name);
    }

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

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

    @Override
    public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException {
      return new TypedValue(getMap(target).get(name));
    }

    @Override
    public void write(EvaluationContext context, Object target, String name, Object newValue) throws AccessException {
      getMap(target).put(name, (String) newValue);
    }
  }


  class ContextObject {

    public Map<String, String> firstContext = new HashMap<String, String>();
    public Map<String, String> secondContext = new HashMap<String, String>();
    public Map<String, String> thirdContext = new HashMap<String, String>();
    public Map<String, String> fourthContext = new HashMap<String, String>();

    public ContextObject() {
      firstContext.put("shouldBeFirst", "first");
      secondContext.put("shouldBeFirst", "second");
      thirdContext.put("shouldBeFirst", "third");
      fourthContext.put("shouldBeFirst", "fourth");

      secondContext.put("shouldBeSecond", "second");
      thirdContext.put("shouldBeSecond", "third");
      fourthContext.put("shouldBeSecond", "fourth");

      thirdContext.put("shouldBeThird", "third");
      fourthContext.put("shouldBeThird", "fourth");

      fourthContext.put("shouldBeFourth", "fourth");
    }

    public Map<String, String> getFirstContext() {
      return firstContext;
    }

    public Map<String, String> getSecondContext() {
      return secondContext;
    }

    public Map<String, String> getThirdContext() {
      return thirdContext;
    }

    public Map<String, String> getFourthContext() {
      return fourthContext;
    }
  }


  /**
   * Test the ability to subclass the ReflectiveMethodResolver and change how it
   * determines the set of methods for a type.
   */
  @Test
  public void customStaticFunctions_SPR9038() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    List<MethodResolver> methodResolvers = new ArrayList<MethodResolver>();
    methodResolvers.add(new ReflectiveMethodResolver() {
      @Override
      protected Method[] getMethods(Class<?> type) {
        try {
          return new Method[] {
              Integer.class.getDeclaredMethod("parseInt", new Class[] { String.class, Integer.TYPE }) };
        }
        catch (NoSuchMethodException ex) {
          return new Method[0];
        }
      }
    });

    context.setMethodResolvers(methodResolvers);
    Expression expression = parser.parseExpression("parseInt('-FF', 16)");

    Integer result = expression.getValue(context, "", Integer.class);
    assertEquals(-255, result.intValue());
  }

  @Test
  public void array() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = null;
    Object result = null;

    expression = parser.parseExpression("new java.lang.Long[0].class");
    result = expression.getValue(context, "");
    assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());

    expression = parser.parseExpression("T(java.lang.Long[])");
    result = expression.getValue(context, "");
    assertEquals("Equal assertion failed: ", "class [Ljava.lang.Long;", result.toString());

    expression = parser.parseExpression("T(java.lang.String[][][])");
    result = expression.getValue(context, "");
    assertEquals("Equal assertion failed: ", "class [[[Ljava.lang.String;", result.toString());
    assertEquals("T(java.lang.String[][][])", ((SpelExpression) expression).toStringAST());

    expression = parser.parseExpression("new int[0].class");
    result = expression.getValue(context, "");
    assertEquals("Equal assertion failed: ", "class [I", result.toString());

    expression = parser.parseExpression("T(int[][])");
    result = expression.getValue(context, "");
    assertEquals("class [[I", result.toString());
  }

  @Test
  public void SPR9486_floatFunctionResolver() throws Exception {
    Number expectedResult = Math.abs(-10.2f);
    ExpressionParser parser = new SpelExpressionParser();
    SPR9486_FunctionsClass testObject = new SPR9486_FunctionsClass();

    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("abs(-10.2f)");
    Number result = expression.getValue(context, testObject, Number.class);
    assertEquals(expectedResult, result);
  }


  class SPR9486_FunctionsClass {

    public int abs(int value) {
      return Math.abs(value);
    }

    public float abs(float value) {
      return Math.abs(value);
    }
  }


  @Test
  public void SPR9486_addFloatWithDouble() {
    Number expectedNumber = 10.21f + 10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f + 10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_addFloatWithFloat() {
    Number expectedNumber = 10.21f + 10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f + 10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_subtractFloatWithDouble() {
    Number expectedNumber = 10.21f - 10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f - 10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_subtractFloatWithFloat() {
    Number expectedNumber = 10.21f - 10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f - 10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_multiplyFloatWithDouble() {
    Number expectedNumber = 10.21f * 10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f * 10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_multiplyFloatWithFloat() {
    Number expectedNumber = 10.21f * 10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f * 10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatDivideByFloat() {
    Number expectedNumber = -10.21f / -10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f / -10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatDivideByDouble() {
    Number expectedNumber = -10.21f / -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f / -10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatEqFloatUnaryMinus() {
    Boolean expectedResult = -10.21f == -10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f == -10.2f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatEqDoubleUnaryMinus() {
    Boolean expectedResult = -10.21f == -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f == -10.2");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatEqFloat() {
    Boolean expectedResult = 10.215f == 10.2109f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.215f == 10.2109f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatEqDouble() {
    Boolean expectedResult = 10.215f == 10.2109;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.215f == 10.2109");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatNotEqFloat() {
    Boolean expectedResult = 10.215f != 10.2109f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.215f != 10.2109f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatNotEqDouble() {
    Boolean expectedResult = 10.215f != 10.2109;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.215f != 10.2109");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatLessThanFloat() {
    Boolean expectedNumber = -10.21f < -10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f < -10.2f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatLessThanDouble() {
    Boolean expectedNumber = -10.21f < -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f < -10.2");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatLessThanOrEqualFloat() {
    Boolean expectedNumber = -10.21f <= -10.22f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f <= -10.22f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatLessThanOrEqualDouble() {
    Boolean expectedNumber = -10.21f <= -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f <= -10.2");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatGreaterThanFloat() {
    Boolean expectedNumber = -10.21f > -10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f > -10.2f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatGreaterThanDouble() {
    Boolean expectedResult = -10.21f > -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f > -10.2");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatGreaterThanOrEqualFloat() {
    Boolean expectedNumber = -10.21f >= -10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f >= -10.2f");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedNumber, result);
  }

  @Test
  public void SPR9486_floatGreaterThanEqualDouble() {
    Boolean expectedResult = -10.21f >= -10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("-10.21f >= -10.2");
    Boolean result = expression.getValue(context, null, Boolean.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatModulusFloat() {
    Number expectedResult = 10.21f % 10.2f;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f % 10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatModulusDouble() {
    Number expectedResult = 10.21f % 10.2;
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f % 10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatPowerFloat() {
    Number expectedResult = Math.pow(10.21f, -10.2f);
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f ^ -10.2f");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9486_floatPowerDouble() {
    Number expectedResult = Math.pow(10.21f, 10.2);
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression expression = parser.parseExpression("10.21f ^ 10.2");
    Number result = expression.getValue(context, null, Number.class);
    assertEquals(expectedResult, result);
  }

  @Test
  public void SPR9994_bridgeMethods() throws Exception {
    ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Object target = new GenericImplementation();
    TypedValue value = accessor.read(context, target, "property");
    assertEquals(Integer.class, value.getTypeDescriptor().getType());
  }

  @Test
  public void SPR10162_onlyBridgeMethod() throws Exception {
    ReflectivePropertyAccessor accessor = new ReflectivePropertyAccessor();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Object target = new OnlyBridgeMethod();
    TypedValue value = accessor.read(context, target, "property");
    assertEquals(Integer.class, value.getTypeDescriptor().getType());
  }

  @Test
  public void SPR10091_simpleTestValueType() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
    Class<?> valueType = parser.parseExpression("simpleProperty").getValueType(evaluationContext);
    assertNotNull(valueType);
  }

  @Test
  public void SPR10091_simpleTestValue() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
    Object value = parser.parseExpression("simpleProperty").getValue(evaluationContext);
    assertNotNull(value);
  }

  @Test
  public void SPR10091_primitiveTestValueType() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
    Class<?> valueType = parser.parseExpression("primitiveProperty").getValueType(evaluationContext);
    assertNotNull(valueType);
  }

  @Test
  public void SPR10091_primitiveTestValue() {
    ExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext evaluationContext = new StandardEvaluationContext(new BooleanHolder());
    Object value = parser.parseExpression("primitiveProperty").getValue(evaluationContext);
    assertNotNull(value);
  }

  @Test
  public void SPR10146_malformedExpressions() throws Exception {
    doTestSpr10146("/foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("*foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("%foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("<foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146(">foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("&&foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("||foo", "EL1070E:(pos 0): Problem parsing left operand");
    doTestSpr10146("&foo", "EL1069E:(pos 0): missing expected character '&'");
    doTestSpr10146("|foo", "EL1069E:(pos 0): missing expected character '|'");
  }

  private void doTestSpr10146(String expression, String expectedMessage) {
    thrown.expect(SpelParseException.class);
    thrown.expectMessage(expectedMessage);
    new SpelExpressionParser().parseExpression(expression);
  }

  @Test
  public void SPR10125() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext();
    String fromInterface = parser.parseExpression("T(" + StaticFinalImpl1.class.getName() + ").VALUE").getValue(
        context, String.class);
    assertThat(fromInterface, is("interfaceValue"));
    String fromClass = parser.parseExpression("T(" + StaticFinalImpl2.class.getName() + ").VALUE").getValue(
        context, String.class);
    assertThat(fromClass, is("interfaceValue"));
  }

  @Test
  public void SPR10210() throws Exception {
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.setVariable("bridgeExample", new org.springframework.expression.spel.spr10210.D());
    Expression parseExpression = parser.parseExpression("#bridgeExample.bridgeMethod()");
    parseExpression.getValue(context);
  }

  @Test
  public void SPR10328() throws Exception {
    thrown.expect(SpelParseException.class);
    thrown.expectMessage("EL1071E:(pos 2): A required selection expression has not been specified");
    Expression exp = parser.parseExpression("$[]");
    exp.getValue(Arrays.asList("foo", "bar", "baz"));
  }

  @Test
  public void SPR10452() throws Exception {
    SpelParserConfiguration configuration = new SpelParserConfiguration(false, false);
    ExpressionParser parser = new SpelExpressionParser(configuration);

    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression spel = parser.parseExpression("#enumType.values()");

    context.setVariable("enumType", ABC.class);
    Object result = spel.getValue(context);
    assertNotNull(result);
    assertTrue(result.getClass().isArray());
    assertEquals(ABC.A, Array.get(result, 0));
    assertEquals(ABC.B, Array.get(result, 1));
    assertEquals(ABC.C, Array.get(result, 2));

    context.setVariable("enumType", XYZ.class);
    result = spel.getValue(context);
    assertNotNull(result);
    assertTrue(result.getClass().isArray());
    assertEquals(XYZ.X, Array.get(result, 0));
    assertEquals(XYZ.Y, Array.get(result, 1));
    assertEquals(XYZ.Z, Array.get(result, 2));
  }

  @Test
  public void SPR9495() throws Exception {
    SpelParserConfiguration configuration = new SpelParserConfiguration(false, false);
    ExpressionParser parser = new SpelExpressionParser(configuration);

    StandardEvaluationContext context = new StandardEvaluationContext();
    Expression spel = parser.parseExpression("#enumType.values()");

    context.setVariable("enumType", ABC.class);
    Object result = spel.getValue(context);
    assertNotNull(result);
    assertTrue(result.getClass().isArray());
    assertEquals(ABC.A, Array.get(result, 0));
    assertEquals(ABC.B, Array.get(result, 1));
    assertEquals(ABC.C, Array.get(result, 2));

    context.addMethodResolver(new MethodResolver() {
      @Override
      public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
          List<TypeDescriptor> argumentTypes) throws AccessException {
        return new MethodExecutor() {
          @Override
          public TypedValue execute(EvaluationContext context, Object target, Object... arguments)
              throws AccessException {
            try {
              Method method = XYZ.class.getMethod("values");
              Object value = method.invoke(target, arguments);
              return new TypedValue(value, new TypeDescriptor(new MethodParameter(method, -1)).narrow(value));
            }
            catch (Exception ex) {
              throw new AccessException(ex.getMessage(), ex);
            }
          }
        };
      }
    });
    result = spel.getValue(context);
    assertNotNull(result);
    assertTrue(result.getClass().isArray());
    assertEquals(XYZ.X, Array.get(result, 0));
    assertEquals(XYZ.Y, Array.get(result, 1));
    assertEquals(XYZ.Z, Array.get(result, 2));
  }

  @Test
  public void SPR10486() throws Exception {
    SpelExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Spr10486 rootObject = new Spr10486();
    Expression classNameExpression = parser.parseExpression("class.name");
    Expression nameExpression = parser.parseExpression("name");
    assertThat(classNameExpression.getValue(context, rootObject), equalTo((Object) Spr10486.class.getName()));
    assertThat(nameExpression.getValue(context, rootObject), equalTo((Object) "name"));
  }

  @Test
  public void SPR11142() throws Exception {
    SpelExpressionParser parser = new SpelExpressionParser();
    StandardEvaluationContext context = new StandardEvaluationContext();
    Spr11142 rootObject = new Spr11142();
    Expression expression = parser.parseExpression("something");
    thrown.expect(SpelEvaluationException.class);
    thrown.expectMessage("'something' cannot be found");
    expression.getValue(context, rootObject);
  }

  @Test
  public void SPR9194() {
    TestClass2 one = new TestClass2("abc");
    TestClass2 two = new TestClass2("abc");
    Map<String, TestClass2> map = new HashMap<String, TestClass2>();
    map.put("one", one);
    map.put("two", two);

    SpelExpressionParser parser = new SpelExpressionParser();
    Expression expr = parser.parseExpression("['one'] == ['two']");
    assertTrue(expr.getValue(map, Boolean.class));
  }

  @Test
  public void SPR11348() {
    Collection<String> coll = new LinkedHashSet<String>();
    coll.add("one");
    coll.add("two");
    coll = Collections.unmodifiableCollection(coll);

    SpelExpressionParser parser = new SpelExpressionParser();
    Expression expr = parser.parseExpression("new java.util.ArrayList(#root)");
    Object value = expr.getValue(coll);
    assertTrue(value instanceof ArrayList);
    @SuppressWarnings("rawtypes")
    ArrayList list = (ArrayList) value;
    assertEquals("one", list.get(0));
    assertEquals("two", list.get(1));
  }

  @Test
  public void SPR11445_simple() {
    StandardEvaluationContext context = new StandardEvaluationContext(new Spr11445Class());
    Expression expr = new SpelExpressionParser().parseRaw("echo(parameter())");
    assertEquals(1, expr.getValue(context));
  }

  @Test
  public void SPR11445_beanReference() {
    StandardEvaluationContext context = new StandardEvaluationContext();
    context.setBeanResolver(new Spr11445Class());
    Expression expr = new SpelExpressionParser().parseRaw("@bean.echo(@bean.parameter())");
    assertEquals(1, expr.getValue(context));
  }

  @Test
  @SuppressWarnings("unchecked")
  public void SPR11494() {
    Expression exp = new SpelExpressionParser().parseExpression("T(java.util.Arrays).asList('a','b')");
    List<String> list = (List<String>) exp.getValue();
    assertThat(list.size(), is(2));
  }

  @Test
  public void SPR11609() {
    StandardEvaluationContext sec = new StandardEvaluationContext();
    sec.addPropertyAccessor(new MapAccessor());
    Expression exp = new SpelExpressionParser().parseExpression(
        "T(org.springframework.expression.spel.SpelReproTests$MapWithConstant).X");
    assertEquals(1, exp.getValue(sec));
  }

  @Test
  public void SPR9735() {
    Item item = new Item();
    item.setName("parent");

    Item item1 = new Item();
    item1.setName("child1");

    Item item2 = new Item();
    item2.setName("child2");

    item.add(item1);
    item.add(item2);

    ExpressionParser parser = new SpelExpressionParser();
    EvaluationContext context = new StandardEvaluationContext();
    Expression exp = parser.parseExpression("#item[0].name");
    context.setVariable("item", item);

    assertEquals("child1", exp.getValue(context));
  }


  private static enum ABC { A, B, C }

  private static enum XYZ { X, Y, Z }


  public static class BooleanHolder {

    private Boolean simpleProperty = true;

    private boolean primitiveProperty = true;

    public void setSimpleProperty(Boolean simpleProperty) {
      this.simpleProperty = simpleProperty;
    }

    public Boolean isSimpleProperty() {
      return this.simpleProperty;
    }

    public void setPrimitiveProperty(boolean primitiveProperty) {
      this.primitiveProperty = primitiveProperty;
    }

    public boolean isPrimitiveProperty() {
      return this.primitiveProperty;
    }
  }


  private static interface GenericInterface<T extends Number> {

    public T getProperty();
  }


  private static class GenericImplementation implements GenericInterface<Integer> {

    @Override
    public Integer getProperty() {
      return null;
    }
  }


  static class PackagePrivateClassWithGetter {

    public Integer getProperty() {
      return null;
    }
  }


  public static class OnlyBridgeMethod extends PackagePrivateClassWithGetter {
  }


  public static interface StaticFinal {

    public static final String VALUE = "interfaceValue";
  }


  public abstract static class AbstractStaticFinal implements StaticFinal {
  }


  public static class StaticFinalImpl1 extends AbstractStaticFinal implements StaticFinal {
  }


  public static class StaticFinalImpl2 extends AbstractStaticFinal {
  }


  public static class Spr10486 {

    private String name = "name";

    public void setName(String name) {
      this.name = name;
    }

    public String getName() {
      return this.name;
    }
  }


  static class Spr11142 {

    public String isSomething() {
      return "";
    }
  }


  static class TestClass2 // SPR-9194

    String string;

    public TestClass2(String string) {
      this.string = string;
    }

    public boolean equals(Object other) {
      return (this == other || (other instanceof TestClass2 &&
          this.string.equals(((TestClass2) other).string)));
    }

    @Override
    public int hashCode() {
      return this.string.hashCode();
    }
  }


  static class Spr11445Class implements BeanResolver {

    private final AtomicInteger counter = new AtomicInteger();

    public int echo(int invocation) {
      return invocation;
    }

    public int parameter() {
      return this.counter.incrementAndGet();
    }

    @Override
    public Object resolve(EvaluationContext context, String beanName) throws AccessException {
      return (beanName.equals("bean") ? this : null);
    }
  }


  @SuppressWarnings({ "rawtypes", "serial" })
  public static class MapWithConstant extends HashMap {

    public static final int X = 1;
  }


  public class Item implements List<Item> {

    private String name;

    private List<Item> children = new ArrayList<Item>();

    public void setName(String name) {
      this.name = name;
    }

    public String getName() {
      return this.name;
    }

    @Override
    public int size() {
      return this.children.size();
    }

    @Override
    public boolean isEmpty() {
      return this.children.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
      return this.children.contains(o);
    }

    @Override
    public Iterator<Item> iterator() {
      return this.children.iterator();
    }

    @Override
    public Object[] toArray() {
      return this.children.toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
      return this.children.toArray(a);
    }

    @Override
    public boolean add(Item e) {
      return this.children.add(e);
    }

    @Override
    public boolean remove(Object o) {
      return this.children.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
      return this.children.containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends Item> c) {
      return this.children.addAll(c);
    }

    @Override
    public boolean addAll(int index, Collection<? extends Item> c) {
      return this.children.addAll(index, c);
    }

    @Override
    public boolean removeAll(Collection<?> c) {
      return this.children.removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
      return this.children.retainAll(c);
    }

    @Override
    public void clear() {
      this.children.clear();
    }

    @Override
    public Item get(int index) {
      return this.children.get(index);
    }

    @Override
    public Item set(int index, Item element) {
      return this.children.set(index, element);
    }

    @Override
    public void add(int index, Item element) {
      this.children.add(index, element);
    }

    @Override
    public Item remove(int index) {
      return this.children.remove(index);
    }

    @Override
    public int indexOf(Object o) {
      return this.children.indexOf(o);
    }

    @Override
    public int lastIndexOf(Object o) {
      return this.children.lastIndexOf(o);
    }

    @Override
    public ListIterator<Item> listIterator() {
      return this.children.listIterator();
    }

    @Override
    public ListIterator<Item> listIterator(int index) {
      return this.children.listIterator(index);
    }

    @Override
    public List<Item> subList(int fromIndex, int toIndex) {
      return this.children.subList(fromIndex, toIndex);
    }
  }

}
TOP

Related Classes of org.springframework.expression.spel.SpelReproTests$Message

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.