diff --git a/spring-binding/.settings/org.eclipse.jdt.core.prefs b/spring-binding/.settings/org.eclipse.jdt.core.prefs
index c416b20c..127f96ce 100644
--- a/spring-binding/.settings/org.eclipse.jdt.core.prefs
+++ b/spring-binding/.settings/org.eclipse.jdt.core.prefs
@@ -1,4 +1,4 @@
-#Wed Aug 15 08:35:04 EDT 2007
+#Mon Jun 30 01:12:48 EDT 2008
eclipse.preferences.version=1
org.eclipse.jdt.core.codeComplete.argumentPrefixes=
org.eclipse.jdt.core.codeComplete.argumentSuffixes=
@@ -9,22 +9,22 @@ org.eclipse.jdt.core.codeComplete.localSuffixes=
org.eclipse.jdt.core.codeComplete.staticFieldPrefixes=
org.eclipse.jdt.core.codeComplete.staticFieldSuffixes=
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
-org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.3
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.2
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
-org.eclipse.jdt.core.compiler.compliance=1.3
+org.eclipse.jdt.core.compiler.compliance=1.4
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.doc.comment.support=enabled
org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
-org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=warning
org.eclipse.jdt.core.compiler.problem.autoboxing=ignore
org.eclipse.jdt.core.compiler.problem.deprecation=warning
org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore
-org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=warning
org.eclipse.jdt.core.compiler.problem.fallthroughCase=ignore
org.eclipse.jdt.core.compiler.problem.fieldHiding=ignore
org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
diff --git a/spring-binding/.settings/org.eclipse.jdt.ui.prefs b/spring-binding/.settings/org.eclipse.jdt.ui.prefs
index 02fbb7e9..193deb8d 100644
--- a/spring-binding/.settings/org.eclipse.jdt.ui.prefs
+++ b/spring-binding/.settings/org.eclipse.jdt.ui.prefs
@@ -1,9 +1,8 @@
-#Wed Aug 15 08:38:35 EDT 2007
+#Wed Jun 25 10:24:03 EDT 2008
eclipse.preferences.version=1
editor_save_participant_org.eclipse.jdt.ui.postsavelistener.cleanup=true
formatter_profile=_Spring Java Conventions
formatter_settings_version=11
-internal.default.compliance=user
org.eclipse.jdt.ui.exception.name=e
org.eclipse.jdt.ui.gettersetter.use.is=false
org.eclipse.jdt.ui.javadoc=false
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 06ffa756..ba171f53 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
@@ -42,11 +42,4 @@ public interface ConversionExecutor {
*/
public Object execute(Object source) throws ConversionExecutionException;
- /**
- * Execute the conversion for the provided source object.
- * @param source the source object to convert
- * @param context the conversion context, useful for influencing the behavior of the converter
- */
- public Object execute(Object source, Object context) throws ConversionExecutionException;
-
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java
index a450e2c2..2ed8fad3 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/ConversionService.java
@@ -27,7 +27,7 @@ package org.springframework.binding.convert;
public interface ConversionService {
/**
- * Return a conversion executor command object capable of converting source objects of the specified
+ * Return the default conversion executor capable of converting source objects of the specified
* sourceClass to instances of the targetClass.
*
* The returned ConversionExecutor is thread-safe and may safely be cached for use in client code.
@@ -39,4 +39,18 @@ public interface ConversionService {
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
throws ConversionExecutorNotFoundException;
+ /**
+ * Return a custom conversion executor capable of converting source objects of the specified
+ * sourceClass to instances of the targetClass.
+ *
+ * The returned ConversionExecutor is thread-safe and may safely be cached for use in client code. + * @param id the id of the custom conversion executor (should be unique among custom converters) + * @param sourceClass the source class to convert from + * @param targetClass the target class to convert to + * @return the executor that can execute instance type conversion, never null + * @throws ConversionExecutorNotFoundException when no suitable conversion executor could be found + */ + public ConversionExecutor getConversionExecutor(String id, Class sourceClass, Class targetClass) + throws ConversionExecutorNotFoundException; + } \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/Converter.java b/spring-binding/src/main/java/org/springframework/binding/convert/Converter.java deleted file mode 100644 index 0c2b2894..00000000 --- a/spring-binding/src/main/java/org/springframework/binding/convert/Converter.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2004-2008 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 org.springframework.binding.format.Formatter; - -/** - * Converts objects from one type to another. May support conversion of multiple source types to multiple target types. - *
- * Implementations of this interface are thread-safe and can be shared. - *
- *- * A converter is more generic than a formatter. A formatter only handles converting from String and back, while - * converters convert from an arbitrary Object type to another. - *
- * @see Formatter - * @author Keith Donald - */ -public interface Converter { - - /** - * The source classes this converter can convert from. - * @return the supported source classes - */ - public Class[] getSourceClasses(); - - /** - * The target classes this converter can convert to. - * @return the supported target classes - */ - public Class[] getTargetClasses(); - - /** - * Convert the provided source object argument to an instance of the specified target class. - * @param source the source object to convert, its class must be one of the supportedsourceClasses
- * @param targetClass the target class to convert the source to, it must be one of the supported
- * targetClasses
- * @param context an optional conversion context that may be used to influence the conversion process
- * @return the converted object, an instance of the target type
- * @throws Exception an exception occurred performing the conversion
- */
- public Object convert(Object source, Class targetClass, Object context) throws Exception;
-
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java
new file mode 100644
index 00000000..67fb0d41
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToArray.java
@@ -0,0 +1,48 @@
+package org.springframework.binding.convert.converters;
+
+import java.lang.reflect.Array;
+
+import org.springframework.binding.convert.ConversionExecutor;
+import org.springframework.binding.convert.ConversionService;
+
+public class ArrayToArray implements Converter {
+
+ private ConversionService conversionService;
+
+ public ArrayToArray(ConversionService conversionService) {
+ this.conversionService = conversionService;
+ }
+
+ public Class getSourceClass() {
+ return Object[].class;
+ }
+
+ public Class getTargetClass() {
+ return Object[].class;
+ }
+
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
+ if (source == null) {
+ return null;
+ }
+ Class sourceComponentType = source.getClass().getComponentType();
+ if (!sourceComponentType.isPrimitive()) {
+ Object[] sourceArray = (Object[]) source;
+ Class targetComponentType = targetClass.getComponentType();
+ ConversionExecutor executor = conversionService.getConversionExecutor(sourceComponentType,
+ targetComponentType);
+ Object target = Array.newInstance(targetComponentType, sourceArray.length);
+ if (!targetComponentType.isPrimitive()) {
+ Object[] targetArray = (Object[]) target;
+ for (int i = 0; i < sourceArray.length; i++) {
+ targetArray[i] = executor.execute(sourceArray[i]);
+ }
+ return targetArray;
+ } else {
+ throw new UnsupportedOperationException("Primitive arrays not yet supported");
+ }
+ } else {
+ throw new UnsupportedOperationException("Primitive arrays not yet supported");
+ }
+ }
+}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
new file mode 100644
index 00000000..ec8a7303
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ArrayToCollection.java
@@ -0,0 +1,100 @@
+package org.springframework.binding.convert.converters;
+
+import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.springframework.binding.convert.ConversionExecutor;
+import org.springframework.binding.convert.ConversionService;
+import org.springframework.core.GenericCollectionTypeResolver;
+import org.springframework.core.JdkVersion;
+
+public class ArrayToCollection implements TwoWayConverter {
+
+ private ConversionService conversionService;
+
+ public ArrayToCollection(ConversionService conversionService) {
+ this.conversionService = conversionService;
+ }
+
+ public Class getSourceClass() {
+ return Object[].class;
+ }
+
+ public Class getTargetClass() {
+ return Collection.class;
+ }
+
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
+ if (source == null) {
+ return null;
+ }
+ Class collectionImplClass;
+ if (targetClass.isInterface()) {
+ if (List.class.equals(targetClass)) {
+ collectionImplClass = ArrayList.class;
+ } else if (Set.class.equals(targetClass)) {
+ collectionImplClass = LinkedHashSet.class;
+ } else if (SortedSet.class.equals(targetClass)) {
+ collectionImplClass = TreeSet.class;
+ } else {
+ throw new IllegalArgumentException("Unsupported collection interface [" + targetClass.getName() + "]");
+ }
+ } else {
+ collectionImplClass = targetClass;
+ }
+ Constructor constructor = collectionImplClass.getConstructor(null);
+ ConversionExecutor converter;
+ if (JdkVersion.isAtLeastJava15()) {
+ Class elementType = GenericCollectionTypeResolver.getCollectionType(targetClass);
+ if (elementType != null) {
+ Class componentType = source.getClass().getComponentType();
+ converter = conversionService.getConversionExecutor(componentType, elementType);
+ } else {
+ converter = null;
+ }
+ } else {
+ converter = null;
+ }
+ Collection collection = (Collection) constructor.newInstance(null);
+ Method add = collectionImplClass.getMethod("add", new Class[] { Object.class });
+ int length = Array.getLength(source);
+ if (converter != null) {
+ for (int i = 0; i < length; i++) {
+ Object value = Array.get(source, i);
+ value = converter.execute(value);
+ add.invoke(collection, new Object[] { value });
+ }
+ } else {
+ for (int i = 0; i < length; i++) {
+ Object value = Array.get(source, i);
+ add.invoke(collection, new Object[] { value });
+ }
+ }
+ return collection;
+ }
+
+ public Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception {
+ if (target == null) {
+ return null;
+ }
+ Collection collection = (Collection) target;
+ Object array = Array.newInstance(sourceClass.getComponentType(), collection.size());
+ int i = 0;
+ for (Iterator it = collection.iterator(); it.hasNext(); i++) {
+ Object value = it.next();
+ ConversionExecutor converter = conversionService.getConversionExecutor(value.getClass(), sourceClass
+ .getComponentType());
+ Array.set(array, i, converter.execute(value));
+ }
+ return array;
+ }
+}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/Converter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/Converter.java
new file mode 100644
index 00000000..4f1cae41
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/Converter.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * A converter is capable of converting a source object of type {@link #getSourceClass()} to a target type of type
+ * {@link #getTargetClass()}. If the converter is a {@link TwoWayConverter}, it can also convert from the target back
+ * to the source.
+ * + * Implementations of this interface are thread-safe and can be shared. + *
+ * @author Keith Donald + */ +public interface Converter { + + /** + * The source class this converter can convert from. May be an interface or abstract type to allow this converter to + * convert specific subclasses as well. + * @return the source type + */ + public Class getSourceClass(); + + /** + * The target class this converter can convert to. May be an interface or abstract type to allow this converter to + * convert specific subclasses as well. + * @return the target type + */ + public Class getTargetClass(); + + /** + * Convert the provided source object argument to an instance of the specified target class. + * @param source the source object to convert, which must be an instance of {@link #getSourceClass()} + * @param targetClass the target class to convert the source to, which must be equal to or a specialization of + * {@link #getTargetClass()} + * @return the converted object, which must be an instance of thetargetClass
+ * @throws Exception an exception occurred performing the conversion
+ */
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception;
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormattedStringToNumber.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormattedStringToNumber.java
new file mode 100644
index 00000000..379aff32
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormattedStringToNumber.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.text.ParsePosition;
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.binding.format.DefaultNumberFormatFactory;
+import org.springframework.binding.format.NumberFormatFactory;
+import org.springframework.util.NumberUtils;
+
+/**
+ * A converter for common number types such as integers and big decimals. Allows the configuration of an explicit number
+ * pattern and locale.
+ *
+ * Works with a general purpose {@link DecimalFormat} instance returned by calling
+ * {@link NumberFormat#getInstance(Locale)} by default. This instance supports parsing any number type generally and
+ * will not perform special type-specific logic such as rounding or truncation. Subclasses may override.
+ *
+ * Will coerse parsed Numbers to the desired numberClass as necessary. If type-coersion results in an overflow
+ * condition; for example, what can occur with a Long being coersed to a Short, an exception will be thrown.
+ *
+ * @see NumberFormat
+ * @see DecimalFormat
+ *
+ * @author Keith Donald
+ */
+public class FormattedStringToNumber extends StringToObject {
+
+ private static Log logger = LogFactory.getLog(FormattedStringToNumber.class);
+
+ private NumberFormatFactory numberFormatFactory = new DefaultNumberFormatFactory();
+
+ private boolean lenient;
+
+ public FormattedStringToNumber(Class numberClass) {
+ super(numberClass);
+ }
+
+ /**
+ * Sets the factory that returns the {@link NumberFormat} instance that will format numbers handled by this
+ * converter.
+ * @param numberFormatFactory the number format factory
+ */
+ public void setNumberFormatFactory(NumberFormatFactory numberFormatFactory) {
+ this.numberFormatFactory = numberFormatFactory;
+ }
+
+ /**
+ * If this Converter is "lenient" in parsing number strings. A lenient converter does not require that all
+ * characters in the String be parsed successfully. Default is false.
+ * @return the lenient flag
+ */
+ public boolean getLenient() {
+ return lenient;
+ }
+
+ /**
+ * Sets if this Converter should parse leniently.
+ * @param lenient the lenient flag
+ */
+ public void setLenient(boolean lenient) {
+ this.lenient = lenient;
+ }
+
+ protected Object toObject(String string, Class targetClass) throws Exception {
+ ParsePosition parsePosition = new ParsePosition(0);
+ NumberFormat format = numberFormatFactory.getNumberFormat();
+ Number number = format.parse(string, parsePosition);
+ if (number == null) {
+ // no object could be parsed
+ throw new InvalidFormatException(string, getPattern(format));
+ }
+ if (!lenient) {
+ if (string.length() != parsePosition.getIndex()) {
+ // indicates a part of the string that was not parsed; e.g. ".5" in 1234.5 when parsing an Integer
+ throw new InvalidFormatException(string, getPattern(format));
+ }
+ }
+ return convertToNumberClass(number, targetClass);
+ }
+
+ protected String toString(Object object) throws Exception {
+ Number number = (Number) object;
+ return numberFormatFactory.getNumberFormat().format(number);
+ }
+
+ /**
+ * Coerces the Number object returned by NumberFormat to the desired numberClass. Subclasses may override.
+ * @param number the parsed number
+ * @return the coersed number
+ * @throws IllegalArgumentException when an overflow condition occurs during coersion
+ */
+ protected Number convertToNumberClass(Number number, Class numberClass) throws IllegalArgumentException {
+ return NumberUtils.convertNumberToTargetClass(number, numberClass);
+ }
+
+ // internal helpers
+
+ private String getPattern(NumberFormat format) {
+ if (format instanceof DecimalFormat) {
+ return ((DecimalFormat) format).toPattern();
+ } else {
+ logger.warn("Pattern string cannot be determined because NumberFormat is not a DecimalFormat");
+ return "defaultNumberFormatInstance";
+ }
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormatterConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormatterConverter.java
deleted file mode 100644
index bd03212b..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/FormatterConverter.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2004-2008 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.converters;
-
-import org.springframework.binding.convert.Converter;
-import org.springframework.binding.format.Formatter;
-
-/**
- * Adapts a Formatter to the Converter interface. Allows a Formatter to be used as a Converter. Allows for both the
- * to-string and from-string logic to be used.
- *
- * @see Formatter
- * @see Formatter#format(Object)
- * @see Formatter#parse(String)
- *
- * @author Keith Donald
- */
-public class FormatterConverter implements Converter {
-
- private Formatter formatter;
-
- /**
- * Creates a new formatter converter.
- * @param formatter the formatter instance to adapt to the Converter API
- */
- public FormatterConverter(Formatter formatter) {
- this.formatter = formatter;
- }
-
- public Class[] getSourceClasses() {
- return new Class[] { formatter.getObjectType(), String.class };
- }
-
- public Class[] getTargetClasses() {
- return new Class[] { String.class, formatter.getObjectType() };
- }
-
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
- if (targetClass.equals(String.class)) {
- return formatter.format(source);
- } else {
- return formatter.parse((String) source);
- }
- }
-
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/InvalidFormatException.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/InvalidFormatException.java
similarity index 97%
rename from spring-binding/src/main/java/org/springframework/binding/format/InvalidFormatException.java
rename to spring-binding/src/main/java/org/springframework/binding/convert/converters/InvalidFormatException.java
index 7d43537b..96c8acde 100644
--- a/spring-binding/src/main/java/org/springframework/binding/format/InvalidFormatException.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/InvalidFormatException.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.binding.format;
+package org.springframework.binding.convert.converters;
/**
* Thrown when a formatted value is of the wrong form.
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java
new file mode 100644
index 00000000..1a9f230f
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ObjectToArray.java
@@ -0,0 +1,72 @@
+package org.springframework.binding.convert.converters;
+
+import java.lang.reflect.Array;
+
+import org.springframework.binding.convert.ConversionExecutor;
+import org.springframework.binding.convert.ConversionService;
+
+public class ObjectToArray implements TwoWayConverter {
+
+ private ConversionService conversionService;
+
+ public ObjectToArray(ConversionService conversionService) {
+ this.conversionService = conversionService;
+ }
+
+ public Class getSourceClass() {
+ return Object.class;
+ }
+
+ public Class getTargetClass() {
+ return Object[].class;
+ }
+
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
+ if (source == null) {
+ return null;
+ }
+ if (source instanceof String) {
+ String string = (String) source;
+ String[] elements = string.split(",");
+ Class componentType = targetClass.getComponentType();
+ Object array = Array.newInstance(componentType, elements.length);
+ ConversionExecutor converter = conversionService.getConversionExecutor(String.class, componentType);
+ for (int i = 0; i < elements.length; i++) {
+ String element = elements[i].trim();
+ Array.set(array, i, converter.execute(element));
+ }
+ return array;
+ } else {
+ Class componentType = targetClass.getComponentType();
+ Object array = Array.newInstance(componentType, 1);
+ ConversionExecutor converter = conversionService.getConversionExecutor(source.getClass(), componentType);
+ Array.set(array, 0, converter.execute(source));
+ return array;
+ }
+ }
+
+ public Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception {
+ if (target == null) {
+ return null;
+ }
+ if (String.class.equals(sourceClass)) {
+ int length = Array.getLength(target);
+ Class componentType = target.getClass().getComponentType();
+ ConversionExecutor converter = conversionService.getConversionExecutor(componentType, String.class);
+ StringBuffer buffer = new StringBuffer();
+ for (int i = 0; i < length; i++) {
+ Object value = Array.get(target, i);
+ buffer.append(converter.execute(value));
+ if (i < length) {
+ buffer.append(",");
+ }
+ }
+ } else {
+ Object value = Array.get(target, 0);
+ Class componentType = target.getClass().getComponentType();
+ ConversionExecutor converter = conversionService.getConversionExecutor(componentType, sourceClass);
+ return converter.execute(value);
+ }
+ return null;
+ }
+}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java
new file mode 100644
index 00000000..fd27d24b
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/ReverseConverter.java
@@ -0,0 +1,23 @@
+package org.springframework.binding.convert.converters;
+
+public class ReverseConverter implements Converter {
+
+ private TwoWayConverter converter;
+
+ public ReverseConverter(TwoWayConverter converter) {
+ this.converter = converter;
+ }
+
+ public Class getSourceClass() {
+ return converter.getTargetClass();
+ }
+
+ public Class getTargetClass() {
+ return converter.getSourceClass();
+ }
+
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
+ return converter.convertTargetToSourceClass(source, targetClass);
+ }
+
+}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToNumber.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigDecimal.java
similarity index 50%
rename from spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToNumber.java
rename to spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigDecimal.java
index e453a56f..4dd9da09 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToNumber.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigDecimal.java
@@ -16,30 +16,25 @@
package org.springframework.binding.convert.converters;
import java.math.BigDecimal;
-import java.math.BigInteger;
-
-import org.springframework.binding.convert.Converter;
-import org.springframework.util.NumberUtils;
/**
- * Converts textual representations of numbers to a Number specialization. Delegates to a synchronized
- * formatter to parse text strings.
+ * Converts a String to a BigDecimal.
*
* @author Keith Donald
*/
-public class TextToNumber implements Converter {
+public class StringToBigDecimal extends StringToObject {
- public Class[] getSourceClasses() {
- return new Class[] { String.class };
+ public StringToBigDecimal() {
+ super(BigDecimal.class);
}
- public Class[] getTargetClasses() {
- return new Class[] { Integer.class, Short.class, Long.class, Float.class, Double.class, Byte.class,
- BigInteger.class, BigDecimal.class };
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return new BigDecimal(string);
}
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
- return NumberUtils.parseNumber((String) source, targetClass);
+ public String toString(Object object) throws Exception {
+ BigDecimal number = (BigDecimal) object;
+ return number.toString();
}
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigInteger.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigInteger.java
new file mode 100644
index 00000000..a0887fb1
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBigInteger.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+import java.math.BigInteger;
+
+/**
+ * Converts a String to a BigInteger.
+ *
+ * @author Keith Donald
+ */
+public class StringToBigInteger extends StringToObject {
+
+ public StringToBigInteger() {
+ super(BigInteger.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return new BigInteger(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ BigInteger number = (BigInteger) object;
+ return number.toString();
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBoolean.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBoolean.java
new file mode 100644
index 00000000..caff4c92
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToBoolean.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a textual representation of a boolean object to a Boolean instance.
+ *
+ * @author Keith Donald
+ */
+public class StringToBoolean extends StringToObject {
+
+ private static final String VALUE_TRUE = "true";
+
+ private static final String VALUE_FALSE = "false";
+
+ private String trueString;
+
+ private String falseString;
+
+ /**
+ * Create a text boolean converter that parses standard true and false strings.
+ */
+ public StringToBoolean() {
+ super(Boolean.class);
+ }
+
+ /**
+ * Create a text to boolean converter that takes specific string representations of true and false into account.
+ * @param trueString special true string to use
+ * @param falseString special false string to use
+ */
+ public StringToBoolean(String trueString, String falseString) {
+ super(Boolean.class);
+ this.trueString = trueString;
+ this.falseString = falseString;
+ }
+
+ protected Object toObject(String string, Class targetClass) throws Exception {
+ if (trueString != null && string.equals(trueString)) {
+ return Boolean.TRUE;
+ } else if (falseString != null && string.equals(falseString)) {
+ return Boolean.FALSE;
+ } else if (trueString == null && string.equals(VALUE_TRUE)) {
+ return Boolean.TRUE;
+ } else if (falseString == null && string.equals(VALUE_FALSE)) {
+ return Boolean.FALSE;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value [" + string + "]");
+ }
+ }
+
+ protected String toString(Object object) throws Exception {
+ Boolean value = (Boolean) object;
+ if (Boolean.TRUE.equals(value)) {
+ if (trueString != null) {
+ return trueString;
+ } else {
+ return VALUE_TRUE;
+ }
+ } else if (Boolean.FALSE.equals(value)) {
+ if (falseString != null) {
+ return falseString;
+ } else {
+ return VALUE_FALSE;
+ }
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value [" + value + "]");
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToByte.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToByte.java
new file mode 100644
index 00000000..4a505317
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToByte.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to a BigInteger.
+ *
+ * @author Keith Donald
+ */
+public class StringToByte extends StringToObject {
+
+ public StringToByte() {
+ super(Byte.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Byte.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Byte number = (Byte) object;
+ return number.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java
new file mode 100644
index 00000000..c38b5de4
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToCharacter.java
@@ -0,0 +1,18 @@
+package org.springframework.binding.convert.converters;
+
+public class StringToCharacter extends StringToObject {
+
+ public StringToCharacter() {
+ super(Character.class);
+ }
+
+ protected Object toObject(String string, Class targetClass) throws Exception {
+ return new Character(string.charAt(0));
+ }
+
+ protected String toString(Object object) throws Exception {
+ Character character = (Character) object;
+ return character.toString();
+ }
+
+}
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java
new file mode 100644
index 00000000..c8d89c74
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToClass.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+import org.springframework.util.ClassUtils;
+
+/**
+ * Converts a textual representation of a class object to a Class instance.
+ *
+ * @author Keith Donald
+ */
+public class StringToClass extends StringToObject {
+
+ public StringToClass() {
+ super(Class.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return ClassUtils.forName(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Class clazz = (Class) object;
+ return clazz.getName();
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDate.java
similarity index 79%
rename from spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java
rename to spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDate.java
index dba05850..c3a1f903 100644
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDate.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.springframework.binding.format.formatters;
+package org.springframework.binding.convert.converters;
import java.text.DateFormat;
import java.text.ParseException;
@@ -23,10 +23,7 @@ import java.util.Locale;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import org.springframework.binding.format.Formatter;
-import org.springframework.binding.format.InvalidFormatException;
import org.springframework.context.i18n.LocaleContextHolder;
-import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
/**
@@ -34,9 +31,9 @@ import org.springframework.util.StringUtils;
* @see SimpleDateFormat
* @author Keith Donald
*/
-public class DateFormatter implements Formatter {
+public class StringToDate extends StringToObject {
- private static Log logger = LogFactory.getLog(DateFormatter.class);
+ private static Log logger = LogFactory.getLog(StringToDate.class);
/**
* The default date pattern.
@@ -47,6 +44,10 @@ public class DateFormatter implements Formatter {
private Locale locale;
+ public StringToDate() {
+ super(Date.class);
+ }
+
/**
* The pattern to use to format date values. If not specified, the default pattern 'yyyy-MM-dd' is used.
* @return the date formatting pattern
@@ -80,32 +81,26 @@ public class DateFormatter implements Formatter {
this.locale = locale;
}
- // implementing Formatter
-
- public Class getObjectType() {
- return Date.class;
- }
-
- public String format(Object date) {
- if (date == null) {
- return "";
- }
- Assert.isInstanceOf(Date.class, date, "Object is not a [java.util.Date]");
- return getDateFormat().format((Date) date);
- }
-
- public Object parse(String formattedString) throws InvalidFormatException {
- if (!StringUtils.hasText(formattedString)) {
+ public Object toObject(String string, Class targetClass) throws Exception {
+ if (!StringUtils.hasText(string)) {
return null;
}
DateFormat dateFormat = getDateFormat();
try {
- return dateFormat.parse(formattedString);
+ return dateFormat.parse(string);
} catch (ParseException e) {
- throw new InvalidFormatException(formattedString, getPattern(dateFormat), e);
+ throw new InvalidFormatException(string, getPattern(dateFormat), e);
}
}
+ public String toString(Object target) throws Exception {
+ Date date = (Date) target;
+ if (date == null) {
+ return "";
+ }
+ return getDateFormat().format(date);
+ }
+
// subclassing hookings
protected DateFormat getDateFormat() {
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDouble.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDouble.java
new file mode 100644
index 00000000..8533ebc4
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToDouble.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to an Short using {@link Short#valueOf(String)}.
+ *
+ * @author Keith Donald
+ */
+public class StringToDouble extends StringToObject {
+
+ public StringToDouble() {
+ super(Double.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Double.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Double number = (Double) object;
+ return number.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToFloat.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToFloat.java
new file mode 100644
index 00000000..190b2965
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToFloat.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to an Short using {@link Short#valueOf(String)}.
+ *
+ * @author Keith Donald
+ */
+public class StringToFloat extends StringToObject {
+
+ public StringToFloat() {
+ super(Float.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Float.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Float number = (Float) object;
+ return number.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToInteger.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToInteger.java
new file mode 100644
index 00000000..3135e341
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToInteger.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to an Integer using {@link Integer#valueOf(String)}.
+ *
+ * @author Keith Donald
+ */
+public class StringToInteger extends StringToObject {
+
+ public StringToInteger() {
+ super(Integer.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Integer.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Integer number = (Integer) object;
+ return number.toString();
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToLabeledEnum.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java
similarity index 74%
rename from spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToLabeledEnum.java
rename to spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java
index 35595243..3baab27a 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToLabeledEnum.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLabeledEnum.java
@@ -15,7 +15,6 @@
*/
package org.springframework.binding.convert.converters;
-import org.springframework.binding.convert.Converter;
import org.springframework.core.enums.LabeledEnum;
import org.springframework.core.enums.LabeledEnumResolver;
import org.springframework.core.enums.StaticLabeledEnumResolver;
@@ -25,20 +24,21 @@ import org.springframework.core.enums.StaticLabeledEnumResolver;
*
* @author Keith Donald
*/
-public class TextToLabeledEnum implements Converter {
+public class StringToLabeledEnum extends StringToObject {
private LabeledEnumResolver labeledEnumResolver = StaticLabeledEnumResolver.instance();
- public Class[] getSourceClasses() {
- return new Class[] { String.class };
+ public StringToLabeledEnum() {
+ super(LabeledEnum.class);
}
- public Class[] getTargetClasses() {
- return new Class[] { LabeledEnum.class };
+ protected Object toObject(String string, Class targetClass) throws Exception {
+ return labeledEnumResolver.getLabeledEnumByLabel(targetClass, string);
}
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
- String label = (String) source;
- return labeledEnumResolver.getLabeledEnumByLabel(targetClass, label);
+ protected String toString(Object object) throws Exception {
+ LabeledEnum labeledEnum = (LabeledEnum) object;
+ return labeledEnum.getLabel();
}
+
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLong.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLong.java
new file mode 100644
index 00000000..0b141f9e
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToLong.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to an Long using {@link Long#valueOf(String)}.
+ *
+ * @author Keith Donald
+ */
+public class StringToLong extends StringToObject {
+
+ public StringToLong() {
+ super(Long.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Long.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Long number = (Long) object;
+ return number.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java
new file mode 100644
index 00000000..f5e0114f
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToObject.java
@@ -0,0 +1,40 @@
+package org.springframework.binding.convert.converters;
+
+public abstract class StringToObject implements TwoWayConverter {
+
+ private Class objectClass;
+
+ public StringToObject(Class objectClass) {
+ this.objectClass = objectClass;
+ }
+
+ public final Class getSourceClass() {
+ return String.class;
+ }
+
+ public final Class getTargetClass() {
+ return objectClass;
+ }
+
+ public final Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
+ String string = (String) source;
+ if (string != null && string.length() > 0) {
+ return toObject(string, targetClass);
+ } else {
+ return null;
+ }
+ }
+
+ public final Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception {
+ if (target != null) {
+ return toString(target);
+ } else {
+ return "";
+ }
+ }
+
+ protected abstract Object toObject(String string, Class targetClass) throws Exception;
+
+ protected abstract String toString(Object object) throws Exception;
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToShort.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToShort.java
new file mode 100644
index 00000000..e0ad50f9
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/StringToShort.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * Converts a String to an Short using {@link Short#valueOf(String)}.
+ *
+ * @author Keith Donald
+ */
+public class StringToShort extends StringToObject {
+
+ public StringToShort() {
+ super(Short.class);
+ }
+
+ public Object toObject(String string, Class objectClass) throws Exception {
+ return Short.valueOf(string);
+ }
+
+ public String toString(Object object) throws Exception {
+ Short number = (Short) object;
+ return number.toString();
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToBoolean.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToBoolean.java
deleted file mode 100644
index 17730175..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToBoolean.java
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2004-2008 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.converters;
-
-import org.springframework.binding.convert.Converter;
-import org.springframework.util.StringUtils;
-
-/**
- * Converts a textual representation of a boolean object to a Boolean instance.
- *
- * @author Keith Donald
- */
-public class TextToBoolean implements Converter {
-
- private static final String VALUE_TRUE = "true";
-
- private static final String VALUE_FALSE = "false";
-
- private static final String VALUE_ON = "on";
-
- private static final String VALUE_OFF = "off";
-
- private static final String VALUE_YES = "yes";
-
- private static final String VALUE_NO = "no";
-
- private static final String VALUE_1 = "1";
-
- private static final String VALUE_0 = "0";
-
- private String trueString;
-
- private String falseString;
-
- /**
- * Default constructor. No special true or false strings are considered.
- */
- public TextToBoolean() {
- this(null, null);
- }
-
- /**
- * Create a text to boolean converter. Take given special string representations of true and false into
- * account.
- * @param trueString special true string to consider
- * @param falseString special false string to consider
- */
- public TextToBoolean(String trueString, String falseString) {
- this.trueString = trueString;
- this.falseString = falseString;
- }
-
- public Class[] getSourceClasses() {
- return new Class[] { String.class };
- }
-
- public Class[] getTargetClasses() {
- return new Class[] { Boolean.class };
- }
-
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
- String text = (String) source;
- if (!StringUtils.hasText(text)) {
- return null;
- } else if (this.trueString != null && text.equalsIgnoreCase(this.trueString)) {
- return Boolean.TRUE;
- } else if (this.falseString != null && text.equalsIgnoreCase(this.falseString)) {
- return Boolean.FALSE;
- } else if (this.trueString == null
- && (text.equalsIgnoreCase(VALUE_TRUE) || text.equalsIgnoreCase(VALUE_ON)
- || text.equalsIgnoreCase(VALUE_YES) || text.equals(VALUE_1))) {
- return Boolean.TRUE;
- } else if (this.falseString == null
- && (text.equalsIgnoreCase(VALUE_FALSE) || text.equalsIgnoreCase(VALUE_OFF)
- || text.equalsIgnoreCase(VALUE_NO) || text.equals(VALUE_0))) {
- return Boolean.FALSE;
- } else {
- throw new IllegalArgumentException("Invalid boolean value [" + text + "]");
- }
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToClass.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToClass.java
deleted file mode 100644
index d2179029..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TextToClass.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2004-2008 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.converters;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.springframework.binding.convert.Converter;
-import org.springframework.core.enums.LabeledEnum;
-import org.springframework.util.ClassUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * Converts a textual representation of a class object to a Class instance.
- *
- * @author Keith Donald
- */
-public class TextToClass implements Converter {
-
- private Map aliasMap = new HashMap();
-
- public TextToClass() {
- addDefaultAliases();
- }
-
- /**
- * Add an alias for given target type.
- */
- public void addAlias(String alias, Class targetType) {
- aliasMap.put(alias, targetType);
- }
-
- public Class[] getSourceClasses() {
- return new Class[] { String.class };
- }
-
- public Class[] getTargetClasses() {
- return new Class[] { Class.class };
- }
-
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
- String text = (String) source;
- if (StringUtils.hasText(text)) {
- text = text.trim();
- if (aliasMap.containsKey(text)) {
- return aliasMap.get(text);
- } else {
- return ClassUtils.forName(text);
- }
- } else {
- return null;
- }
- }
-
- protected void addDefaultAliases() {
- addAlias("string", String.class);
- addAlias("short", Short.class);
- addAlias("integer", Integer.class);
- addAlias("int", Integer.class);
- addAlias("byte", Byte.class);
- addAlias("long", Long.class);
- addAlias("float", Float.class);
- addAlias("double", Double.class);
- addAlias("bigInteger", BigInteger.class);
- addAlias("bigDecimal", BigDecimal.class);
- addAlias("boolean", Boolean.class);
- addAlias("class", Class.class);
- addAlias("labeledEnum", LabeledEnum.class);
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/converters/TwoWayConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/converters/TwoWayConverter.java
new file mode 100644
index 00000000..57ec4c3d
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/converters/TwoWayConverter.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2004-2008 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.converters;
+
+/**
+ * A converter that can also convert from the target back to the source.
+ *
+ * @author Keith Donald
+ */
+public interface TwoWayConverter extends Converter {
+
+ /**
+ * Convert the provided target object argument to an instance of the specified source class.
+ * @param target the target object to convert, which must be an instance of {@link #getTargetClass()}
+ * @param sourceClass the source class to convert the target to, which must be equal to or a specialization of
+ * {@link #getSourceClass()}
+ * @return the converted object, which must be an instance of the sourceClass
+ * @throws Exception an exception occurred performing the conversion
+ */
+ public Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception;
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
index d55f1a8b..177b4859 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/DefaultConversionService.java
@@ -16,10 +16,19 @@
package org.springframework.binding.convert.service;
import org.springframework.binding.convert.ConversionService;
-import org.springframework.binding.convert.converters.TextToBoolean;
-import org.springframework.binding.convert.converters.TextToClass;
-import org.springframework.binding.convert.converters.TextToLabeledEnum;
-import org.springframework.binding.convert.converters.TextToNumber;
+import org.springframework.binding.convert.converters.StringToBigDecimal;
+import org.springframework.binding.convert.converters.StringToBigInteger;
+import org.springframework.binding.convert.converters.StringToBoolean;
+import org.springframework.binding.convert.converters.StringToByte;
+import org.springframework.binding.convert.converters.StringToCharacter;
+import org.springframework.binding.convert.converters.StringToClass;
+import org.springframework.binding.convert.converters.StringToDate;
+import org.springframework.binding.convert.converters.StringToDouble;
+import org.springframework.binding.convert.converters.StringToFloat;
+import org.springframework.binding.convert.converters.StringToInteger;
+import org.springframework.binding.convert.converters.StringToLabeledEnum;
+import org.springframework.binding.convert.converters.StringToLong;
+import org.springframework.binding.convert.converters.StringToShort;
/**
* Default, local implementation of a conversion service. Will automatically register from string converters for
@@ -45,10 +54,19 @@ public class DefaultConversionService extends GenericConversionService {
* Add all default converters to the conversion service.
*/
protected void addDefaultConverters() {
- addConverter(new TextToClass());
- addConverter(new TextToBoolean());
- addConverter(new TextToLabeledEnum());
- addConverter(new TextToNumber());
+ addConverter(new StringToByte());
+ addConverter(new StringToBoolean());
+ addConverter(new StringToCharacter());
+ addConverter(new StringToShort());
+ addConverter(new StringToInteger());
+ addConverter(new StringToLong());
+ addConverter(new StringToFloat());
+ addConverter(new StringToDouble());
+ addConverter(new StringToBigInteger());
+ addConverter(new StringToBigDecimal());
+ addConverter(new StringToClass());
+ addConverter(new StringToLabeledEnum());
+ addConverter(new StringToDate());
}
/**
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
index f535d95b..e34a77a7 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/GenericConversionService.java
@@ -15,6 +15,8 @@
*/
package org.springframework.binding.convert.service;
+import java.lang.reflect.Modifier;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
@@ -23,7 +25,12 @@ import java.util.Map;
import org.springframework.binding.convert.ConversionExecutor;
import org.springframework.binding.convert.ConversionExecutorNotFoundException;
import org.springframework.binding.convert.ConversionService;
-import org.springframework.binding.convert.Converter;
+import org.springframework.binding.convert.converters.ArrayToArray;
+import org.springframework.binding.convert.converters.ArrayToCollection;
+import org.springframework.binding.convert.converters.Converter;
+import org.springframework.binding.convert.converters.ObjectToArray;
+import org.springframework.binding.convert.converters.ReverseConverter;
+import org.springframework.binding.convert.converters.TwoWayConverter;
import org.springframework.util.Assert;
/**
@@ -35,8 +42,8 @@ public class GenericConversionService implements ConversionService {
/**
* An indexed map of converters. Each entry key is a source class that can be converted from, and each entry value
- * is a map of target classes that can be convertered to, ultimately mapping to a specific converter that can
- * perform the source->target conversion.
+ * is a map of target classes that can be converted to, ultimately mapping to a specific converter that can perform
+ * the source->target conversion.
*/
private Map sourceClassConverters = new HashMap();
@@ -64,36 +71,65 @@ public class GenericConversionService implements ConversionService {
* @param converter the converter
*/
public void addConverter(Converter converter) {
- Class[] sourceClasses = converter.getSourceClasses();
- Class[] targetClasses = converter.getTargetClasses();
- for (int i = 0; i < sourceClasses.length; i++) {
- Class sourceClass = sourceClasses[i];
- Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
- if (sourceMap == null) {
- sourceMap = new HashMap();
- sourceClassConverters.put(sourceClass, sourceMap);
- }
- for (int j = 0; j < targetClasses.length; j++) {
- Class targetClass = targetClasses[j];
- if (!targetClass.equals(sourceClass)) {
- sourceMap.put(targetClass, converter);
- }
- }
+ Class sourceClass = converter.getSourceClass();
+ Class targetClass = converter.getTargetClass();
+ if (sourceClass.isPrimitive()) {
+ throw new IllegalArgumentException("Invalid Converter " + converter
+ + "; A primitive type is not allowed for the [sourceClass] argument");
}
+ if (targetClass.isPrimitive()) {
+ throw new IllegalArgumentException("Invalid Converter " + converter
+ + "; A primitive type is not allowed for the [targetClass] argument");
+ }
+ Map sourceMap = getSourceMap(sourceClass);
+ sourceMap.put(targetClass, converter);
+ if (converter instanceof TwoWayConverter) {
+ sourceMap = getSourceMap(targetClass);
+ sourceMap.put(sourceClass, new ReverseConverter((TwoWayConverter) converter));
+ }
+ }
+
+ private Map getSourceMap(Class sourceClass) {
+ Map sourceMap = (Map) sourceClassConverters.get(sourceClass);
+ if (sourceMap == null) {
+ sourceMap = new HashMap();
+ sourceClassConverters.put(sourceClass, sourceMap);
+ }
+ return sourceMap;
}
public ConversionExecutor getConversionExecutor(Class sourceClass, Class targetClass)
throws ConversionExecutorNotFoundException {
Assert.notNull(sourceClass, "The source class to convert from is required");
Assert.notNull(targetClass, "The target class to convert to is required");
- if (sourceClassConverters == null || sourceClassConverters.isEmpty()) {
- throw new IllegalStateException("No converters have been added to this service's registry");
- }
sourceClass = convertToWrapperClassIfNecessary(sourceClass);
targetClass = convertToWrapperClassIfNecessary(targetClass);
if (targetClass.isAssignableFrom(sourceClass)) {
return new StaticConversionExecutor(sourceClass, targetClass, new NoOpConverter(sourceClass, targetClass));
}
+ if (sourceClass.isArray()) {
+ if (targetClass.isArray()) {
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToArray(this));
+ } else if (Collection.class.isAssignableFrom(targetClass)) {
+ if (!targetClass.isInterface() && Modifier.isAbstract(targetClass.getModifiers())) {
+ throw new IllegalArgumentException("Conversion target class [" + targetClass.getName()
+ + "] is invalid; cannot convert to abstract collection types--"
+ + "request an interface or concrete implementation instead");
+ }
+ return new StaticConversionExecutor(sourceClass, targetClass, new ArrayToCollection(this));
+ } else {
+ Converter arrayToObject = new ReverseConverter(new ObjectToArray(this));
+ return new StaticConversionExecutor(sourceClass, targetClass, arrayToObject);
+ }
+ }
+ if (targetClass.isArray()) {
+ if (Collection.class.isAssignableFrom(sourceClass)) {
+ Converter collectionToArray = new ReverseConverter(new ArrayToCollection(this));
+ return new StaticConversionExecutor(sourceClass, targetClass, collectionToArray);
+ } else {
+ return new StaticConversionExecutor(sourceClass, targetClass, new ObjectToArray(this));
+ }
+ }
Map sourceTargetConverters = findConvertersForSource(sourceClass);
Converter converter = findTargetConverter(sourceTargetConverters, targetClass);
if (converter != null) {
@@ -111,6 +147,11 @@ public class GenericConversionService implements ConversionService {
}
}
+ public ConversionExecutor getConversionExecutor(String id, Class sourceClass, Class targetClass)
+ throws ConversionExecutorNotFoundException {
+ throw new UnsupportedOperationException("Not yet implemented");
+ }
+
// subclassing support
/**
@@ -143,7 +184,7 @@ public class GenericConversionService implements ConversionService {
if (sourceTargetConverters != null && !sourceTargetConverters.isEmpty()) {
return sourceTargetConverters;
}
- if (!sourceClass.isInterface() && (sourceClass.getSuperclass() != null)) {
+ if (!sourceClass.isInterface() && sourceClass.getSuperclass() != null) {
classQueue.addFirst(sourceClass.getSuperclass());
}
// queue up source class's implemented interfaces.
@@ -164,7 +205,7 @@ public class GenericConversionService implements ConversionService {
if (converter != null) {
return converter;
}
- if (!targetClass.isInterface() && (targetClass.getSuperclass() != null)) {
+ if (!targetClass.isInterface() && targetClass.getSuperclass() != null) {
classQueue.addFirst(targetClass.getSuperclass());
}
// queue up target class's implemented interfaces.
@@ -201,4 +242,5 @@ public class GenericConversionService implements ConversionService {
return targetType;
}
}
+
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java
index 582747d6..3c331480 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/NoOpConverter.java
@@ -15,7 +15,7 @@
*/
package org.springframework.binding.convert.service;
-import org.springframework.binding.convert.Converter;
+import org.springframework.binding.convert.converters.Converter;
/**
* Package private converter that is a "no op".
@@ -36,15 +36,24 @@ class NoOpConverter implements Converter {
this.targetClass = targetClass;
}
- public Object convert(Object source, Class targetClass, Object context) throws Exception {
+ public Class getSourceClass() {
+ return sourceClass;
+ }
+
+ public Class getTargetClass() {
+ return targetClass;
+ }
+
+ public Object convertSourceToTargetClass(Object source, Class targetClass) throws Exception {
return source;
}
- public Class[] getSourceClasses() {
- return new Class[] { sourceClass };
+ public boolean isTwoWay() {
+ return true;
}
- public Class[] getTargetClasses() {
- return new Class[] { targetClass };
+ public Object convertTargetToSourceClass(Object target, Class sourceClass) throws Exception,
+ UnsupportedOperationException {
+ return target;
}
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/convert/service/StaticConversionExecutor.java b/spring-binding/src/main/java/org/springframework/binding/convert/service/StaticConversionExecutor.java
index 9e7e2334..52754390 100644
--- a/spring-binding/src/main/java/org/springframework/binding/convert/service/StaticConversionExecutor.java
+++ b/spring-binding/src/main/java/org/springframework/binding/convert/service/StaticConversionExecutor.java
@@ -17,7 +17,7 @@ package org.springframework.binding.convert.service;
import org.springframework.binding.convert.ConversionExecutionException;
import org.springframework.binding.convert.ConversionExecutor;
-import org.springframework.binding.convert.Converter;
+import org.springframework.binding.convert.converters.Converter;
import org.springframework.core.style.ToStringCreator;
import org.springframework.util.Assert;
@@ -87,10 +87,6 @@ public class StaticConversionExecutor implements ConversionExecutor {
}
public Object execute(Object source) throws ConversionExecutionException {
- return execute(source, null);
- }
-
- public Object execute(Object source, Object context) throws ConversionExecutionException {
if (targetClass.isInstance(source)) {
// source is already assignment compatible with target class
return source;
@@ -100,7 +96,7 @@ public class StaticConversionExecutor implements ConversionExecutor {
+ source + " is expected to be an instance of " + getSourceClass());
}
try {
- return converter.convert(source, targetClass, context);
+ return converter.convertSourceToTargetClass(source, targetClass);
} catch (Exception e) {
throw new ConversionExecutionException(source, getSourceClass(), getTargetClass(), e);
}
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/AbstractNumberFormatFactory.java b/spring-binding/src/main/java/org/springframework/binding/format/AbstractNumberFormatFactory.java
new file mode 100644
index 00000000..4e2185f4
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/format/AbstractNumberFormatFactory.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2004-2008 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.format;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import org.springframework.context.i18n.LocaleContextHolder;
+
+/**
+ * Base class suitable for subclassing by most {@link NumberFormatFactory} implementations.
+ *
+ * @author Keith Donald
+ */
+public abstract class AbstractNumberFormatFactory implements NumberFormatFactory {
+
+ private Locale locale;
+
+ /**
+ * The locale to use in formatting number values. If null, the locale associated with the current thread is used.
+ * @see LocaleContextHolder#getLocale()
+ * @return the locale
+ */
+ public Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Sets the locale to use in formatting number values.
+ * @param locale the locale
+ */
+ public void setLocale(Locale locale) {
+ this.locale = locale;
+ }
+
+ public final NumberFormat getNumberFormat() {
+ Locale locale = determineLocale(this.locale);
+ return getNumberFormat(locale);
+ }
+
+ /**
+ * Subclasses should override to create the new NumberFormat instance.
+ * @param locale the locale to use
+ * @return the number format
+ */
+ protected abstract NumberFormat getNumberFormat(Locale locale);
+
+ // internal helpers
+
+ private Locale determineLocale(Locale locale) {
+ return locale != null ? locale : LocaleContextHolder.getLocale();
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/CurrencyNumberFormatFactory.java b/spring-binding/src/main/java/org/springframework/binding/format/CurrencyNumberFormatFactory.java
new file mode 100644
index 00000000..0e59651e
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/format/CurrencyNumberFormatFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004-2008 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.format;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Produces NumberFormat instances that format currency values.
+ *
+ * @see NumberFormat
+ * @author Keith Donald
+ */
+public class CurrencyNumberFormatFactory extends AbstractNumberFormatFactory {
+ protected NumberFormat getNumberFormat(Locale locale) {
+ return NumberFormat.getCurrencyInstance(locale);
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/DefaultNumberFormatFactory.java b/spring-binding/src/main/java/org/springframework/binding/format/DefaultNumberFormatFactory.java
new file mode 100644
index 00000000..9b391e2c
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/format/DefaultNumberFormatFactory.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2004-2008 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.format;
+
+import java.text.DecimalFormat;
+import java.text.NumberFormat;
+import java.util.Locale;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Works with a general purpose {@link DecimalFormat} instance returned by calling
+ * {@link NumberFormat#getInstance(Locale)} by default. This instance supports parsing any number type generally and
+ * will not perform special type-specific logic such as rounding or truncation.
+ *
+ * @see NumberFormat
+ * @see DecimalFormat
+ *
+ * @author Keith Donald
+ */
+public class DefaultNumberFormatFactory extends AbstractNumberFormatFactory {
+
+ private static Log logger = LogFactory.getLog(DefaultNumberFormatFactory.class);
+
+ private String pattern;
+
+ /**
+ * The pattern to use to format number values. If not specified, the default DecimalFormat pattern is used.
+ * @return the date formatting pattern
+ */
+ public String getPattern() {
+ return pattern;
+ }
+
+ /**
+ * Sets the pattern for formatting numbers.
+ * @param pattern the format pattern
+ * @see DecimalFormat
+ */
+ public void setPattern(String pattern) {
+ this.pattern = pattern;
+ }
+
+ protected NumberFormat getNumberFormat(Locale locale) {
+ NumberFormat format = NumberFormat.getInstance(locale);
+ if (pattern != null) {
+ if (format instanceof DecimalFormat) {
+ ((DecimalFormat) format).applyPattern(pattern);
+ } else {
+ logger.warn("Unable to apply format pattern '" + pattern
+ + "'; Returned NumberFormat is not a DecimalFormat");
+ }
+ }
+ return format;
+ }
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/Formatter.java b/spring-binding/src/main/java/org/springframework/binding/format/Formatter.java
deleted file mode 100644
index 3dbbb9b4..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/Formatter.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2004-2008 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.format;
-
-/**
- * Formats objects of a certain class for display.
- *
- * @author Keith Donald
- */
-public interface Formatter {
-
- /**
- * Returns the type of object this Formatter formats. Successful {@link #parse(String) parse calls} will return
- * instances of this type. {@link #format(Object)} callers must provide an instance of this type.
- * @return the type of object being formatted
- */
- public Class getObjectType();
-
- /**
- * Format the object for display.
- * @param object the object to format
- * @return the formatted string, fit for display in a UI
- * @throws IllegalArgumentException if the object is of the wrong type
- */
- public String format(Object object) throws IllegalArgumentException;
-
- /**
- * Parse the formatted string representation of an object and return the object.
- * @param formattedString the formatted string representation
- * @return the parsed object
- * @throws InvalidFormatException the formatted string was in an invalid form, often due to user input error
- */
- public Object parse(String formattedString) throws InvalidFormatException;
-
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/FormatterRegistry.java b/spring-binding/src/main/java/org/springframework/binding/format/FormatterRegistry.java
deleted file mode 100644
index a7bfa72e..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/FormatterRegistry.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2004-2008 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.format;
-
-/**
- * A Source for shared and commonly used Formatters.
- *
- * @author Keith Donald
- */
-public interface FormatterRegistry {
-
- /**
- * Returns the default formatter installed for the given class of object.
- * @param clazz the type of object that will be formatted
- * @return the formatter
- */
- public Formatter getFormatter(Class clazz);
-
- /**
- * Returns the formatter for the given class of object with the given id. Use this method to query a custom
- * formatter instance for a given class of object.
- * @param clazz the type of object that will be formatted
- * @param id the id of the custom formatter instance; typically descriptive like "localDate"
- * @return the formatter
- */
- public Formatter getFormatter(Class clazz, String id);
-
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/IntegerFormatter.java b/spring-binding/src/main/java/org/springframework/binding/format/IntegerNumberFormatFactory.java
similarity index 61%
rename from spring-binding/src/main/java/org/springframework/binding/format/formatters/IntegerFormatter.java
rename to spring-binding/src/main/java/org/springframework/binding/format/IntegerNumberFormatFactory.java
index c50ff952..22c8877b 100644
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/IntegerFormatter.java
+++ b/spring-binding/src/main/java/org/springframework/binding/format/IntegerNumberFormatFactory.java
@@ -1,36 +1,29 @@
/*
* Copyright 2004-2008 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.format.formatters;
+package org.springframework.binding.format;
import java.text.NumberFormat;
import java.util.Locale;
/**
- * The default formatter for integer instances that are whole numbers and do not have fractions, such as Integers,
- * Longs, and Shorts. Simply delegates to {@link NumberFormat#getIntegerInstance(Locale)}.
- *
+ * @see NumberFormat
* @author Keith Donald
*/
-public class IntegerFormatter extends NumberFormatter {
-
- public IntegerFormatter(Class numberClass) {
- super(numberClass);
- }
-
- protected NumberFormat createNumberFormat(Locale locale) {
+public class IntegerNumberFormatFactory extends AbstractNumberFormatFactory {
+ protected NumberFormat getNumberFormat(Locale locale) {
return NumberFormat.getIntegerInstance(locale);
}
}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/NumberFormatFactory.java b/spring-binding/src/main/java/org/springframework/binding/format/NumberFormatFactory.java
new file mode 100644
index 00000000..2212556a
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/format/NumberFormatFactory.java
@@ -0,0 +1,20 @@
+package org.springframework.binding.format;
+
+import java.text.NumberFormat;
+
+/**
+ * A factory for {@link NumberFormat} objects. Conceals the complexity associated with configuring, constructing, and/or
+ * caching number format instances.
+ *
+ * @author Keith Donald
+ */
+public interface NumberFormatFactory {
+
+ /**
+ * Factory method that returns a fully-configured {@link NumberFormat} instance to use to format an object for
+ * display.
+ * @return returns the number for a
+ */
+ public NumberFormat getNumberFormat();
+
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/PercentNumberFormatFactory.java b/spring-binding/src/main/java/org/springframework/binding/format/PercentNumberFormatFactory.java
new file mode 100644
index 00000000..52305028
--- /dev/null
+++ b/spring-binding/src/main/java/org/springframework/binding/format/PercentNumberFormatFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2004-2008 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.format;
+
+import java.text.NumberFormat;
+import java.util.Locale;
+
+/**
+ * Produces NumberFormat instances that format percent values.
+ *
+ * @see NumberFormat
+ * @author Keith Donald
+ */
+public class PercentNumberFormatFactory extends AbstractNumberFormatFactory {
+ protected NumberFormat getNumberFormat(Locale locale) {
+ return NumberFormat.getPercentInstance(locale);
+ }
+}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/BooleanFormatter.java b/spring-binding/src/main/java/org/springframework/binding/format/formatters/BooleanFormatter.java
deleted file mode 100644
index bc97f087..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/BooleanFormatter.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2004-2008 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.format.formatters;
-
-import org.springframework.binding.format.Formatter;
-import org.springframework.binding.format.InvalidFormatException;
-import org.springframework.util.Assert;
-import org.springframework.util.StringUtils;
-
-/**
- * A formatter for boolean values. Formats {@link Boolean#TRUE} as "true" and {@link Boolean#FALSE} as "false".
- *
- * @author Keith Donald
- */
-public class BooleanFormatter implements Formatter {
-
- public Class getObjectType() {
- return Boolean.class;
- }
-
- public String format(Object value) throws IllegalArgumentException {
- if (value == null) {
- return "";
- }
- Assert.isInstanceOf(Boolean.class, value, "Object is not a [java.lang.Boolean]");
- if (Boolean.TRUE.equals(value)) {
- return "true";
- } else {
- return "false";
- }
- }
-
- public Object parse(String formattedString) throws InvalidFormatException {
- if (!StringUtils.hasText(formattedString)) {
- return null;
- }
- if (formattedString.equals("true")) {
- return Boolean.TRUE;
- } else if (formattedString.equals("false")) {
- return Boolean.FALSE;
- } else {
- throw new InvalidFormatException(formattedString, "true | false");
- }
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/NumberFormatter.java b/spring-binding/src/main/java/org/springframework/binding/format/formatters/NumberFormatter.java
deleted file mode 100644
index 039b2b9d..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/NumberFormatter.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2004-2008 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.format.formatters;
-
-import java.text.DecimalFormat;
-import java.text.NumberFormat;
-import java.text.ParsePosition;
-import java.util.Locale;
-
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-import org.springframework.binding.format.Formatter;
-import org.springframework.binding.format.InvalidFormatException;
-import org.springframework.context.i18n.LocaleContextHolder;
-import org.springframework.util.Assert;
-import org.springframework.util.NumberUtils;
-import org.springframework.util.StringUtils;
-
-/**
- * A general formatter for common number types such as integers and big decimals. Allows the configuration of an
- * explicit number pattern and locale.
- *
- * Works with a general purpose {@link DecimalFormat} instance returned by calling
- * {@link NumberFormat#getInstance(Locale)} by default. This instance supports parsing any number type generally and
- * will not perform special type-specific logic such as rounding or truncation. Subclasses may override.
- *
- * Will coerse parsed Numbers to the desired numberClass as necessary. If type-coersion results in an overflow
- * condition; for example, what can occur with a Long being coersed to a Short, an exception will be thrown.
- *
- * @see NumberFormat
- * @see DecimalFormat
- *
- * @author Keith Donald
- */
-public class NumberFormatter implements Formatter {
-
- private static Log logger = LogFactory.getLog(NumberFormatter.class);
-
- private String pattern;
-
- private Class numberClass;
-
- private Locale locale;
-
- private boolean lenient;
-
- /**
- * Creates a number formatter for the specified number type.
- * @param numberClass the number type, a class extending from {@link Number}.
- */
- public NumberFormatter(Class numberClass) {
- Assert.notNull(numberClass, "The number class is required");
- Assert.isTrue(Number.class.isAssignableFrom(numberClass), "The class must extend from Number");
- this.numberClass = numberClass;
- }
-
- /**
- * The pattern to use to format number values. If not specified, the default DecimalFormat pattern is used.
- * @return the date formatting pattern
- */
- public String getPattern() {
- return pattern;
- }
-
- /**
- * Sets the pattern for formatting numbers.
- * @param pattern the format pattern
- * @see DecimalFormat
- */
- public void setPattern(String pattern) {
- this.pattern = pattern;
- }
-
- /**
- * The locale to use in formatting number values. If null, the locale associated with the current thread is used.
- * @see LocaleContextHolder#getLocale()
- * @return the locale
- */
- public Locale getLocale() {
- return locale;
- }
-
- /**
- * Sets the locale to use in formatting number values.
- * @param locale the locale
- */
- public void setLocale(Locale locale) {
- this.locale = locale;
- }
-
- /**
- * If this Formatter is "lenient" in parsing number strings. A lenient formatter does not require that all
- * characters in the String be parsed successfully. Default is false.
- * @return the lenient flag
- */
- public boolean getLenient() {
- return lenient;
- }
-
- /**
- * Sets if this Formatter should parse leniently.
- * @param lenient the lenient flag
- */
- public void setLenient(boolean lenient) {
- this.lenient = lenient;
- }
-
- // implementing Formatter
-
- public Class getObjectType() {
- return numberClass;
- }
-
- public String format(Object number) {
- if (number == null) {
- return "";
- }
- if (!numberClass.isInstance(number)) {
- throw new IllegalArgumentException("Object is not a [" + numberClass.getName() + "]; it is a ["
- + number.getClass().getName() + "]");
- }
- return getNumberFormat().format(number);
- }
-
- public Object parse(String formattedString) throws InvalidFormatException {
- if (!StringUtils.hasText(formattedString)) {
- return null;
- }
- ParsePosition parsePosition = new ParsePosition(0);
- NumberFormat format = getNumberFormat();
- Number number = format.parse(formattedString, parsePosition);
- if (number == null) {
- // no object could be parsed
- throw new InvalidFormatException(formattedString, getPattern(format));
- }
- if (!lenient) {
- if (formattedString.length() != parsePosition.getIndex()) {
- // indicates a part of the string that was not parsed; e.g. ".5" in 1234.5 when parsing an Integer
- throw new InvalidFormatException(formattedString, getPattern(format));
- }
- }
- return convertToNumberClass(number);
- }
-
- // subclassing hookings
-
- /**
- * Factory method that returns a fully-configured {@link NumberFormat} instance to use to format an object for
- * display. Applies the locale and pattern properties if configured. Subclasses may override.
- */
- protected NumberFormat getNumberFormat() {
- Locale locale = determineLocale(this.locale);
- NumberFormat format = createNumberFormat(locale);
- if (pattern != null) {
- if (format instanceof DecimalFormat) {
- ((DecimalFormat) format).applyPattern(pattern);
- } else {
- logger.warn("Unable to apply format pattern '" + pattern
- + "'; Returned NumberFormat is not a DecimalFormat");
- }
- }
- return format;
- }
-
- /**
- * Delegates to the {@link NumberFormat java.text.NumberFormat API} to construct the new NumberFormat instance.
- * Called by {@link #getNumberFormat()} after calculating the Locale. Subclasses may override to control how the
- * Format instance is constructed.
- * @param locale the calculated Locale
- * @return the new NumberFormat instance
- */
- protected NumberFormat createNumberFormat(Locale locale) {
- return NumberFormat.getInstance(locale);
- }
-
- /**
- * Coerces the Number object returned by NumberFormat to the desired numberClass. Subclasses may override.
- * @param number the parsed number
- * @return the coersed number
- * @throws IllegalArgumentException when an overflow condition occurs during coersion
- */
- protected Number convertToNumberClass(Number number) throws IllegalArgumentException {
- return NumberUtils.convertNumberToTargetClass(number, numberClass);
- }
-
- // internal helpers
-
- private Locale determineLocale(Locale locale) {
- return locale != null ? locale : LocaleContextHolder.getLocale();
- }
-
- private String getPattern(NumberFormat format) {
- if (format instanceof DecimalFormat) {
- return ((DecimalFormat) format).toPattern();
- } else {
- logger.warn("Pattern string cannot be determined because NumberFormat is not a DecimalFormat");
- return "defaultNumberFormatInstance";
- }
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/PropertyEditorFormatter.java b/spring-binding/src/main/java/org/springframework/binding/format/formatters/PropertyEditorFormatter.java
deleted file mode 100644
index ea4bb9f7..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/PropertyEditorFormatter.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2004-2008 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.format.formatters;
-
-import java.beans.PropertyEditor;
-
-import org.springframework.binding.format.Formatter;
-import org.springframework.util.Assert;
-
-/**
- * Adapts a {@link PropertyEditor} to the formatter interface. Useful for re-using pre-existing PropertyEditors as
- * Formatters.
- *
- * Note: this class synchronizes calls into the configured PropertyEditor instance to ensure thread safety.
- *
- * @author Keith Donald
- */
-public class PropertyEditorFormatter implements Formatter {
-
- private Class objectType;
-
- private PropertyEditor propertyEditor;
-
- /**
- * Wrap the given property editor in a formatter.
- */
- public PropertyEditorFormatter(PropertyEditor propertyEditor, Class objectType) {
- Assert.notNull(propertyEditor, "The PropertyEditor is required");
- Assert.notNull(objectType, "The object type is required");
- this.propertyEditor = propertyEditor;
- this.objectType = objectType;
- }
-
- /**
- * Returns the wrapped property editor.
- */
- public PropertyEditor getPropertyEditor() {
- return propertyEditor;
- }
-
- // implementing Formatter
-
- public Class getObjectType() {
- return objectType;
- }
-
- public String format(Object value) {
- synchronized (propertyEditor) {
- propertyEditor.setValue(value);
- String text = propertyEditor.getAsText();
- propertyEditor.setValue(null);
- return text;
- }
- }
-
- public Object parse(String formattedValue) {
- synchronized (propertyEditor) {
- propertyEditor.setAsText(formattedValue);
- Object value = propertyEditor.getValue();
- propertyEditor.setValue(null);
- return value;
- }
- }
-}
\ No newline at end of file
diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/package.html b/spring-binding/src/main/java/org/springframework/binding/format/formatters/package.html
deleted file mode 100644
index 11cf8142..00000000
--- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/package.html
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
--Common Formatter implementations. -
- - \ No newline at end of file diff --git a/spring-binding/src/main/java/org/springframework/binding/mapping/impl/DefaultMapping.java b/spring-binding/src/main/java/org/springframework/binding/mapping/impl/DefaultMapping.java index 573f5e83..96613c03 100644 --- a/spring-binding/src/main/java/org/springframework/binding/mapping/impl/DefaultMapping.java +++ b/spring-binding/src/main/java/org/springframework/binding/mapping/impl/DefaultMapping.java @@ -123,7 +123,7 @@ public class DefaultMapping implements Mapping { if (sourceValue != null) { if (typeConverter != null) { try { - targetValue = typeConverter.execute(sourceValue, context); + targetValue = typeConverter.execute(sourceValue); } catch (ConversionExecutionException e) { context.setTypeConversionErrorResult(e); return; @@ -142,7 +142,7 @@ public class DefaultMapping implements Mapping { ConversionExecutor typeConverter = conversionService.getConversionExecutor(sourceValue .getClass(), targetType); try { - targetValue = typeConverter.execute(sourceValue, context); + targetValue = typeConverter.execute(sourceValue); } catch (ConversionExecutionException e) { context.setTypeConversionErrorResult(e); return; diff --git a/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java b/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java index 56c200d2..0ef0b2c1 100644 --- a/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/convert/service/DefaultConversionServiceTests.java @@ -15,8 +15,11 @@ */ package org.springframework.binding.convert.service; +import java.util.AbstractList; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; +import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -25,10 +28,10 @@ import junit.framework.TestCase; import org.springframework.binding.convert.ConversionExecutionException; import org.springframework.binding.convert.ConversionExecutor; import org.springframework.binding.convert.ConversionExecutorNotFoundException; -import org.springframework.binding.convert.Converter; -import org.springframework.binding.convert.converters.FormatterConverter; -import org.springframework.binding.convert.converters.TextToBoolean; -import org.springframework.binding.format.formatters.IntegerFormatter; +import org.springframework.binding.convert.converters.Converter; +import org.springframework.binding.convert.converters.FormattedStringToNumber; +import org.springframework.binding.convert.converters.StringToBoolean; +import org.springframework.binding.format.DefaultNumberFormatFactory; /** * Test case for the default conversion service. @@ -39,10 +42,8 @@ public class DefaultConversionServiceTests extends TestCase { public void testConvertCompatibleTypes() { DefaultConversionService service = new DefaultConversionService(); - List lst = new ArrayList(); assertSame(lst, service.getConversionExecutor(ArrayList.class, List.class).execute(lst)); - try { service.getConversionExecutor(List.class, ArrayList.class); fail(); @@ -52,10 +53,8 @@ public class DefaultConversionServiceTests extends TestCase { } public void testOverrideConverter() { - Converter customConverter = new TextToBoolean("ja", "nee"); - + Converter customConverter = new StringToBoolean("ja", "nee"); DefaultConversionService service = new DefaultConversionService(); - StaticConversionExecutor executor = (StaticConversionExecutor) service.getConversionExecutor(String.class, Boolean.class); assertNotSame(customConverter, executor.getConverter()); @@ -65,9 +64,7 @@ public class DefaultConversionServiceTests extends TestCase { } catch (ConversionExecutionException e) { // expected } - service.addConverter(customConverter); - executor = (StaticConversionExecutor) service.getConversionExecutor(String.class, Boolean.class); assertSame(customConverter, executor.getConverter()); assertTrue(((Boolean) executor.execute("ja")).booleanValue()); @@ -87,21 +84,204 @@ public class DefaultConversionServiceTests extends TestCase { ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class); Integer three = (Integer) executor.execute("3"); assertEquals(3, three.intValue()); + + ConversionExecutor executor2 = service.getConversionExecutor(Integer.class, String.class); + String threeString = (String) executor2.execute(new Integer(3)); + assertEquals("3", threeString); } public void testRegisterConverter() { GenericConversionService service = new GenericConversionService(); - IntegerFormatter formatter = new IntegerFormatter(Integer.class); - formatter.setLocale(Locale.US); - FormatterConverter converter = new FormatterConverter(formatter); + FormattedStringToNumber converter = new FormattedStringToNumber(Integer.class); + DefaultNumberFormatFactory numberFormatFactory = new DefaultNumberFormatFactory(); + numberFormatFactory.setLocale(Locale.US); + converter.setNumberFormatFactory(numberFormatFactory); service.addConverter(converter); ConversionExecutor executor = service.getConversionExecutor(String.class, Integer.class); Integer three = (Integer) executor.execute("3,000"); assertEquals(3000, three.intValue()); - ConversionExecutor executor2 = service.getConversionExecutor(Integer.class, String.class); String string = (String) executor2.execute(new Integer(3000)); assertEquals("3,000", string); - } + + public void testConversionPrimitive() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String.class, int.class); + Integer three = (Integer) executor.execute("3"); + assertEquals(3, three.intValue()); + } + + public void testArrayConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String[].class, Integer[].class); + Integer[] result = (Integer[]) executor.execute(new String[] { "1", "2", "3" }); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + public void testPrimitiveArrayConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String[].class, int[].class); + int[] result = (int[]) executor.execute(new String[] { "1", "2", "3" }); + assertEquals(1, result[0]); + assertEquals(2, result[1]); + assertEquals(3, result[2]); + } + + public void testArrayListConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String[].class, List.class); + List result = (List) executor.execute(new String[] { "1", "2", "3" }); + assertEquals("1", result.get(0)); + assertEquals("2", result.get(1)); + assertEquals("3", result.get(2)); + } + + public void testListArrayConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(Collection.class, String[].class); + List list = new ArrayList(); + list.add("1"); + list.add("2"); + list.add("3"); + String[] result = (String[]) executor.execute(list); + assertEquals("1", result[0]); + assertEquals("2", result[1]); + assertEquals("3", result[2]); + } + + public void testListArrayConversionWithComponentConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(Collection.class, Integer[].class); + List list = new ArrayList(); + list.add("1"); + list.add("2"); + list.add("3"); + Integer[] result = (Integer[]) executor.execute(list); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + public void testArrayLinkedListConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String[].class, LinkedList.class); + LinkedList result = (LinkedList) executor.execute(new String[] { "1", "2", "3" }); + assertEquals("1", result.get(0)); + assertEquals("2", result.get(1)); + assertEquals("3", result.get(2)); + } + + public void testArrayAbstractListConversion() { + DefaultConversionService service = new DefaultConversionService(); + try { + service.getConversionExecutor(String[].class, AbstractList.class); + } catch (IllegalArgumentException e) { + + } + } + + public void testToArrayConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String.class, String[].class); + String[] result = (String[]) executor.execute("1,2,3"); + assertEquals("1", result[0]); + assertEquals("2", result[1]); + assertEquals("3", result[2]); + } + + public void testToArrayConversionWithElementConversion() { + DefaultConversionService service = new DefaultConversionService(); + ConversionExecutor executor = service.getConversionExecutor(String.class, Integer[].class); + Integer[] result = (Integer[]) executor.execute("1,2,3"); + assertEquals(new Integer(1), result[0]); + assertEquals(new Integer(2), result[1]); + assertEquals(new Integer(3), result[2]); + } + + /* + * + * public void testArrayListConversionWithElementConversion() throws Exception { DefaultConversionService service = + * new DefaultConversionService(); ConversionExecutor executor = service.getConversionExecutor(String[].class, + * IntegerArrayList.class); List result = (List) executor.execute(new String[] { "1", "2", "3" }); assertEquals(new + * Integer(1), result.get(0)); assertEquals(new Integer(2), result.get(1)); assertEquals(new Integer(3), + * result.get(2)); } + * + * + * public static class IntegerArrayList implements List