/* * Copyright 2002-2013 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.expression.spel; import org.junit.Test; import org.springframework.expression.EvaluationContext; import org.springframework.expression.EvaluationException; import org.springframework.expression.Expression; import org.springframework.expression.ParseException; import org.springframework.expression.ParserContext; import org.springframework.expression.common.CompositeStringExpression; import org.springframework.expression.common.TemplateParserContext; import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.support.StandardEvaluationContext; import static org.junit.Assert.*; /** * @author Andy Clement * @author Juergen Hoeller */ public class TemplateExpressionParsingTests extends AbstractExpressionTests { public static final ParserContext DEFAULT_TEMPLATE_PARSER_CONTEXT = new ParserContext() { @Override public String getExpressionPrefix() { return "${"; } @Override public String getExpressionSuffix() { return "}"; } @Override public boolean isTemplate() { return true; } }; public static final ParserContext HASH_DELIMITED_PARSER_CONTEXT = new ParserContext() { @Override public String getExpressionPrefix() { return "#{"; } @Override public String getExpressionSuffix() { return "}"; } @Override public boolean isTemplate() { return true; } }; @Test public void testParsingSimpleTemplateExpression01() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("hello ${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertEquals("hello world", o.toString()); } @Test public void testParsingSimpleTemplateExpression02() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("hello ${'to'} you", DEFAULT_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertEquals("hello to you", o.toString()); } @Test public void testParsingSimpleTemplateExpression03() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("The quick ${'brown'} fox jumped over the ${'lazy'} dog", DEFAULT_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertEquals("The quick brown fox jumped over the lazy dog", o.toString()); } @Test public void testParsingSimpleTemplateExpression04() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); Expression expr = parser.parseExpression("${'hello'} world", DEFAULT_TEMPLATE_PARSER_CONTEXT); Object o = expr.getValue(); assertEquals("hello world", o.toString()); expr = parser.parseExpression("", DEFAULT_TEMPLATE_PARSER_CONTEXT); o = expr.getValue(); assertEquals("", o.toString()); expr = parser.parseExpression("abc", DEFAULT_TEMPLATE_PARSER_CONTEXT); o = expr.getValue(); assertEquals("abc", o.toString()); expr = parser.parseExpression("abc", DEFAULT_TEMPLATE_PARSER_CONTEXT); o = expr.getValue((Object)null); assertEquals("abc", o.toString()); } @Test public void testCompositeStringExpression() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); Expression ex = parser.parseExpression("hello ${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT); checkString("hello world", ex.getValue()); checkString("hello world", ex.getValue(String.class)); checkString("hello world", ex.getValue((Object)null, String.class)); checkString("hello world", ex.getValue(new Rooty())); checkString("hello world", ex.getValue(new Rooty(), String.class)); EvaluationContext ctx = new StandardEvaluationContext(); checkString("hello world", ex.getValue(ctx)); checkString("hello world", ex.getValue(ctx, String.class)); checkString("hello world", ex.getValue(ctx, null, String.class)); checkString("hello world", ex.getValue(ctx, new Rooty())); checkString("hello world", ex.getValue(ctx, new Rooty(), String.class)); checkString("hello world", ex.getValue(ctx, new Rooty(), String.class)); assertEquals("hello ${'world'}", ex.getExpressionString()); assertFalse(ex.isWritable(new StandardEvaluationContext())); assertFalse(ex.isWritable(new Rooty())); assertFalse(ex.isWritable(new StandardEvaluationContext(), new Rooty())); assertEquals(String.class,ex.getValueType()); assertEquals(String.class,ex.getValueType(ctx)); assertEquals(String.class,ex.getValueTypeDescriptor().getType()); assertEquals(String.class,ex.getValueTypeDescriptor(ctx).getType()); assertEquals(String.class,ex.getValueType(new Rooty())); assertEquals(String.class,ex.getValueType(ctx, new Rooty())); assertEquals(String.class,ex.getValueTypeDescriptor(new Rooty()).getType()); assertEquals(String.class,ex.getValueTypeDescriptor(ctx, new Rooty()).getType()); try { ex.setValue(ctx, null); fail(); } catch (EvaluationException ee) { // success } try { ex.setValue((Object)null, null); fail(); } catch (EvaluationException ee) { // success } try { ex.setValue(ctx, null, null); fail(); } catch (EvaluationException ee) { // success } } static class Rooty {} @Test public void testNestedExpressions() throws Exception { SpelExpressionParser parser = new SpelExpressionParser(); // treat the nested ${..} as a part of the expression Expression ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT); String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello 4 world",s); // not a useful expression but tests nested expression syntax that clashes with template prefix/suffix ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1]==3]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT); assertEquals(CompositeStringExpression.class,ex.getClass()); CompositeStringExpression cse = (CompositeStringExpression)ex; Expression[] exprs = cse.getExpressions(); assertEquals(3,exprs.length); assertEquals("listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1]==3]",exprs[1].getExpressionString()); s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello world",s); ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT); s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello 4 10 world",s); try { ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5] world",DEFAULT_TEMPLATE_PARSER_CONTEXT); fail("Should have failed"); } catch (ParseException pe) { assertEquals("No ending suffix '}' for expression starting at character 41: ${listOfNumbersUpToTen.$[#this>5] world", pe.getSimpleMessage()); } try { ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1==3]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT); fail("Should have failed"); } catch (ParseException pe) { assertEquals("Found closing '}' at position 74 but most recent opening is '[' at position 30", pe.getSimpleMessage()); } } @Test public void testClashingWithSuffixes() throws Exception { // Just wanting to use the prefix or suffix within the template: Expression ex = parser.parseExpression("hello ${3+4} world",DEFAULT_TEMPLATE_PARSER_CONTEXT); String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello 7 world",s); ex = parser.parseExpression("hello ${3+4} wo${'${'}rld",DEFAULT_TEMPLATE_PARSER_CONTEXT); s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello 7 wo${rld",s); ex = parser.parseExpression("hello ${3+4} wo}rld",DEFAULT_TEMPLATE_PARSER_CONTEXT); s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class); assertEquals("hello 7 wo}rld",s); } @Test public void testParsingNormalExpressionThroughTemplateParser() throws Exception { Expression expr = parser.parseExpression("1+2+3"); assertEquals(6,expr.getValue()); expr = parser.parseExpression("1+2+3",null); assertEquals(6,expr.getValue()); } @Test public void testErrorCases() throws Exception { try { parser.parseExpression("hello ${'world'", DEFAULT_TEMPLATE_PARSER_CONTEXT); fail("Should have failed"); } catch (ParseException pe) { assertEquals("No ending suffix '}' for expression starting at character 6: ${'world'", pe.getSimpleMessage()); assertEquals("hello ${'world'", pe.getExpressionString()); } try { parser.parseExpression("hello ${'wibble'${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT); fail("Should have failed"); } catch (ParseException pe) { assertEquals("No ending suffix '}' for expression starting at character 6: ${'wibble'${'world'}", pe.getSimpleMessage()); } try { parser.parseExpression("hello ${} world", DEFAULT_TEMPLATE_PARSER_CONTEXT); fail("Should have failed"); } catch (ParseException pe) { assertEquals("No expression defined within delimiter '${}' at character 6", pe.getSimpleMessage()); } } @Test public void testTemplateParserContext() { TemplateParserContext tpc = new TemplateParserContext("abc","def"); assertEquals("abc", tpc.getExpressionPrefix()); assertEquals("def", tpc.getExpressionSuffix()); assertTrue(tpc.isTemplate()); tpc = new TemplateParserContext(); assertEquals("#{", tpc.getExpressionPrefix()); assertEquals("}", tpc.getExpressionSuffix()); assertTrue(tpc.isTemplate()); ParserContext pc = ParserContext.TEMPLATE_EXPRESSION; assertEquals("#{", pc.getExpressionPrefix()); assertEquals("}", pc.getExpressionSuffix()); assertTrue(pc.isTemplate()); } // --- private void checkString(String expectedString, Object value) { if (!(value instanceof String)) { fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")"); } if (!value.equals(expectedString)) { fail("Did not get expected result. Should have been '" + expectedString + "' but was '" + value + "'"); } } }