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 40f01aba..f535d95b 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 @@ -75,7 +75,9 @@ public class GenericConversionService implements ConversionService { } for (int j = 0; j < targetClasses.length; j++) { Class targetClass = targetClasses[j]; - sourceMap.put(targetClass, converter); + if (!targetClass.equals(sourceClass)) { + sourceMap.put(targetClass, converter); + } } } } 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 index da3e36b0..3dbbb9b4 100644 --- a/spring-binding/src/main/java/org/springframework/binding/format/Formatter.java +++ b/spring-binding/src/main/java/org/springframework/binding/format/Formatter.java @@ -16,17 +16,24 @@ package org.springframework.binding.format; /** - * Formats objects for display. + * 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 could not be formatted + * @throws IllegalArgumentException if the object is of the wrong type */ public String format(Object object) throws IllegalArgumentException; @@ -34,7 +41,7 @@ public interface Formatter { * 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 + * @throws InvalidFormatException the formatted string was in an invalid form, often due to user input error */ public Object parse(String formattedString) throws InvalidFormatException; 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 index 42a14eeb..33ed92c4 100644 --- a/spring-binding/src/main/java/org/springframework/binding/format/FormatterRegistry.java +++ b/spring-binding/src/main/java/org/springframework/binding/format/FormatterRegistry.java @@ -16,12 +16,7 @@ package org.springframework.binding.format; /** - * Source for shared and commonly used Formatters. - *

- * Note: formatters are typically not thread safe as Format objects aren't thread safe. In general, you - * should not attempt to share formatters between threads. - *

- * @see java.text.Format + * A Source for shared and commonly used Formatters. * * @author Keith Donald */ 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 index 799ab973..bc97f087 100644 --- 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 @@ -17,6 +17,7 @@ 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; /** @@ -26,16 +27,19 @@ import org.springframework.util.StringUtils; */ 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 if (Boolean.FALSE.equals(value)) { - return "false"; } else { - throw new IllegalArgumentException("Not a Boolean: " + value); + return "false"; } } diff --git a/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java b/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java index 70359f52..dba05850 100644 --- a/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java +++ b/spring-binding/src/main/java/org/springframework/binding/format/formatters/DateFormatter.java @@ -26,6 +26,7 @@ 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; /** @@ -79,10 +80,17 @@ 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); } 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 index d98dd78a..039b2b9d 100644 --- 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 @@ -30,9 +30,19 @@ import org.springframework.util.NumberUtils; import org.springframework.util.StringUtils; /** - * A formatter for common number types such as integers and big decimals. Allows the configuration of an explicit number - * pattern and locale. + * 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 { @@ -45,12 +55,15 @@ public class NumberFormatter implements Formatter { 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; } @@ -88,10 +101,37 @@ public class NumberFormatter implements Formatter { 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); } @@ -102,18 +142,28 @@ public class NumberFormatter implements Formatter { ParsePosition parsePosition = new ParsePosition(0); NumberFormat format = getNumberFormat(); Number number = format.parse(formattedString, parsePosition); - if (number == null || formattedString.length() != parsePosition.getIndex()) { + if (number == null) { + // no object could be parsed throw new InvalidFormatException(formattedString, getPattern(format)); - } else { - return NumberUtils.convertNumberToTargetClass(number, numberClass); } + 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 = NumberFormat.getInstance(locale); + NumberFormat format = createNumberFormat(locale); if (pattern != null) { if (format instanceof DecimalFormat) { ((DecimalFormat) format).applyPattern(pattern); @@ -125,6 +175,27 @@ public class NumberFormatter implements Formatter { 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) { 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 index 8e3745ee..ea4bb9f7 100644 --- 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 @@ -21,20 +21,27 @@ import org.springframework.binding.format.Formatter; import org.springframework.util.Assert; /** - * Adapts a {@link PropertyEditor} to the formatter interface. + * 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) { + 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; } /** @@ -44,13 +51,27 @@ public class PropertyEditorFormatter implements Formatter { return propertyEditor; } + // implementing Formatter + + public Class getObjectType() { + return objectType; + } + public String format(Object value) { - propertyEditor.setValue(value); - return propertyEditor.getAsText(); + synchronized (propertyEditor) { + propertyEditor.setValue(value); + String text = propertyEditor.getAsText(); + propertyEditor.setValue(null); + return text; + } } public Object parse(String formattedValue) { - propertyEditor.setAsText(formattedValue); - return propertyEditor.getValue(); + 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/registry/DefaultFormatterRegistry.java b/spring-binding/src/main/java/org/springframework/binding/format/registry/DefaultFormatterRegistry.java index 5a7d8524..3da13f07 100644 --- a/spring-binding/src/main/java/org/springframework/binding/format/registry/DefaultFormatterRegistry.java +++ b/spring-binding/src/main/java/org/springframework/binding/format/registry/DefaultFormatterRegistry.java @@ -17,12 +17,12 @@ package org.springframework.binding.format.registry; import java.math.BigDecimal; import java.math.BigInteger; -import java.util.Date; import org.springframework.binding.convert.service.DefaultConversionService; import org.springframework.binding.format.FormatterRegistry; import org.springframework.binding.format.formatters.BooleanFormatter; import org.springframework.binding.format.formatters.DateFormatter; +import org.springframework.binding.format.formatters.IntegerFormatter; import org.springframework.binding.format.formatters.NumberFormatter; public class DefaultFormatterRegistry extends GenericFormatterRegistry { @@ -43,16 +43,16 @@ public class DefaultFormatterRegistry extends GenericFormatterRegistry { * Registers the default formatters. Subclasses may override. */ protected void registerDefaultFormatters() { - registerFormatter(Integer.class, new NumberFormatter(Integer.class)); - registerFormatter(Long.class, new NumberFormatter(Long.class)); - registerFormatter(Short.class, new NumberFormatter(Short.class)); - registerFormatter(Float.class, new NumberFormatter(Float.class)); - registerFormatter(Double.class, new NumberFormatter(Double.class)); - registerFormatter(Byte.class, new NumberFormatter(Byte.class)); - registerFormatter(BigInteger.class, new NumberFormatter(BigInteger.class)); - registerFormatter(BigDecimal.class, new NumberFormatter(BigDecimal.class)); - registerFormatter(Boolean.class, new BooleanFormatter()); - registerFormatter(Date.class, new DateFormatter()); + registerFormatter(new IntegerFormatter(Integer.class)); + registerFormatter(new IntegerFormatter(BigInteger.class)); + registerFormatter(new IntegerFormatter(Long.class)); + registerFormatter(new IntegerFormatter(Short.class)); + registerFormatter(new NumberFormatter(Float.class)); + registerFormatter(new NumberFormatter(Double.class)); + registerFormatter(new NumberFormatter(BigDecimal.class)); + registerFormatter(new NumberFormatter(Byte.class)); + registerFormatter(new BooleanFormatter()); + registerFormatter(new DateFormatter()); } /** diff --git a/spring-binding/src/main/java/org/springframework/binding/format/registry/GenericFormatterRegistry.java b/spring-binding/src/main/java/org/springframework/binding/format/registry/GenericFormatterRegistry.java index 2c5ac964..707ed4a8 100644 --- a/spring-binding/src/main/java/org/springframework/binding/format/registry/GenericFormatterRegistry.java +++ b/spring-binding/src/main/java/org/springframework/binding/format/registry/GenericFormatterRegistry.java @@ -16,7 +16,6 @@ package org.springframework.binding.format.registry; import java.util.HashMap; -import java.util.LinkedList; import java.util.Map; import org.springframework.binding.format.Formatter; @@ -24,8 +23,10 @@ import org.springframework.binding.format.FormatterRegistry; import org.springframework.util.Assert; /** - * Base class for formatter factories. Manages the locale used by the produced formatters using Spring's - * {@link org.springframework.context.i18n.LocaleContext} system. + * A general-purpose {@link FormatterRegistry} implementation allows formatters to be registered programatically. + * + * @see #registerFormatter(Class, Formatter) + * @see #registerFormatter(String, Formatter) * * @author Keith Donald */ @@ -38,7 +39,7 @@ public class GenericFormatterRegistry implements FormatterRegistry { public Formatter getFormatter(Class clazz) { Assert.notNull(clazz, "The formatted class argument is required"); clazz = convertToWrapperClassIfNecessary(clazz); - return findFormatter(clazz); + return (Formatter) formattersByClass.get(clazz); } public Formatter getFormatter(String id) { @@ -48,9 +49,9 @@ public class GenericFormatterRegistry implements FormatterRegistry { // impl - public void registerFormatter(Class clazz, Formatter formatter) { + public void registerFormatter(Formatter formatter) { Assert.notNull(formatter, "The formatter to register is required"); - formattersByClass.put(clazz, formatter); + formattersByClass.put(formatter.getObjectType(), formatter); } public void registerFormatter(String id, Formatter formatter) { @@ -61,26 +62,6 @@ public class GenericFormatterRegistry implements FormatterRegistry { // helpers - private Formatter findFormatter(Class clazz) { - LinkedList classQueue = new LinkedList(); - classQueue.addFirst(clazz); - while (!classQueue.isEmpty()) { - clazz = (Class) classQueue.removeLast(); - Formatter factory = (Formatter) formattersByClass.get(clazz); - if (factory != null) { - return factory; - } - if (!clazz.isInterface() && clazz.getSuperclass() != null) { - classQueue.add(clazz.getSuperclass()); - } - Class[] interfaces = clazz.getInterfaces(); - for (int i = 0; i < interfaces.length; i++) { - classQueue.addFirst(interfaces[i]); - } - } - return null; - } - private Class convertToWrapperClassIfNecessary(Class targetType) { if (targetType.isPrimitive()) { if (targetType.equals(int.class)) { 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 e4da6b19..56c200d2 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 @@ -18,6 +18,7 @@ package org.springframework.binding.convert.service; import java.util.ArrayList; import java.util.HashMap; import java.util.List; +import java.util.Locale; import junit.framework.TestCase; @@ -25,7 +26,9 @@ 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; /** * Test case for the default conversion service. @@ -85,4 +88,20 @@ public class DefaultConversionServiceTests extends TestCase { Integer three = (Integer) executor.execute("3"); assertEquals(3, three.intValue()); } + + public void testRegisterConverter() { + GenericConversionService service = new GenericConversionService(); + IntegerFormatter formatter = new IntegerFormatter(Integer.class); + formatter.setLocale(Locale.US); + FormatterConverter converter = new FormatterConverter(formatter); + 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); + + } } \ No newline at end of file diff --git a/spring-binding/src/test/java/org/springframework/binding/format/formatters/NumberFormatterTests.java b/spring-binding/src/test/java/org/springframework/binding/format/formatters/NumberFormatterTests.java index ffb53884..c4038b45 100644 --- a/spring-binding/src/test/java/org/springframework/binding/format/formatters/NumberFormatterTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/format/formatters/NumberFormatterTests.java @@ -13,7 +13,7 @@ public class NumberFormatterTests extends TestCase { public void testFormatIntegerDefaultPattern() { formatter = new NumberFormatter(Integer.class); - formatter.setLocale(Locale.ENGLISH); + formatter.setLocale(Locale.US); String value = formatter.format(new Integer(12345)); assertEquals("12,345", value); } @@ -21,7 +21,7 @@ public class NumberFormatterTests extends TestCase { public void testFormatBigDecimalCustomPattern() { formatter = new NumberFormatter(BigDecimal.class); formatter.setPattern("000.00"); - formatter.setLocale(Locale.ENGLISH); + formatter.setLocale(Locale.US); BigDecimal dec = new BigDecimal("123.45"); String value = formatter.format(dec); assertEquals("123.45", value); @@ -34,7 +34,7 @@ public class NumberFormatterTests extends TestCase { public void testParseIntegerDefaultPattern() { formatter = new NumberFormatter(Integer.class); - formatter.setLocale(Locale.ENGLISH); + formatter.setLocale(Locale.US); Integer integer = (Integer) formatter.parse("123,450"); assertEquals(Integer.valueOf(123450), integer); } @@ -42,7 +42,7 @@ public class NumberFormatterTests extends TestCase { public void testParseBigDecimalCustomPattern() { formatter = new NumberFormatter(BigDecimal.class); formatter.setPattern("000.00"); - formatter.setLocale(Locale.ENGLISH); + formatter.setLocale(Locale.US); BigDecimal dec = (BigDecimal) formatter.parse("123.45"); assertEquals(new BigDecimal("123.45"), dec); } @@ -50,12 +50,32 @@ public class NumberFormatterTests extends TestCase { public void testParseInvalidFormatPatternTruncation() { try { formatter = new NumberFormatter(Integer.class); + formatter.setLocale(Locale.US); formatter.parse("123,450b"); fail("Should have failed"); } catch (InvalidFormatException e) { } } + public void testParseInvalidFormatPatternTruncationInteger() { + try { + formatter = new IntegerFormatter(Integer.class); + formatter.setLocale(Locale.US); + formatter.parse("123,450.00"); + fail("Should have failed"); + } catch (InvalidFormatException e) { + + } + } + + public void testParseInvalidFormatPatternLenient() { + formatter = new NumberFormatter(Integer.class); + formatter.setLocale(Locale.US); + formatter.setLenient(true); + Integer integer = (Integer) formatter.parse("123,450b"); + assertEquals(Integer.valueOf(123450), integer); + } + public void testParseInvalidFormatPattern() { try { formatter = new NumberFormatter(BigDecimal.class); diff --git a/spring-binding/src/test/java/org/springframework/binding/format/impl/GenericFormatterRegistryTests.java b/spring-binding/src/test/java/org/springframework/binding/format/impl/GenericFormatterRegistryTests.java index 7ca7f03d..4a779148 100644 --- a/spring-binding/src/test/java/org/springframework/binding/format/impl/GenericFormatterRegistryTests.java +++ b/spring-binding/src/test/java/org/springframework/binding/format/impl/GenericFormatterRegistryTests.java @@ -14,35 +14,34 @@ public class GenericFormatterRegistryTests extends TestCase { GenericFormatterRegistry registry = new GenericFormatterRegistry(); public void testRegisterAndGetFormatter() { - registry.registerFormatter(Integer.class, new NumberFormatter(Integer.class)); + registry.registerFormatter(new NumberFormatter(Integer.class)); Formatter formatter = registry.getFormatter(Integer.class); Integer value = (Integer) formatter.parse("3"); assertEquals(new Integer(3), value); } public void testRegisterAndGetFormatterAbstractClass() { - registry.registerFormatter(Number.class, new NumberFormatter(Long.class)); + registry.registerFormatter(new NumberFormatter(Number.class)); Formatter formatter = registry.getFormatter(Long.class); - Number value = (Number) formatter.parse("3"); - assertEquals(3L, value.longValue()); + assertNull(formatter); } public void testRegisterAndGetFormatterPrimitive() { - registry.registerFormatter(Integer.class, new NumberFormatter(Integer.class)); + registry.registerFormatter(new NumberFormatter(Integer.class)); Formatter formatter = registry.getFormatter(int.class); Integer value = (Integer) formatter.parse("3"); assertEquals(new Integer(3), value); } public void testRegisterAndGetFormatterInterface() { - registry.registerFormatter(CustomType.class, new CustomTypeFormatter()); - Formatter formatter = registry.getFormatter(DefaultCustomType.class); + registry.registerFormatter(new CustomTypeFormatter()); + Formatter formatter = registry.getFormatter(CustomType.class); assertEquals("12345", formatter.format(new DefaultCustomType("12345"))); assertEquals(new DefaultCustomType("12345"), formatter.parse("12345")); } public void testRegisterCustomFormatter() { - registry.registerFormatter(Integer.class, new NumberFormatter(Integer.class)); + registry.registerFormatter(new NumberFormatter(Integer.class)); NumberFormatter percentFormatter = new NumberFormatter(BigDecimal.class); percentFormatter.setPattern("00%"); registry.registerFormatter("percent", percentFormatter); @@ -53,7 +52,7 @@ public class GenericFormatterRegistryTests extends TestCase { } public void testRegisterCustomFormatterBogusLookupId() { - registry.registerFormatter(Integer.class, new NumberFormatter(Integer.class)); + registry.registerFormatter(new NumberFormatter(Integer.class)); registry.registerFormatter("double", new NumberFormatter(Double.class)); Formatter formatter = registry.getFormatter("bogusFormat"); assertNull(formatter); @@ -85,6 +84,10 @@ public class GenericFormatterRegistryTests extends TestCase { private class CustomTypeFormatter implements Formatter { + public Class getObjectType() { + return CustomType.class; + } + public String format(Object value) throws IllegalArgumentException { CustomType type = (CustomType) value; return type.getText();