diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/Expression.java b/spring-binding/src/main/java/org/springframework/binding/expression/Expression.java index b044271b..8d9d429b 100644 --- a/spring-binding/src/main/java/org/springframework/binding/expression/Expression.java +++ b/spring-binding/src/main/java/org/springframework/binding/expression/Expression.java @@ -44,7 +44,8 @@ public interface Expression { * Returns the most general type that can be passed to the {@link #setValue(Object, Object)} method for the given * context. * @param context the context to evaluate - * @return the most general type of value that can be set on this context + * @return the most general type of value that can be set on this context, or null if the type + * information cannot be determined * @throws EvaluationException an exception occurred during expression evaluation */ public Class getValueType(Object context) throws EvaluationException; diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/el/ELExpressionParserTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/el/ELExpressionParserTests.java index 15d93441..a13ca972 100644 --- a/spring-binding/src/test/java/org/springframework/binding/expression/el/ELExpressionParserTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/expression/el/ELExpressionParserTests.java @@ -131,6 +131,13 @@ public class ELExpressionParserTests extends TestCase { assertEquals("foo2bar", exp.getValue(target)); } + public void testGetValueTypeNullCollectionValue() { + String exp = "list[3]"; + Expression e = parser.parseExpression(exp, null); + TestBean target = new TestBean(); + assertEquals(null, e.getValueType(target)); + } + public static class TestBean { private String value = "foo"; @@ -153,6 +160,7 @@ public class ELExpressionParserTests extends TestCase { list.add("1"); list.add("2"); list.add("3"); + list.add(null); } public TestBean getBean() { @@ -178,6 +186,10 @@ public class ELExpressionParserTests extends TestCase { public void setMaximum(int maximum) { this.maximum = maximum; } + + public List getList() { + return list; + } } private static class TestELContextFactory implements ELContextFactory { 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 a052cadf..5c8f5abf 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 @@ -160,4 +160,10 @@ public class OgnlExpressionParserTests extends TestCase { Expression e = parser.parseExpression(exp, null); assertEquals(boolean.class, e.getValueType(bean)); } + + public void testGetValueTypeNullCollectionValue() { + String exp = "list[0]"; + Expression e = parser.parseExpression(exp, null); + assertEquals(null, e.getValueType(bean)); + } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java b/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java index 34f1a295..57e96bf2 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/expression/DefaultExpressionParserFactory.java @@ -20,10 +20,7 @@ import javax.el.ExpressionFactory; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.binding.convert.ConversionService; -import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.ParserContext; -import org.springframework.binding.expression.ParserException; import org.springframework.binding.expression.el.DefaultExpressionFactoryUtils; import org.springframework.util.ClassUtils; import org.springframework.webflow.expression.el.WebFlowELExpressionParser; @@ -61,14 +58,7 @@ public final class DefaultExpressionParserFactory { * @return the expression parser */ public static synchronized ExpressionParser getExpressionParser() { - // return a wrapper that will lazily load the default expression parser - // this prevents the underlying parser from being initialized until it is actually used - // this allows the EL to be an optional dependency if the expression parser wrapper is replaced and never used - return new ExpressionParser() { - public Expression parseExpression(String expressionString, ParserContext context) throws ParserException { - return getDefaultExpressionParser().parseExpression(expressionString, context); - } - }; + return getDefaultExpressionParser(); } /** @@ -78,7 +68,7 @@ public final class DefaultExpressionParserFactory { * @return the expression parser */ public static synchronized ExpressionParser getExpressionParser(final ConversionService conversionService) { - return new DefaultExpressionParserProxy(conversionService); + return createDefaultExpressionParser(conversionService); } /** @@ -129,23 +119,4 @@ public final class DefaultExpressionParserFactory { } } } - - private static class DefaultExpressionParserProxy implements ExpressionParser { - private ConversionService conversionService; - - private ExpressionParser instance; - - public DefaultExpressionParserProxy(ConversionService conversionService) { - this.conversionService = conversionService; - } - - public Expression parseExpression(String expressionString, ParserContext context) throws ParserException { - synchronized (instance) { - if (instance == null) { - instance = createDefaultExpressionParser(conversionService); - } - } - return instance.parseExpression(expressionString, context); - } - } } \ No newline at end of file diff --git a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java index c9fb9d0d..158d28dd 100644 --- a/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java +++ b/spring-webflow/src/main/java/org/springframework/webflow/mvc/view/AbstractMvcView.java @@ -57,7 +57,6 @@ import org.springframework.webflow.execution.Event; import org.springframework.webflow.execution.FlowExecutionKey; import org.springframework.webflow.execution.RequestContext; import org.springframework.webflow.execution.View; -import org.springframework.webflow.expression.DefaultExpressionParserFactory; /** * Base view implementation for the Spring Web MVC Servlet and Spring Web MVC Portlet frameworks. @@ -76,7 +75,7 @@ public abstract class AbstractMvcView implements View { private RequestContext requestContext; - private ExpressionParser expressionParser = DefaultExpressionParserFactory.getExpressionParser(); + private ExpressionParser expressionParser; private ConversionService conversionService; diff --git a/spring-webflow/src/test/java/org/springframework/webflow/TestBean.java b/spring-webflow/src/test/java/org/springframework/webflow/TestBean.java index bff0152a..fe7b3743 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/TestBean.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/TestBean.java @@ -16,6 +16,7 @@ package org.springframework.webflow; import java.io.Serializable; +import java.util.Date; /** * Simple test bean used by some test cases. Note that this bean has value semantics. @@ -26,6 +27,8 @@ public class TestBean implements Serializable { public int datum2; + private Date datum3; + public boolean executed; public void execute() { @@ -40,6 +43,14 @@ public class TestBean implements Serializable { return datum2; } + public Date getDatum3() { + return datum3; + } + + public void setDatum3(Date datum3) { + this.datum3 = datum3; + } + public boolean isExecuted() { return executed; } diff --git a/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java b/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java index 41fa39fb..5f207d0c 100644 --- a/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java +++ b/spring-webflow/src/test/java/org/springframework/webflow/expression/DefaultExpressionParserFactoryTests.java @@ -15,9 +15,15 @@ */ package org.springframework.webflow.expression; +import java.util.Calendar; + import junit.framework.TestCase; +import org.springframework.binding.convert.service.DefaultConversionService; +import org.springframework.binding.expression.Expression; import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.support.FluentParserContext; +import org.springframework.webflow.TestBean; /** * Unit tests for {@link DefaultExpressionParserFactory}. @@ -28,4 +34,16 @@ public class DefaultExpressionParserFactoryTests extends TestCase { ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(); assertNotNull(parser); } + + public void testGetDefaultExpressionParserConversionService() { + DefaultConversionService conversionService = new DefaultConversionService(); + ExpressionParser parser = DefaultExpressionParserFactory.getExpressionParser(conversionService); + Expression exp = parser.parseExpression("datum3", new FluentParserContext().expectResult(String.class)); + TestBean context = new TestBean(); + Calendar cal = Calendar.getInstance(); + cal.set(2008, 1, 1); + exp.setValue(context, cal.getTime()); + String string = (String) exp.getValue(context); + assertEquals(null, string); + } }