Merge pull request #113 from aclement/SPR-9613
* SPR-9613: Support case-insensitive null literals in SpEL
This commit is contained in:
commit
3fbcebb82e
|
|
@ -513,7 +513,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private boolean maybeEatNullReference() {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
Token nullToken = peekToken();
|
||||
if (!nullToken.stringValue().equals("null")) {
|
||||
if (!nullToken.stringValue().toLowerCase().equals("null")) {
|
||||
return false;
|
||||
}
|
||||
nextToken();
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2012 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.
|
||||
|
|
@ -16,12 +16,13 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import junit.framework.Assert;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
|
|
@ -38,6 +39,7 @@ import org.springframework.expression.spel.testresources.TestPerson;
|
|||
*
|
||||
* @author Andy Clement
|
||||
* @author Mark Fisher
|
||||
* @author Sam Brannen
|
||||
* @since 3.0
|
||||
*/
|
||||
public class EvaluationTests extends ExpressionTestCase {
|
||||
|
|
@ -49,62 +51,53 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
TestClass testClass = new TestClass();
|
||||
Object o = null;
|
||||
o = expression.getValue(new StandardEvaluationContext(testClass));
|
||||
Assert.assertEquals("",o);
|
||||
assertEquals("", o);
|
||||
o = parser.parseExpression("list[3]").getValue(new StandardEvaluationContext(testClass));
|
||||
Assert.assertEquals("",o);
|
||||
Assert.assertEquals(4, testClass.list.size());
|
||||
assertEquals("", o);
|
||||
assertEquals(4, testClass.list.size());
|
||||
try {
|
||||
o = parser.parseExpression("list2[3]").getValue(new StandardEvaluationContext(testClass));
|
||||
Assert.fail();
|
||||
fail();
|
||||
} catch (EvaluationException ee) {
|
||||
ee.printStackTrace();
|
||||
// success!
|
||||
}
|
||||
o = parser.parseExpression("foo[3]").getValue(new StandardEvaluationContext(testClass));
|
||||
Assert.assertEquals("",o);
|
||||
Assert.assertEquals(4, testClass.getFoo().size());
|
||||
assertEquals("", o);
|
||||
assertEquals(4, testClass.getFoo().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateMapsOnAttemptToIndexNull01() throws EvaluationException, ParseException {
|
||||
@Test(expected = SpelEvaluationException.class)
|
||||
public void testCreateMapsOnAttemptToIndexNull01() throws Exception {
|
||||
TestClass testClass = new TestClass();
|
||||
StandardEvaluationContext ctx = new StandardEvaluationContext(testClass);
|
||||
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
|
||||
Object o = null;
|
||||
o = parser.parseExpression("map['a']").getValue(ctx);
|
||||
Assert.assertNull(o);
|
||||
assertNull(o);
|
||||
o = parser.parseExpression("map").getValue(ctx);
|
||||
Assert.assertNotNull(o);
|
||||
assertNotNull(o);
|
||||
|
||||
try {
|
||||
o = parser.parseExpression("map2['a']").getValue(ctx);
|
||||
// fail!
|
||||
Assert.fail("map2 should be null, there is no setter");
|
||||
} catch (Exception e) {
|
||||
// success!
|
||||
}
|
||||
// map2 should be null, there is no setter
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateObjectsOnAttemptToReferenceNull() throws EvaluationException, ParseException {
|
||||
// wibble2 should be null (cannot be initialized dynamically), there is no setter
|
||||
@Test(expected = SpelEvaluationException.class)
|
||||
public void testCreateObjectsOnAttemptToReferenceNull() throws Exception {
|
||||
TestClass testClass = new TestClass();
|
||||
StandardEvaluationContext ctx = new StandardEvaluationContext(testClass);
|
||||
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
|
||||
Object o = null;
|
||||
o = parser.parseExpression("wibble.bar").getValue(ctx);
|
||||
Assert.assertEquals("hello",o);
|
||||
assertEquals("hello", o);
|
||||
o = parser.parseExpression("wibble").getValue(ctx);
|
||||
Assert.assertNotNull(o);
|
||||
assertNotNull(o);
|
||||
|
||||
try {
|
||||
o = parser.parseExpression("wibble2.bar").getValue(ctx);
|
||||
// fail!
|
||||
Assert.fail("wibble2 should be null (cannot be initialized dynamically), there is no setter");
|
||||
} catch (Exception e) {
|
||||
// success!
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class TestClass {
|
||||
|
||||
public Foo wibble;
|
||||
|
|
@ -114,11 +107,10 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
public List<String> list;
|
||||
public List list2;
|
||||
private Map map2;
|
||||
private List<String> foo;
|
||||
|
||||
public Map getMap2() { return this.map2; }
|
||||
public Foo getWibble2() { return this.wibble2; }
|
||||
// public void setMap2(Map m) { this.map2 = m; }
|
||||
private List<String> foo;
|
||||
public List<String> getFoo() { return this.foo; }
|
||||
public void setFoo(List<String> newfoo) { this.foo = newfoo; }
|
||||
}
|
||||
|
|
@ -128,6 +120,7 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
public String bar = "hello";
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testElvis01() {
|
||||
evaluate("'Andy'?:'Dave'", "Andy", String.class);
|
||||
|
|
@ -234,16 +227,15 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
public void testRogueTrailingDotCausesNPE_SPR6866() {
|
||||
try {
|
||||
new SpelExpressionParser().parseExpression("placeOfBirth.foo.");
|
||||
Assert.fail("Should have failed to parse");
|
||||
fail("Should have failed to parse");
|
||||
} catch (ParseException e) {
|
||||
Assert.assertTrue(e instanceof SpelParseException);
|
||||
assertTrue(e instanceof SpelParseException);
|
||||
SpelParseException spe = (SpelParseException) e;
|
||||
Assert.assertEquals(SpelMessage.OOD,spe.getMessageCode());
|
||||
Assert.assertEquals(16,spe.getPosition());
|
||||
assertEquals(SpelMessage.OOD, spe.getMessageCode());
|
||||
assertEquals(16, spe.getPosition());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// nested properties
|
||||
@Test
|
||||
public void testPropertiesNested01() {
|
||||
|
|
@ -259,10 +251,10 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
public void testPropertiesNested03() throws ParseException {
|
||||
try {
|
||||
new SpelExpressionParser().parseRaw("placeOfBirth.23");
|
||||
Assert.fail();
|
||||
fail();
|
||||
} catch (SpelParseException spe) {
|
||||
Assert.assertEquals(spe.getMessageCode(), SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
|
||||
Assert.assertEquals("23", spe.getInserts()[0]);
|
||||
assertEquals(spe.getMessageCode(), SpelMessage.UNEXPECTED_DATA_AFTER_DOT);
|
||||
assertEquals("23", spe.getInserts()[0]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -293,15 +285,15 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
// repeated evaluation to drive use of cached executor
|
||||
SpelExpression expr = (SpelExpression) parser.parseExpression("new String('wibble')");
|
||||
String newString = expr.getValue(String.class);
|
||||
Assert.assertEquals("wibble",newString);
|
||||
assertEquals("wibble", newString);
|
||||
newString = expr.getValue(String.class);
|
||||
Assert.assertEquals("wibble",newString);
|
||||
assertEquals("wibble", newString);
|
||||
|
||||
// not writable
|
||||
Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
|
||||
// ast
|
||||
Assert.assertEquals("new String('wibble')",expr.toStringAST());
|
||||
assertEquals("new String('wibble')", expr.toStringAST());
|
||||
}
|
||||
|
||||
// unary expressions
|
||||
|
|
@ -368,13 +360,14 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
|
||||
@Test
|
||||
public void testTernaryOperator03() {
|
||||
evaluateAndCheckError("'hello'?1:2", SpelMessage.TYPE_CONVERSION_ERROR); // cannot convert String to boolean
|
||||
// cannot convert String to boolean
|
||||
evaluateAndCheckError("'hello'?1:2", SpelMessage.TYPE_CONVERSION_ERROR);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTernaryOperator04() throws Exception {
|
||||
Expression expr = parser.parseExpression("1>2?3:4");
|
||||
Assert.assertFalse(expr.isWritable(eContext));
|
||||
assertFalse(expr.isWritable(eContext));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -397,7 +390,8 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
|
||||
@Test
|
||||
public void ctorCallWithRootReferenceThroughParameter() {
|
||||
evaluate("new org.springframework.expression.spel.testresources.PlaceOfBirth(inventions[0].toString()).city", "Telephone repeater", String.class);
|
||||
evaluate("new org.springframework.expression.spel.testresources.PlaceOfBirth(inventions[0].toString()).city",
|
||||
"Telephone repeater", String.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -415,10 +409,10 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
evaluate("'christian'[8]", "n", String.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexerError() {
|
||||
evaluateAndCheckError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
|
||||
evaluateAndCheckError("new org.springframework.expression.spel.testresources.Inventor().inventions[1]",
|
||||
SpelMessage.CANNOT_INDEX_INTO_NULL_VALUE);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -451,12 +445,12 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
@Test
|
||||
public void testTypeReferencesAndQualifiedIdentifierCaching() throws Exception {
|
||||
SpelExpression expr = (SpelExpression) parser.parseExpression("T(java.lang.String)");
|
||||
Assert.assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
Assert.assertEquals("T(java.lang.String)",expr.toStringAST());
|
||||
Assert.assertEquals(String.class,expr.getValue(Class.class));
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
assertEquals("T(java.lang.String)", expr.toStringAST());
|
||||
assertEquals(String.class, expr.getValue(Class.class));
|
||||
// use cached QualifiedIdentifier:
|
||||
Assert.assertEquals("T(java.lang.String)",expr.toStringAST());
|
||||
Assert.assertEquals(String.class,expr.getValue(Class.class));
|
||||
assertEquals("T(java.lang.String)", expr.toStringAST());
|
||||
assertEquals(String.class, expr.getValue(Class.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -490,49 +484,50 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
evaluateAndAskForReturnType("3*4+5", "17", String.class);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAdvancedNumerics() throws Exception {
|
||||
int twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Integer.class);
|
||||
Assert.assertEquals(24,twentyFour);
|
||||
assertEquals(24, twentyFour);
|
||||
double one = parser.parseExpression("8.0 / 5e0 % 2").getValue(Double.class);
|
||||
Assert.assertEquals(1.6d,one);
|
||||
assertEquals(1.6d, one, 0);
|
||||
int o = parser.parseExpression("8.0 / 5e0 % 2").getValue(Integer.class);
|
||||
Assert.assertEquals(1,o);
|
||||
assertEquals(1, o);
|
||||
int sixteen = parser.parseExpression("-2 ^ 4").getValue(Integer.class);
|
||||
Assert.assertEquals(16,sixteen);
|
||||
assertEquals(16, sixteen);
|
||||
int minusFortyFive = parser.parseExpression("1+2-3*8^2/2/2").getValue(Integer.class);
|
||||
Assert.assertEquals(-45,minusFortyFive);
|
||||
assertEquals(-45, minusFortyFive);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testComparison() throws Exception {
|
||||
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
|
||||
boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context, Boolean.class);
|
||||
Assert.assertTrue(trueValue);
|
||||
boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context,
|
||||
Boolean.class);
|
||||
assertTrue(trueValue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolvingList() throws Exception {
|
||||
StandardEvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
|
||||
try {
|
||||
Assert.assertFalse(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
|
||||
Assert.fail("should have failed to find List");
|
||||
assertFalse(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
|
||||
fail("should have failed to find List");
|
||||
} catch (EvaluationException ee) {
|
||||
// success - List not found
|
||||
}
|
||||
((StandardTypeLocator) context.getTypeLocator()).registerImport("java.util");
|
||||
Assert.assertTrue(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
|
||||
assertTrue(parser.parseExpression("T(List)!=null").getValue(context, Boolean.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResolvingString() throws Exception {
|
||||
Class stringClass = parser.parseExpression("T(String)").getValue(Class.class);
|
||||
Assert.assertEquals(String.class,stringClass);
|
||||
Class<?> stringClass = parser.parseExpression("T(String)").getValue(Class.class);
|
||||
assertEquals(String.class, stringClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* SPR-6984: attempting to index a collection on write using an index that doesn't currently exist in the collection (address.crossStreets[0] below)
|
||||
* SPR-6984: attempting to index a collection on write using an index that
|
||||
* doesn't currently exist in the collection (address.crossStreets[0] below)
|
||||
*/
|
||||
@Test
|
||||
public void initializingCollectionElementsOnWrite() throws Exception {
|
||||
|
|
@ -542,20 +537,38 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
ExpressionParser parser = new SpelExpressionParser(config);
|
||||
Expression expression = parser.parseExpression("name");
|
||||
expression.setValue(context, "Oleg");
|
||||
Assert.assertEquals("Oleg",person.getName());
|
||||
assertEquals("Oleg", person.getName());
|
||||
|
||||
expression = parser.parseExpression("address.street");
|
||||
expression.setValue(context, "123 High St");
|
||||
Assert.assertEquals("123 High St",person.getAddress().getStreet());
|
||||
assertEquals("123 High St", person.getAddress().getStreet());
|
||||
|
||||
expression = parser.parseExpression("address.crossStreets[0]");
|
||||
expression.setValue(context, "Blah");
|
||||
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
|
||||
assertEquals("Blah", person.getAddress().getCrossStreets().get(0));
|
||||
|
||||
expression = parser.parseExpression("address.crossStreets[3]");
|
||||
expression.setValue(context, "Wibble");
|
||||
Assert.assertEquals("Blah",person.getAddress().getCrossStreets().get(0));
|
||||
Assert.assertEquals("Wibble",person.getAddress().getCrossStreets().get(3));
|
||||
assertEquals("Blah", person.getAddress().getCrossStreets().get(0));
|
||||
assertEquals("Wibble", person.getAddress().getCrossStreets().get(3));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies behavior requested in SPR-9613.
|
||||
*/
|
||||
@Test
|
||||
public void caseInsensitiveNullLiterals() {
|
||||
ExpressionParser parser = new SpelExpressionParser();
|
||||
Expression exp;
|
||||
|
||||
exp = parser.parseExpression("null");
|
||||
assertNull(exp.getValue());
|
||||
|
||||
exp = parser.parseExpression("NULL");
|
||||
assertNull(exp.getValue());
|
||||
|
||||
exp = parser.parseExpression("NuLl");
|
||||
assertNull(exp.getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ Changes in version 3.2 M2 (2012-08-xx)
|
|||
* spring-test module now depends on junit:junit-dep (SPR-6966)
|
||||
* now inferring return type of parameterized factory methods (SPR-9493)
|
||||
* SpEL Tokenizer now supports methods on integers (SPR-9612)
|
||||
* introduced support for case-insensitive null literals in SpEL expressions (SPR-9613)
|
||||
* now using BufferedInputStream in SimpleMetaDataReader to double performance (SPR-9528)
|
||||
* introduced "repeatCount" property in Quartz SimpleTriggerFactoryBean (SPR-9521)
|
||||
* introduced "jtaTransactionManager" property in Hibernate 4 LocalSessionFactoryBean/Builder (SPR-9480)
|
||||
|
|
|
|||
Loading…
Reference in New Issue