diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionException.java b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionException.java index b1a78505..054742f0 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionException.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionException.java @@ -103,6 +103,20 @@ public class ConversionException extends NestedRuntimeException { this.targetClass = null; // not available } + /** + * Creates a new conversion exception. + * @param sourceClass the source type + * @param value the value we tried to convert + * @param targetClass the target type + * @param message a descriptive message + */ + public ConversionException(Class sourceClass, Object value, Class targetClass, String message) { + super(message); + this.sourceClass = sourceClass; + this.value = value; + this.targetClass = targetClass; + } + /** * Returns the source type. */ diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionExecutor.java b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionExecutor.java index 53efce5e..f8de988e 100644 --- a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionExecutor.java +++ b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionExecutor.java @@ -98,8 +98,13 @@ public class ConversionExecutor { * behavior of the converter */ public Object execute(Object source, ConversionContext context) throws ConversionException { - if (source != null) { - Assert.isInstanceOf(sourceClass, source, "Not of source type: "); + if (getTargetClass().isInstance(source)) { + // source is already assignment compatible with target class + return source; + } + if (source != null && !getSourceClass().isInstance(source)) { + throw new ConversionException(getSourceClass(), source, getTargetClass(), + "Source object '" + source + "' is expected to be a " + getSourceClass()); } return converter.convert(source, targetClass, context); } diff --git a/spring-binding/src/test/java/org/springframework/binding/convert/ConversionExecutorTests.java b/spring-binding/src/test/java/org/springframework/binding/convert/ConversionExecutorTests.java new file mode 100644 index 00000000..f6bfc89f --- /dev/null +++ b/spring-binding/src/test/java/org/springframework/binding/convert/ConversionExecutorTests.java @@ -0,0 +1,73 @@ +/* + * 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.convert; + +import java.util.Date; + +import junit.framework.TestCase; + +import org.springframework.binding.convert.support.AbstractConverter; + +/** + * Test case for {@link ConversionExecutor}. + */ +public class ConversionExecutorTests extends TestCase { + + private ConversionExecutor conversionExecutor; + + protected void setUp() throws Exception { + conversionExecutor = new ConversionExecutor(String.class, Date.class, new TestTextToDate()); + } + + public void testTypeConversion() { + assertTrue(conversionExecutor.execute("10-10-2008").getClass().equals(Date.class)); + } + + public void testAssignmentCompatibleTypeConversion() { + java.sql.Date date = new java.sql.Date(123L); + assertSame(date, conversionExecutor.execute(date)); + } + + public void testConvertNull() { + assertNull(conversionExecutor.execute(null)); + } + + public void testIllegalType() { + try { + conversionExecutor.execute(new StringBuffer()); + fail(); + } + catch (ConversionException e) { + // expected + } + } + + private class TestTextToDate extends AbstractConverter { + + public Class[] getSourceClasses() { + return new Class[] { String.class }; + } + + public Class[] getTargetClasses() { + return new Class[] { Date.class }; + } + + protected Object doConvert(Object source, Class targetClass, ConversionContext context) throws Exception { + return source == null ? null : new Date(); + } + } + +} diff --git a/spring-webflow/changelog.txt b/spring-webflow/changelog.txt index 572a6cde..89f406e1 100644 --- a/spring-webflow/changelog.txt +++ b/spring-webflow/changelog.txt @@ -8,6 +8,7 @@ Changes in version 1.0.4 (13.06.2007) Package org.springframework.binding * Fixed serializability problems in ConversionException, EvaluationException and MethodInvocationException. * Added targetCollection(String) method to MappingBuilder. +* ConversionExecutor now checks for assignment compatible types (SWF-337). Package org.springframework.webflow.action * Improved FormAction.setupForm() JavaDoc (SWF-325).