/*
* 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);
}
}
}