diff --git a/spring-binding/ivy.xml b/spring-binding/ivy.xml index 57318a52..f42591d1 100644 --- a/spring-binding/ivy.xml +++ b/spring-binding/ivy.xml @@ -13,12 +13,14 @@ + + - + diff --git a/spring-binding/project.properties b/spring-binding/project.properties index 60d3db3a..9e7817fe 100644 --- a/spring-binding/project.properties +++ b/spring-binding/project.properties @@ -7,5 +7,5 @@ project.base.version=1.1-SNAPSHOT #project.version=${project.base.version} #ivy.status=release -javac.source=1.3 -javac.target=1.3 +javac.source=1.4 +javac.target=1.4 diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/DefaultELResolver.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/DefaultELResolver.java new file mode 100644 index 00000000..932ec12a --- /dev/null +++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/DefaultELResolver.java @@ -0,0 +1,77 @@ +package org.springframework.binding.expression.support; + +import javax.el.ArrayELResolver; +import javax.el.BeanELResolver; +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ListELResolver; +import javax.el.MapELResolver; +import javax.el.ResourceBundleELResolver; + +import org.springframework.binding.collection.MapAdaptable; +import org.springframework.util.Assert; + +/** + * A generic ELResolver to be used as a default when no other ELResolvers have been + * configured by the client application. + * + * This implementation will resolve the first part of the expression to + * the pre-configured base object, and will then delegate through the + * chain of standard resolvers for the rest of the expression. + * + * Note - Requires Java 5 or higher due to the use of generics in the API's basic resolvers. + * + * @author Jeremy Grelle + * + */ +public class DefaultELResolver extends CompositeELResolver { + + private Object target; + + public DefaultELResolver() { + configureResolvers(); + } + + public Class getType(ELContext context, Object base, Object property) { + return super.getType(context, adaptIfNecessary(base), property); + } + + public Object getValue(ELContext context, Object base, Object property) { + Assert.notNull(target,"The DefaultELResolver must have a target base property set."); + if (base == null) { + return super.getValue(context, target, property); + } + return super.getValue(context, adaptIfNecessary(base), property); + } + + public void setValue(ELContext context, Object base, Object property, Object val) { + Assert.notNull(target,"The DefaultELResolver must have a target base property set."); + if (base == null) + super.setValue(context, target, property, val); + else + super.setValue(context, adaptIfNecessary(base), property, val); + } + + public Object getTarget() { + return target; + } + + public void setTarget(Object target) { + this.target = adaptIfNecessary(target); + } + + private Object adaptIfNecessary(Object base) { + if (base instanceof MapAdaptable) + return ((MapAdaptable)base).asMap(); + return base; + } + + private void configureResolvers() { + add(new ArrayELResolver()); + add(new ListELResolver()); + add(new MapELResolver()); + add(new ResourceBundleELResolver()); + add(new BeanELResolver()); + } + +} diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/DelegatingELContext.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/DelegatingELContext.java new file mode 100644 index 00000000..ad98c45d --- /dev/null +++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/DelegatingELContext.java @@ -0,0 +1,132 @@ +package org.springframework.binding.expression.support; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.el.CompositeELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.VariableMapper; + +/** + * An {@link ELContext} implementation that is meant to aggregate the {@link ELResolver}s of + * pre-existing {@link ELContext}s. Can also be used standalone if no other {@link ELContext} + * exists in the current environment. + * + * Note - Using this context standalone requires Java 5 or higher. + * + * @author Jeremy Grelle + * + */ +public class DelegatingELContext extends ELContext { + + private ELResolver resolver; + + private FunctionMapper functionMapper; + + private VariableMapper variableMapper; + + private List delegates = new ArrayList(); + + public ELResolver getELResolver() { + return resolver; + } + + public void setELResolver(ELResolver resolver) { + this.resolver = resolver; + } + + public FunctionMapper getFunctionMapper() { + return functionMapper; + } + + public void setFunctionMapper(FunctionMapper functionMapper) { + this.functionMapper = functionMapper; + } + + public VariableMapper getVariableMapper() { + return variableMapper; + } + + public void setVariableMapper(VariableMapper variableMapper) { + this.variableMapper = variableMapper; + } + + /** + * Add a delegate {@link ELContext}. + * + * If this context is currently configured with the {@link DefaultELResolver}, that resolver + * instance will be replaced with a new {@link CompositeELResolver}. + * + * The delegate's base {@link ELResolver} will be added to this context's base {@link CompositeELResolver}. + * + * @param context The {@link ELContext} whose base {@link ELResolver} needs to be included in this + * context's base {@link CompositeELResolver}. + */ + public void addDelegate(ELContext context) { + delegates.add(context); + if (getELResolver() == null || getELResolver() instanceof DefaultELResolver) { + CompositeELResolver composite = new CompositeELResolver(); + composite.add(context.getELResolver()); + setELResolver(composite); + } + else if (getELResolver() instanceof CompositeELResolver) { + ((CompositeELResolver) getELResolver()).add(context.getELResolver()); + } + } + + public Object getContext(Class key) { + Object context = super.getContext(key); + if (context != null) + return context; + + Iterator i = delegates.iterator(); + while(i.hasNext()) + { + ELContext delegate = (ELContext) i.next(); + context = delegate.getContext(key); + if (context != null) + return context; + } + return null; + } + + /** + * The ThreadLocal variable used to record the + * {@link ELContext} instance for each processing thread. + */ + private static ThreadLocal instance = new ThreadLocal() { + protected Object initialValue() { + return null; + } + }; + + /** + * Return the {@link ELContext} instance for the request that is + * being processed by the current thread, if any. + */ + public static DelegatingELContext getCurrentInstance() { + if (instance.get() == null) + setCurrentInstance(defaultInstance()); + return ((DelegatingELContext) instance.get()); + } + + /** + * Set the {@link ELContext} instance for the request that is + * being processed by the current thread. + * + * @param context The {@link ELContext} instance for the current + * thread, or null if this thread no longer has an + * ELContext instance. + * + */ + public static void setCurrentInstance(DelegatingELContext context) { + instance.set(context); + } + + private static DelegatingELContext defaultInstance() { + return new DelegatingELContext(); + } +} diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpression.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpression.java new file mode 100644 index 00000000..18da0658 --- /dev/null +++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpression.java @@ -0,0 +1,88 @@ +package org.springframework.binding.expression.support; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ValueExpression; + +import org.springframework.binding.expression.EvaluationAttempt; +import org.springframework.binding.expression.EvaluationContext; +import org.springframework.binding.expression.EvaluationException; +import org.springframework.binding.expression.SettableExpression; + +/** + * Evaluates a parsed EL expression. + * + * @author Jeremy Grelle + */ +public class ELExpression implements SettableExpression { + + ValueExpression expression; + + public ELExpression(ValueExpression expression) { + this.expression = expression; + } + + public void evaluateToSet(Object target, Object value, EvaluationContext context) throws EvaluationException { + ELContext ctx = getELContext(target); + try { + expression.setValue(ctx, value); + } + catch (ELException ex) { + throw new EvaluationException(new EvaluationAttempt(this, target, context), ex); + } + } + + public Object evaluate(Object target, EvaluationContext context) throws EvaluationException { + ELContext ctx = getELContext(target); + try { + return expression.getValue(ctx); + } + catch (ELException ex) { + throw new EvaluationException(new EvaluationAttempt(this, target, context), ex); + } + } + + protected Class getType(Object target, EvaluationContext context) throws EvaluationException{ + ELContext ctx = getELContext(target); + try { + return expression.getType(ctx); + } + catch (ELException ex) { + throw new EvaluationException(new EvaluationAttempt(this, target, context), ex); + } + } + + /** + * Retrieves the thread-bound {@link ELContext} instance, configured with a DefaultELResolver if + * no other resolvers have been configured. + * + * @return {@link ELContext} The thread-bound {@link ELContext} instance. + */ + private ELContext getELContext(Object target) { + ELContext ctx = DelegatingELContext.getCurrentInstance(); + if (ctx.getELResolver() == null) + ((DelegatingELContext)ctx).setELResolver(new DefaultELResolver()); + if (ctx.getELResolver() instanceof DefaultELResolver) + ((DefaultELResolver)ctx.getELResolver()).setTarget(target); + return ctx; + } + + public int hashCode() { + return expression.hashCode(); + } + + public boolean equals(Object o) { + if (!(o instanceof ELExpression)) { + return false; + } + ELExpression other = (ELExpression) o; + return expression.equals(other.expression); + } + + public String toString() + { + return expression.getExpressionString(); + } + + +} diff --git a/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpressionParser.java b/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpressionParser.java new file mode 100644 index 00000000..e9d374f9 --- /dev/null +++ b/spring-binding/src/main/java/org/springframework/binding/expression/support/ELExpressionParser.java @@ -0,0 +1,119 @@ +package org.springframework.binding.expression.support; + +import javax.el.ELContext; +import javax.el.ELException; +import javax.el.ExpressionFactory; + +import org.jboss.el.ExpressionFactoryImpl; +import org.springframework.binding.expression.Expression; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.ParserException; +import org.springframework.binding.expression.SettableExpression; + +/** + * An expression parser that parses EL expressions. Beyond standard EL expression parsing, it + * makes use of the ability of the JBoss-EL implementation to parse dynamic method invocations + * such as foo.bar() (the EL spec currently only provides out-of-the-box support for functions). + * + * @author Jeremy Grelle + */ +public class ELExpressionParser implements ExpressionParser { + + /** + * The expression prefix for deferred EL expressions. + */ + private static final String DEFERRED_EL_EXPRESSION_PREFIX = "#{"; + + /** + * The expression suffix for deferred EL expressions. + */ + private static final String DEFERRED_EL_EXPRESSION_SUFFIX = "}"; + + /** + * The marked expression delimiter prefix. + */ + private String expressionPrefix = DEFERRED_EL_EXPRESSION_PREFIX; + + /** + * The marked expression delimiter suffix. + */ + private String expressionSuffix = DEFERRED_EL_EXPRESSION_SUFFIX; + + /** + * The ExpressionFactory for constructing EL expressions + */ + private ExpressionFactory factory = new ExpressionFactoryImpl(); + + public String getExpressionPrefix() { + return expressionPrefix; + } + + public String getExpressionSuffix() { + return expressionSuffix; + } + + /** + * Check whether or not given criteria are expressed as an expression. + */ + public boolean isDelimitedExpression(String expressionString) { + int prefixIndex = expressionString.indexOf(getExpressionPrefix()); + if (prefixIndex == -1) { + return false; + } + int suffixIndex = expressionString.indexOf(getExpressionSuffix(), prefixIndex); + if (suffixIndex == -1) { + return false; + } + else { + if (suffixIndex == prefixIndex + getExpressionPrefix().length()) { + return false; + } + else { + return true; + } + } + } + + public Expression parseExpression(String expressionString) throws ParserException { + if (!isDelimitedExpression(expressionString)) { + expressionString = getExpressionPrefix() + expressionString + getExpressionSuffix(); + } + return doParseExpression(expressionString); + } + + public SettableExpression parseSettableExpression(String expressionString) throws ParserException, + UnsupportedOperationException { + if (!isDelimitedExpression(expressionString)) { + expressionString = getExpressionPrefix() + expressionString + getExpressionSuffix(); + } + return doParseSettableExpression(expressionString); + } + + /** + * Parses the expression string into an EL value expression. + * @param expressionString + * @throws ParserException + */ + protected Expression doParseExpression(String expressionString) throws ParserException { + return doParseSettableExpression(expressionString); + } + + /** + * Parses the expression string into an EL value expression. + * @param expressionString + * @throws ParserException + */ + protected SettableExpression doParseSettableExpression(String expressionString) throws ParserException { + ELContext ctx = getELContext(); + try { + return new ELExpression(factory.createValueExpression(ctx, expressionString, Object.class)); + } + catch (ELException ex) { + throw new ParserException(expressionString, ex); + } + } + + private ELContext getELContext() { + return DelegatingELContext.getCurrentInstance(); + } +} diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/support/ELContextDelegationTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELContextDelegationTests.java new file mode 100644 index 00000000..1a7310da --- /dev/null +++ b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELContextDelegationTests.java @@ -0,0 +1,106 @@ +package org.springframework.binding.expression.support; + +import java.util.Iterator; + +import javax.el.BeanELResolver; +import javax.el.ELContext; +import javax.el.ELResolver; +import javax.el.FunctionMapper; +import javax.el.VariableMapper; + +import junit.framework.TestCase; + +import org.springframework.binding.expression.ExpressionParser; + +/** + * Tests to verify the delegation behavior of ELContextImpl. + * + * @author Jeremy Grelle + * + */ +public class ELContextDelegationTests extends TestCase { + + private ELContext context = new MockELContext(); + private ExpressionParser expressionParser = new ELExpressionParser(); + private TestBean bean; + + protected void setUp() throws Exception { + bean = new TestBean(); + bean.setFlag(true); + } + + public final void testGetValueByContextDelegation() + { + DelegatingELContext internalContext = DelegatingELContext.getCurrentInstance(); + internalContext.addDelegate(context); + assertEquals(Boolean.TRUE, expressionParser.parseExpression("#{bean.flag}").evaluate(bean, null)); + assertEquals(Boolean.TRUE, expressionParser.parseExpression("#{bean.flag}").evaluate(null, null)); + assertFalse(internalContext.getELResolver() instanceof DefaultELResolver); + } + + private class MockELContext extends ELContext + { + + ELResolver resolver = new MockELResolver(); + + public ELResolver getELResolver() { + return resolver; + } + + public FunctionMapper getFunctionMapper() { + return null; + } + + public VariableMapper getVariableMapper() { + return null; + } + + } + + private class MockELResolver extends ELResolver + { + + public Class getCommonPropertyType(ELContext context, Object base) { + return null; + } + + public Iterator getFeatureDescriptors(ELContext context, Object base) { + return null; + } + + public Class getType(ELContext context, Object base, Object property) { + if (base != null) + return base.getClass(); + return null; + } + + public Object getValue(ELContext context, Object base, Object property) { + if (base == null && "bean".equals(property)) + { + context.setPropertyResolved(true); + return bean; + } + if (base == bean) + { + return new BeanELResolver().getValue(context, base, property); + } + return null; + } + + public boolean isReadOnly(ELContext context, Object base, Object property) { + return false; + } + + public void setValue(ELContext context, Object base, Object property, Object value) { + if (base == null && "bean".equals(property)) + { + context.setPropertyResolved(true); + } + else if (base == bean) + { + new BeanELResolver().setValue(context, base, property, value); + } + } + + } +} diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodExpressionTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodExpressionTests.java new file mode 100644 index 00000000..22b2afc3 --- /dev/null +++ b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodExpressionTests.java @@ -0,0 +1,75 @@ +package org.springframework.binding.expression.support; + +import java.util.HashMap; +import java.util.Map; +import org.easymock.MockControl; + +import junit.framework.TestCase; + +/** + * Tests to exercise the extended method invoking expression extensions of JBoss-el. + * + * @author Jeremy Grelle + * + */ +public class ELMethodExpressionTests extends TestCase { + + ELExpressionParser parser = new ELExpressionParser(); + + Map context; + + Map container; + + TestMethods target; + MockControl targetMockControl; + + protected void setUp() throws Exception { + context = new HashMap(); + container = new HashMap(); + targetMockControl = MockControl.createControl(TestMethods.class); + target = (TestMethods) targetMockControl.getMock(); + context.put("container", container); + container.put("myObject", target); + } + + public void testWithIntParam() { + String expression = "#{container.myObject.doSomethingWithInt(container.param1)}"; + int param = 5; + container.put("param1", new Integer(param)); + target.doSomethingWithInt(param); + targetMockControl.replay(); + + parser.parseExpression(expression).evaluate(context, null); + targetMockControl.verify(); + + } + + public void testReturnWithIntParam() { + String expected = "sucess"; + String expression = "#{container.myObject.returnStringFromInt(container.param1)}"; + int param = 5; + container.put("param1", new Integer(param)); + targetMockControl.expectAndReturn(target.returnStringFromInt(param), expected); + targetMockControl.replay(); + + String result = (String) parser.parseExpression(expression).evaluate(context, null); + targetMockControl.verify(); + assertEquals(expected, result); + } + + public void testReturnWithIntAndObject() { + String expected = "success"; + String expression = "#{container.myObject.returnStringFromIntAndObject(container.param1, container.param2)}"; + int param1 = 5; + container.put("param1", new Integer(param1)); + TestBean param2 = new TestBean(); + container.put("param2", param2); + targetMockControl.expectAndReturn(target.returnStringFromIntAndObject(param1, param2), expected); + targetMockControl.replay(); + + String result = (String) parser.parseExpression(expression).evaluate(context, null); + targetMockControl.verify(); + assertEquals(expected, result); + } + +} diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodParsingTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodParsingTests.java new file mode 100644 index 00000000..45ab6bd4 --- /dev/null +++ b/spring-binding/src/test/java/org/springframework/binding/expression/support/ELMethodParsingTests.java @@ -0,0 +1,41 @@ +package org.springframework.binding.expression.support; + +import junit.framework.TestCase; + +import org.springframework.binding.expression.Expression; + +public class ELMethodParsingTests extends TestCase { + + ELExpressionParser parser; + + protected void setUp() throws Exception { + parser = new ELExpressionParser(); + } + + public void testEmptyMethod() { + + String expStr1 = "#{foo.bar()}"; + Expression result1 = parser.parseExpression(expStr1); + assertNotNull(result1); + assertEquals(expStr1, result1.toString()); + + String expStr2 = "foo.bar()"; + Expression result2 = parser.parseExpression(expStr2); + assertNotNull(result2); + assertEquals(expStr1, result2.toString()); + } + + public void testMethodWithParams() { + + String expStr1 = "#{foo.bar(moe.curly, groucho.harpo)}"; + Expression result1 = parser.parseExpression(expStr1); + assertNotNull(result1); + assertEquals(expStr1, result1.toString()); + + String expStr2 = "foo.bar(moe.curly, groucho.harpo)"; + Expression result2 = parser.parseExpression(expStr2); + assertNotNull(result2); + assertEquals(expStr1, result2.toString()); + } + +} diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/support/SimpleExpressionTests.java b/spring-binding/src/test/java/org/springframework/binding/expression/support/SimpleExpressionTests.java index 5d27c0b3..a274e57d 100644 --- a/spring-binding/src/test/java/org/springframework/binding/expression/support/SimpleExpressionTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/expression/support/SimpleExpressionTests.java @@ -1,94 +1,100 @@ -/* - * 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.expression.support; - -import java.util.ArrayList; -import java.util.List; - -import org.springframework.binding.expression.EvaluationException; -import org.springframework.binding.expression.ExpressionParser; -import org.springframework.binding.expression.ParserException; - -import junit.framework.TestCase; -import junit.framework.TestSuite; - -/** - * Tests simple expressions. Any expression language capable enough for - * real life usage should be able to pass these tests. - * - * @author Erwin Vervaet - */ -public class SimpleExpressionTests extends TestCase { - - private ExpressionParser expressionParser; - private TestBean bean; - - public static TestSuite suite() { - TestSuite suite = new TestSuite(); - suite.addTest(new SimpleExpressionTests("testGetValue", new OgnlExpressionParser())); - suite.addTest(new SimpleExpressionTests("testSetValue", new OgnlExpressionParser())); - suite.addTest(new SimpleExpressionTests("testSyntaxError", new OgnlExpressionParser())); - suite.addTest(new SimpleExpressionTests("testGetValue", new BeanWrapperExpressionParser())); - suite.addTest(new SimpleExpressionTests("testSetValue", new BeanWrapperExpressionParser())); - suite.addTest(new SimpleExpressionTests("testSyntaxError", new BeanWrapperExpressionParser())); - return suite; - } - - public SimpleExpressionTests(String name, ExpressionParser expressionParser) { - super(name); - this.expressionParser = expressionParser; - } - - protected void setUp() throws Exception { - bean = new TestBean(); - bean.setFlag(true); - List list = new ArrayList(); - list.add("foo"); - list.add("bar"); - bean.setList(list); - } - - public void testGetValue() { - assertEquals(Boolean.TRUE, expressionParser.parseExpression("${flag}").evaluate(bean, null)); - assertEquals(Boolean.TRUE, expressionParser.parseExpression("flag").evaluate(bean, null)); - assertSame(bean.getList(), expressionParser.parseExpression("${list}").evaluate(bean, null)); - assertEquals("foo", expressionParser.parseExpression("${list[0]}").evaluate(bean, null)); - } - - public void testSetValue() { - expressionParser.parseSettableExpression("${flag}").evaluateToSet(bean, Boolean.FALSE, null); - assertFalse(bean.isFlag()); - expressionParser.parseSettableExpression("flag").evaluateToSet(bean, Boolean.TRUE, null); - assertTrue(bean.isFlag()); - List newList = new ArrayList(); - newList.add("boo"); - expressionParser.parseSettableExpression("${list}").evaluateToSet(bean, newList, null); - assertSame(newList, bean.getList()); - expressionParser.parseSettableExpression("${list[0]}").evaluateToSet(bean, "baa", null); - assertEquals("baa", bean.getList().get(0)); - } - - public void testSyntaxError() { - try { - expressionParser.parseExpression("foo(").evaluate(bean, null); - fail("should have failed"); - } - catch (ParserException e) { - } - catch (EvaluationException e) { - } - } -} +/* + * 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.expression.support; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.binding.expression.EvaluationException; +import org.springframework.binding.expression.ExpressionParser; +import org.springframework.binding.expression.ParserException; + +import junit.framework.TestCase; +import junit.framework.TestSuite; + +/** + * Tests simple expressions. Any expression language capable enough for + * real life usage should be able to pass these tests. + * + * @author Erwin Vervaet + * @author Jeremy Grelle + */ +public class SimpleExpressionTests extends TestCase { + + private ExpressionParser expressionParser; + private String expressionPrefix; + private TestBean bean; + + public static TestSuite suite() { + TestSuite suite = new TestSuite(); + suite.addTest(new SimpleExpressionTests("testGetValue", new OgnlExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testSetValue", new OgnlExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testSyntaxError", new OgnlExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testGetValue", new BeanWrapperExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testSetValue", new BeanWrapperExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testSyntaxError", new BeanWrapperExpressionParser(), "$")); + suite.addTest(new SimpleExpressionTests("testGetValue", new ELExpressionParser(), "#")); + suite.addTest(new SimpleExpressionTests("testSetValue", new ELExpressionParser(), "#")); + suite.addTest(new SimpleExpressionTests("testSyntaxError", new ELExpressionParser(), "#")); + return suite; + } + + public SimpleExpressionTests(String name, ExpressionParser expressionParser, String expressionPrefix) { + super(name); + this.expressionParser = expressionParser; + this.expressionPrefix = expressionPrefix; + } + + protected void setUp() throws Exception { + bean = new TestBean(); + bean.setFlag(true); + List list = new ArrayList(); + list.add("foo"); + list.add("bar"); + bean.setList(list); + } + + public void testGetValue() { + assertEquals(Boolean.TRUE, expressionParser.parseExpression(expressionPrefix+"{flag}").evaluate(bean, null)); + assertEquals(Boolean.TRUE, expressionParser.parseExpression("flag").evaluate(bean, null)); + assertSame(bean.getList(), expressionParser.parseExpression(expressionPrefix+"{list}").evaluate(bean, null)); + assertEquals("foo", expressionParser.parseExpression(expressionPrefix+"{list[0]}").evaluate(bean, null)); + } + + public void testSetValue() { + expressionParser.parseSettableExpression(expressionPrefix+"{flag}").evaluateToSet(bean, Boolean.FALSE, null); + assertFalse(bean.isFlag()); + expressionParser.parseSettableExpression("flag").evaluateToSet(bean, Boolean.TRUE, null); + assertTrue(bean.isFlag()); + List newList = new ArrayList(); + newList.add("boo"); + expressionParser.parseSettableExpression(expressionPrefix+"{list}").evaluateToSet(bean, newList, null); + assertSame(newList, bean.getList()); + expressionParser.parseSettableExpression(expressionPrefix+"{list[0]}").evaluateToSet(bean, "baa", null); + assertEquals("baa", bean.getList().get(0)); + } + + public void testSyntaxError() { + try { + expressionParser.parseExpression("foo(").evaluate(bean, null); + fail("should have failed"); + } + catch (ParserException e) { + } + catch (EvaluationException e) { + } + } +} diff --git a/spring-binding/src/test/java/org/springframework/binding/expression/support/TestMethods.java b/spring-binding/src/test/java/org/springframework/binding/expression/support/TestMethods.java new file mode 100644 index 00000000..45f75b0f --- /dev/null +++ b/spring-binding/src/test/java/org/springframework/binding/expression/support/TestMethods.java @@ -0,0 +1,10 @@ +package org.springframework.binding.expression.support; + +public interface TestMethods { + + public void doSomethingWithInt(int arg); + + public String returnStringFromInt(int arg); + + public String returnStringFromIntAndObject(int arg, TestBean bean); +}