diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/support/ConversionServiceAwareConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/support/ConversionServiceAwareConverter.java
index 1c5bc8b4..fa56d37f 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/support/ConversionServiceAwareConverter.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/support/ConversionServiceAwareConverter.java
@@ -32,7 +32,7 @@ public abstract class ConversionServiceAwareConverter extends AbstractConverter
private ConversionService conversionService;
/**
- * Default constructor, expectes to conversion service to be injected using
+ * Default constructor, expects to conversion service to be injected using
* {@link #setConversionService(ConversionService)}.
*/
protected ConversionServiceAwareConverter() {
diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/ExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/ExpressionParser.java
index 3e785009..44477d27 100644
--- a/spring-binding/src/main/java/org/springframework/binding/expression/ExpressionParser.java
+++ b/spring-binding/src/main/java/org/springframework/binding/expression/ExpressionParser.java
@@ -27,6 +27,8 @@ public interface ExpressionParser {
* Is the provided expression string an "eval" expression: meaning an expression that validates to a dynamic value,
* and not a literal expression? "Eval" expressions are normally enclosed in delimiters like #{}, where literal
* expressions are not delimited.
+ *
+ * TODO - candidate for removal in a future milestone: is this really needed?
* @param string the string
* @return true if the expression is an eval expression string, false otherwise.
*/
@@ -37,6 +39,8 @@ public interface ExpressionParser {
* against a target object. For example, the raw expression string "person.id" might become #{person.id}. If the
* string is already an eval expression string, the string argument is returned unchanged. If the string is an
* composite expression string that mixes eval and literal expressions, a parser exception is thrown.
+ *
+ * TODO - candidate for removal in a future milestone: is this really needed?
* @param string the raw string to be transformed into a parseable eval expression string
* @return the eval expression spring
* @throws ParserException an exception occurred during parsing
@@ -47,7 +51,7 @@ public interface ExpressionParser {
* Parse the provided expression string, returning an expression evaluator capable of evaluating it. The expression
* string may be a literal expression string like "foo", an eval-expression string like #{foo}, or a
* composite-expression string like "foo#{foo}bar#{bar}".
- * @param expressionString the parseable expression string
+ * @param expressionString the parseable expression string; cannot be null
* @param expressionTargetType the class of target object this expression can successfully evaluate; for example,
* Map.class for an expression that is expected to evaluate against Maps.
* @param expectedEvaluationResultType the class of object this expression is expected to return or set: for
diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/AbstractExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/AbstractExpressionParser.java
index 5dca7269..f2e20907 100644
--- a/spring-binding/src/main/java/org/springframework/binding/expression/support/AbstractExpressionParser.java
+++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/AbstractExpressionParser.java
@@ -22,7 +22,7 @@ import org.springframework.binding.expression.Expression;
import org.springframework.binding.expression.ExpressionParser;
import org.springframework.binding.expression.ExpressionVariable;
import org.springframework.binding.expression.ParserException;
-import org.springframework.util.StringUtils;
+import org.springframework.util.Assert;
/**
* Abstract base class for expression parsers.
@@ -90,6 +90,7 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
public Expression parseExpression(String expressionString, Class expressionTargetType,
Class expectedEvaluationResultType, ExpressionVariable[] expressionVariables) throws ParserException {
+ Assert.notNull(expressionString, "The expression string to parse is required");
// TODO variables
Expression[] expressions = parseExpressions(expressionString);
if (expressions.length == 1) {
@@ -118,52 +119,42 @@ public abstract class AbstractExpressionParser implements ExpressionParser {
*/
private Expression[] parseExpressions(String expressionString) throws ParserException {
List expressions = new LinkedList();
- if (StringUtils.hasText(expressionString)) {
- int startIdx = 0;
- while (startIdx < expressionString.length()) {
- int prefixIndex = expressionString.indexOf(getExpressionPrefix(), startIdx);
- if (prefixIndex >= startIdx) {
- // an expression was found
- if (prefixIndex > startIdx) {
- expressions.add(new StaticExpression(expressionString.substring(startIdx, prefixIndex)));
- startIdx = prefixIndex;
- }
- int nextPrefixIndex = expressionString.indexOf(getExpressionPrefix(), prefixIndex
- + getExpressionPrefix().length());
- int suffixIndex;
- if (nextPrefixIndex == -1) {
- // this is the last expression in the expression string
- suffixIndex = expressionString.lastIndexOf(getExpressionSuffix());
- } else {
- // another expression exists after this one in the expression string
- suffixIndex = expressionString.lastIndexOf(getExpressionSuffix(), nextPrefixIndex);
- }
- if (suffixIndex < (prefixIndex + getExpressionPrefix().length())) {
- throw new ParserException(expressionString, "No ending suffix '" + getExpressionSuffix()
- + "' for expression starting at character " + prefixIndex + ": "
- + expressionString.substring(prefixIndex), null);
- } else if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
- throw new ParserException(expressionString, "No expression defined within delimiter '"
- + getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex, null);
- } else {
- String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(),
- suffixIndex);
- expressions.add(doParseExpression(expr));
- startIdx = suffixIndex + 1;
- }
- } else {
- if (startIdx == 0) {
- // treat entire string as one expression
- expressions.add(doParseExpression(expressionString));
- } else {
- // no more ${expressions} found in string
- expressions.add(new StaticExpression(expressionString.substring(startIdx)));
- }
- startIdx = expressionString.length();
+ int startIdx = 0;
+ while (startIdx < expressionString.length()) {
+ int prefixIndex = expressionString.indexOf(getExpressionPrefix(), startIdx);
+ if (prefixIndex >= startIdx) {
+ // an expression was found
+ if (prefixIndex > startIdx) {
+ expressions.add(new StaticExpression(expressionString.substring(startIdx, prefixIndex)));
+ startIdx = prefixIndex;
}
+ int nextPrefixIndex = expressionString.indexOf(getExpressionPrefix(), prefixIndex
+ + getExpressionPrefix().length());
+ int suffixIndex;
+ if (nextPrefixIndex == -1) {
+ // this is the last expression in the expression string
+ suffixIndex = expressionString.lastIndexOf(getExpressionSuffix());
+ } else {
+ // another expression exists after this one in the expression string
+ suffixIndex = expressionString.lastIndexOf(getExpressionSuffix(), nextPrefixIndex);
+ }
+ if (suffixIndex < (prefixIndex + getExpressionPrefix().length())) {
+ throw new ParserException(expressionString, "No ending suffix '" + getExpressionSuffix()
+ + "' for expression starting at character " + prefixIndex + ": "
+ + expressionString.substring(prefixIndex), null);
+ } else if (suffixIndex == prefixIndex + getExpressionPrefix().length()) {
+ throw new ParserException(expressionString, "No expression defined within delimiter '"
+ + getExpressionPrefix() + getExpressionSuffix() + "' at character " + prefixIndex, null);
+ } else {
+ String expr = expressionString.substring(prefixIndex + getExpressionPrefix().length(), suffixIndex);
+ expressions.add(doParseExpression(expr));
+ startIdx = suffixIndex + 1;
+ }
+ } else {
+ // no more evaluatable ${expressions} found in string
+ expressions.add(new StaticExpression(expressionString.substring(startIdx)));
+ startIdx = expressionString.length();
}
- } else {
- expressions.add(new StaticExpression(expressionString));
}
return (Expression[]) expressions.toArray(new Expression[expressions.size()]);
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/method/TextToMethodSignature.java b/spring-binding/src/main/java/org/springframework/binding/method/TextToMethodSignature.java
deleted file mode 100644
index 2cf85125..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/method/TextToMethodSignature.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2004-2007 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.binding.method;
-
-import java.util.LinkedList;
-import java.util.List;
-
-import org.springframework.binding.convert.ConversionContext;
-import org.springframework.binding.convert.ConversionException;
-import org.springframework.binding.convert.ConversionService;
-import org.springframework.binding.convert.support.ConversionServiceAwareConverter;
-import org.springframework.binding.expression.Expression;
-
-/**
- * Converter that takes an encoded string representation and produces a corresponding MethodSignature
- * object.
- *
- * This converter supports the following encoded forms:
- *
- * - "methodName" - the name of the method to invoke, where the method is expected to have no arguments.
- * - "methodName(param1Type param1Name, paramNType paramNName)" - the name of the method to invoke, where the method
- * is expected to have parameters delimited by a comma. In this example, the method has two parameters. The type is
- * either the fully-qualified class of the argument OR a known type alias OR left out althogether. The name is the
- * logical name of the argument, which is used during data binding to retrieve the argument value (typically an
- * expression).
- *
- *
- * @see MethodSignature
- *
- * @author Keith Donald
- * @author Erwin Vervaet
- */
-public class TextToMethodSignature extends ConversionServiceAwareConverter {
-
- /**
- * Create a new converter that converts strings to MethodSignature objects.
- */
- public TextToMethodSignature() {
- }
-
- /**
- * Create a new converter that converts strings to MethodSignature objects.
- * @param conversionService the conversion service to use
- */
- public TextToMethodSignature(ConversionService conversionService) {
- super(conversionService);
- }
-
- public Class[] getSourceClasses() {
- return new Class[] { String.class };
- }
-
- public Class[] getTargetClasses() {
- return new Class[] { MethodSignature.class };
- }
-
- protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception {
- String encodedMethodSignature = (String) source;
- encodedMethodSignature = encodedMethodSignature.trim();
- int openParan = encodedMethodSignature.indexOf('(');
- if (openParan == -1) {
- // form "foo"
- return new MethodSignature(encodedMethodSignature);
- } else {
- // form "foo(...)"
- String methodName = encodedMethodSignature.substring(0, openParan);
- int closeParan = encodedMethodSignature.lastIndexOf(')');
- if (closeParan != (encodedMethodSignature.length() - 1)) {
- throw new ConversionException(encodedMethodSignature, MethodSignature.class,
- "Syntax error: No close parenthesis specified for method parameter list", null);
- }
- String delimitedParams = encodedMethodSignature.substring(openParan + 1, closeParan);
- String[] paramArray = splitParameters(encodedMethodSignature, delimitedParams);
- Parameters params = new Parameters(paramArray.length);
- for (int i = 0; i < paramArray.length; i++) {
- // param could be of the form "type name", "name", "type ${name}" or "${name}"
- String param = paramArray[i].trim();
- int space = param.indexOf(' ');
- int expr = param.indexOf('{');
- if (space == -1 || (expr != -1 && space > expr)) {
- // "name" or "${name}"
- params.add(new Parameter(null, parseExpression(param)));
- } else {
- // "type name" or "type ${name}"
- Class type = (Class) fromStringTo(Class.class).execute(param.substring(0, space).trim());
- Expression name = parseExpression(param.substring(space + 1).trim());
- params.add(new Parameter(type, name));
- }
- }
- return new MethodSignature(methodName, params);
- }
- }
-
- /**
- * Split given parameter string into individual parameter definitions.
- */
- private String[] splitParameters(String encodedMethodSignature, String parameters) {
- List res = new LinkedList();
-
- int paramStart = 0;
- int blockNestingCount = 0;
- for (int i = 0; i < parameters.length(); i++) {
- switch (parameters.charAt(i)) {
- case '{':
- blockNestingCount++;
- break;
- case '}':
- blockNestingCount--;
- break;
- case ',':
- if (blockNestingCount == 0) {
- // only take comma delimiter into account when not inside
- // a block
- res.add(parameters.substring(paramStart, i));
- paramStart = i + 1;
- }
- break;
- }
- }
- if (blockNestingCount != 0) {
- throw new ConversionException(encodedMethodSignature, MethodSignature.class,
- "Syntax error: Curly braces do not match", null);
- }
- if (paramStart < parameters.length()) {
- res.add(parameters.substring(paramStart));
- }
-
- return (String[]) res.toArray(new String[res.size()]);
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/ognl/OgnlExpressionParserTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/ognl/OgnlExpressionParserTests.java
index bd0220c5..150bd611 100644
--- a/spring-binding/src/test/java/org/springframework/binding/expression/ognl/OgnlExpressionParserTests.java
+++ b/spring-binding/src/test/java/org/springframework/binding/expression/ognl/OgnlExpressionParserTests.java
@@ -29,7 +29,7 @@ public class OgnlExpressionParserTests extends TestCase {
private TestBean bean = new TestBean();
- public void testParseSimpleDelimited() {
+ public void testParseSimple() {
String exp = "${flag}";
Expression e = parser.parseExpression(exp, null, null, null);
assertNotNull(e);
@@ -37,20 +37,6 @@ public class OgnlExpressionParserTests extends TestCase {
assertFalse(b.booleanValue());
}
- public void testParseSimple() {
- String exp = "flag";
- Expression e = parser.parseExpression(exp, null, null, null);
- assertNotNull(e);
- Boolean b = (Boolean) e.getValue(bean);
- assertFalse(b.booleanValue());
- }
-
- public void testParseNull() {
- Expression e = parser.parseExpression(null, null, null, null);
- assertNotNull(e);
- assertNull(e.getValue(bean));
- }
-
public void testParseEmpty() {
Expression e = parser.parseExpression("", null, null, null);
assertNotNull(e);
diff --git a/spring-binding/src/test/java/org/springframework/binding/mapping/RequiredMappingTests.java b/spring-binding/src/test/java/org/springframework/binding/mapping/RequiredMappingTests.java
index 5d3cb573..242ea875 100644
--- a/spring-binding/src/test/java/org/springframework/binding/mapping/RequiredMappingTests.java
+++ b/spring-binding/src/test/java/org/springframework/binding/mapping/RequiredMappingTests.java
@@ -28,7 +28,7 @@ public class RequiredMappingTests extends TestCase {
public void testRequired() {
MappingBuilder builder = new MappingBuilder(new OgnlExpressionParser());
- Mapping mapping = builder.source("foo").target("bar").required().value();
+ Mapping mapping = builder.source("${foo}").target("${bar}").required().value();
HashMap source = new HashMap();
source.put("foo", "baz");
HashMap target = new HashMap();
@@ -38,7 +38,7 @@ public class RequiredMappingTests extends TestCase {
public void testRequiredExceptionOnNull() {
MappingBuilder builder = new MappingBuilder(new OgnlExpressionParser());
- Mapping mapping = builder.source("foo").target("bar").required().value();
+ Mapping mapping = builder.source("${foo}").target("${bar}").required().value();
HashMap source = new HashMap();
source.put("foo", null);
HashMap target = new HashMap();
@@ -50,7 +50,7 @@ public class RequiredMappingTests extends TestCase {
public void testRequiredExceptionOnNoKey() {
MappingBuilder builder = new MappingBuilder(new OgnlExpressionParser());
- Mapping mapping = builder.source("foo").target("bar").required().value();
+ Mapping mapping = builder.source("${foo}").target("${bar}").required().value();
HashMap source = new HashMap();
HashMap target = new HashMap();
try {
diff --git a/spring-binding/src/test/java/org/springframework/binding/method/TextToMethodSignatureTests.java b/spring-binding/src/test/java/org/springframework/binding/method/TextToMethodSignatureTests.java
deleted file mode 100644
index 76764291..00000000
--- a/spring-binding/src/test/java/org/springframework/binding/method/TextToMethodSignatureTests.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright 2004-2007 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.binding.method;
-
-import junit.framework.TestCase;
-
-import org.springframework.binding.convert.ConversionException;
-import org.springframework.binding.convert.support.DefaultConversionService;
-import org.springframework.binding.convert.support.TextToExpression;
-import org.springframework.binding.expression.ognl.OgnlExpressionParser;
-
-/**
- * Test case for {@link TextToMethodSignature}.
- *
- * @author Erwin Vervaet
- */
-public class TextToMethodSignatureTests extends TestCase {
-
- private TextToMethodSignature converter;
-
- protected void setUp() throws Exception {
- DefaultConversionService conversionService = new DefaultConversionService();
- conversionService.addConverter(new TextToExpression(new OgnlExpressionParser()));
- converter = new TextToMethodSignature(conversionService);
- }
-
- public void testParseNoArguments() {
- MethodSignature signature = (MethodSignature) converter.convert("foo");
- assertEquals("foo", signature.getMethodName());
- assertEquals(0, signature.getParameters().size());
-
- signature = (MethodSignature) converter.convert("foo()");
- assertEquals("foo", signature.getMethodName());
- assertEquals(0, signature.getParameters().size());
- }
-
- public void testSingleArgument() {
- MethodSignature signature = (MethodSignature) converter.convert("foo(${flowScope.bar})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertNull(signature.getParameters().getParameter(0).getType());
- assertEquals("flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
-
- signature = (MethodSignature) converter.convert("foo(${'Foo' + flowScope.bar})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertEquals("\"Foo\" + flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
- }
-
- public void testSingleArgumentWithType() {
- MethodSignature signature = (MethodSignature) converter.convert("foo(java.lang.String ${flowScope.bar})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertEquals(String.class, signature.getParameters().getParameter(0).getType());
- assertEquals("flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
-
- signature = (MethodSignature) converter.convert("foo(long ${flowScope.bar})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertEquals(Long.class, signature.getParameters().getParameter(0).getType());
- assertEquals("flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
- }
-
- public void testMultipleArguments() {
- MethodSignature signature = (MethodSignature) converter
- .convert("foo(${flowScope.bar}, ${externalContext.requestParameterMap.test})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(2, signature.getParameters().size());
- assertNull(signature.getParameters().getParameter(0).getType());
- assertEquals("flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
- assertNull(signature.getParameters().getParameter(1).getType());
- assertEquals("externalContext.requestParameterMap.test", signature.getParameters().getParameter(1).getName()
- .toString());
- }
-
- public void testMultipleArgumentsWithType() {
- MethodSignature signature = (MethodSignature) converter
- .convert("foo(long ${flowScope.bar}, java.lang.String ${externalContext.requestParameterMap.test})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(2, signature.getParameters().size());
- assertEquals(Long.class, signature.getParameters().getParameter(0).getType());
- assertEquals("flowScope.bar", signature.getParameters().getParameter(0).getName().toString());
- assertEquals(String.class, signature.getParameters().getParameter(1).getType());
- assertEquals("externalContext.requestParameterMap.test", signature.getParameters().getParameter(1).getName()
- .toString());
- }
-
- public void testCollectionConstructionSyntax() {
- MethodSignature signature = (MethodSignature) converter.convert("foo({1, 2, 3})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertNull(signature.getParameters().getParameter(0).getType());
- assertEquals("{ 1, 2, 3 }", signature.getParameters().getParameter(0).getName().toString());
- }
-
- public void testCollectionConstructionSyntaxWithType() {
- MethodSignature signature = (MethodSignature) converter.convert("foo(java.util.List {1, 2, 3})");
- assertEquals("foo", signature.getMethodName());
- assertEquals(1, signature.getParameters().size());
- assertEquals(java.util.List.class, signature.getParameters().getParameter(0).getType());
- assertEquals("{ 1, 2, 3 }", signature.getParameters().getParameter(0).getName().toString());
-
- signature = (MethodSignature) converter.convert("foo(a${b,#{1:2},e}f${g,#{3:4},j}k)");
- }
-
- public void testSyntaxErrors() {
- try {
- converter.convert("foo(");
- fail();
- } catch (ConversionException e) {
- }
-
- try {
- converter.convert("foo(long 1, ${bar()}");
- fail();
- } catch (ConversionException e) {
- }
-
- try {
- converter.convert("foo(long 1, {1, 2)");
- fail();
- } catch (ConversionException e) {
- }
- }
-}