diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/Formatter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/Formatter.java new file mode 100644 index 00000000000..abf6197bad5 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/Formatter.java @@ -0,0 +1,74 @@ +/* + * Copyright 2004-2009 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. + */ +/* + * Copyright 2004-2009 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. + */ +/* + * Copyright 2004-2009 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.ui.format; + +import java.text.ParseException; +import java.util.Locale; + +/** + * Formats objects of type T for display. + * @author Keith Donald + * @param the type of object this formatter can format + */ +public interface Formatter { + + /** + * Format the object of type T for display. + * @param object the object to format + * @param locale the user's locale + * @return the formatted display string + */ + String format(T object, Locale locale); + + /** + * Parse an object from its formatted representation. + * @param formatted a formatted representation + * @param locale the user's locale + * @return the parsed object + * @throws ParseException when a parse exception occurs + */ + T parse(String formatted, Locale locale) throws ParseException; +} diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/FormatterConverterFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/FormatterConverterFactory.java new file mode 100644 index 00000000000..89def18352e --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/FormatterConverterFactory.java @@ -0,0 +1,52 @@ +/* + * Copyright 2004-2009 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.ui.format; + +import org.springframework.core.convert.converter.Converter; +import org.springframework.core.convert.converter.ConverterRegistry; + +/** + * A factory for adapting formatting and parsing logic in a {@link Formatter} to the {@link Converter} contract. + * @author Keith Donald + */ +public class FormatterConverterFactory { + + /** + * Register converter adapters for the formatter. + * An adapter will be registered for formatting to String as well as parsing from String. + * @param The type of formatter + * @param formatter the formatter + * @param registry the converter registry + */ + public static void add(Formatter formatter, + ConverterRegistry registry) { + registry.add(new FormattingConverter(formatter)); + registry.add(new ParsingConverter(formatter)); + } + + /** + * Remove the Formatter/converter adapters previously registered for the formatted type. + * @param the formatted type + * @param formattedType the formatted type + * @param registry the converter registry + */ + public static void remove(Class formattedType, + ConverterRegistry registry) { + registry.removeConverter(formattedType, String.class); + registry.removeConverter(String.class, formattedType); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/FormattingConverter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/FormattingConverter.java new file mode 100644 index 00000000000..ad9282647fd --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/FormattingConverter.java @@ -0,0 +1,33 @@ +/* + * Copyright 2004-2009 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.ui.format; + +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.convert.converter.Converter; + +class FormattingConverter implements Converter { + + private Formatter formatter; + + public FormattingConverter(Formatter formatter) { + this.formatter = formatter; + } + + public String convert(T source) { + return formatter.format(source, LocaleContextHolder.getLocale()); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/ParsingConverter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/ParsingConverter.java new file mode 100644 index 00000000000..95a37202c44 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/ParsingConverter.java @@ -0,0 +1,35 @@ +/* + * Copyright 2004-2009 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.ui.format; + +import java.text.ParseException; + +import org.springframework.context.i18n.LocaleContextHolder; +import org.springframework.core.convert.converter.Converter; + +class ParsingConverter implements Converter { + + private Formatter formatter; + + public ParsingConverter(Formatter formatter) { + this.formatter = formatter; + } + + public T convert(String source) throws ParseException { + return formatter.parse(source, LocaleContextHolder.getLocale()); + } + +} diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyFormatter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyFormatter.java new file mode 100644 index 00000000000..96a368356ce --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyFormatter.java @@ -0,0 +1,70 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.math.BigDecimal; +import java.math.RoundingMode; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import org.springframework.ui.format.Formatter; + +/** + * A BigDecimal formatter for currency values. + * Delegates to {@link NumberFormat#getCurrencyInstance(Locale)}. + * Configures BigDecimal parsing so there is no loss of precision. + * Sets the scale of parsed BigDecimal values to {@link NumberFormat#getMaximumFractionDigits()}. + * Applies {@link RoundingMode#DOWN} to parsed values. + * @author Keith Donald + */ +public class CurrencyFormatter implements Formatter { + + private CurrencyNumberFormatFactory currencyFormatFactory = new CurrencyNumberFormatFactory(); + + private boolean lenient; + + public String format(BigDecimal decimal, Locale locale) { + if (decimal == null) { + return ""; + } + NumberFormat format = currencyFormatFactory.getNumberFormat(locale); + return format.format(decimal); + } + + public BigDecimal parse(String formatted, Locale locale) + throws ParseException { + if (formatted.length() == 0) { + return null; + } + NumberFormat format = currencyFormatFactory.getNumberFormat(locale); + ParsePosition position = new ParsePosition(0); + BigDecimal decimal = (BigDecimal) format.parse(formatted, position); + if (position.getErrorIndex() != -1) { + throw new ParseException(formatted, position.getIndex()); + } + if (!lenient) { + if (formatted.length() != position.getIndex()) { + // indicates a part of the string that was not parsed + throw new ParseException(formatted, position.getIndex()); + } + } + decimal = decimal.setScale(format.getMaximumFractionDigits(), format.getRoundingMode()); + return decimal; + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyNumberFormatFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyNumberFormatFactory.java new file mode 100644 index 00000000000..f157e6ec8f2 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/CurrencyNumberFormatFactory.java @@ -0,0 +1,39 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.math.RoundingMode; +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +/** + * Produces NumberFormat instances that format currency values. + * + * @author Keith Donald + * @see NumberFormat + */ +final class CurrencyNumberFormatFactory extends NumberFormatFactory { + + private RoundingMode roundingMode = RoundingMode.DOWN; + + public NumberFormat getNumberFormat(Locale locale) { + DecimalFormat format = (DecimalFormat) NumberFormat.getCurrencyInstance(locale); + format.setParseBigDecimal(true); + format.setRoundingMode(roundingMode); + return format; + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/DecimalFormatter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/DecimalFormatter.java new file mode 100644 index 00000000000..fa41a4145de --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/DecimalFormatter.java @@ -0,0 +1,80 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import org.springframework.ui.format.Formatter; + +/** + * A BigDecimal formatter for decimal values. + * Delegates to {@link NumberFormat#getInstance(Locale)}. + * Configures BigDecimal parsing so there is no loss in precision. + * Allows configuration over the decimal number pattern; see {@link #DecimalFormatter(String)}. + * @author Keith Donald + */ +public class DecimalFormatter implements Formatter { + + private DefaultNumberFormatFactory formatFactory = new DefaultNumberFormatFactory(); + + private boolean lenient; + + public DecimalFormatter() { + initDefaults(); + } + + public DecimalFormatter(String pattern) { + initDefaults(); + formatFactory.setPattern(pattern); + } + + public String format(BigDecimal decimal, Locale locale) { + if (decimal == null) { + return ""; + } + NumberFormat format = formatFactory.getNumberFormat(locale); + return format.format(decimal); + } + + public BigDecimal parse(String formatted, Locale locale) + throws ParseException { + if (formatted.length() == 0) { + return null; + } + NumberFormat format = formatFactory.getNumberFormat(locale); + ParsePosition position = new ParsePosition(0); + BigDecimal decimal = (BigDecimal) format.parse(formatted, position); + if (position.getErrorIndex() != -1) { + throw new ParseException(formatted, position.getIndex()); + } + if (!lenient) { + if (formatted.length() != position.getIndex()) { + // indicates a part of the string that was not parsed + throw new ParseException(formatted, position.getIndex()); + } + } + return decimal; + } + + private void initDefaults() { + formatFactory.setParseBigDecimal(true); + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/DefaultNumberFormatFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/DefaultNumberFormatFactory.java new file mode 100644 index 00000000000..b10bad3da64 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/DefaultNumberFormatFactory.java @@ -0,0 +1,80 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +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. + * + * @author Keith Donald + * @see NumberFormat + * @see DecimalFormat + */ +class DefaultNumberFormatFactory extends NumberFormatFactory { + + private static Log logger = LogFactory.getLog(DefaultNumberFormatFactory.class); + + private String pattern; + + private Boolean parseBigDecimal; + + /** + * Sets the pattern to use to format number values. + * If not specified, the default DecimalFormat pattern is used. + * @param pattern the format pattern + * @see DecimalFormat#applyPattern(String) + */ + public void setPattern(String pattern) { + this.pattern = pattern; + } + + /** + * Sets whether the format should always parse a big decimal. + * @param parseBigDecimal the big decimal parse status + * @see DecimalFormat#setParseBigDecimal(boolean) + */ + public void setParseBigDecimal(boolean parseBigDecimal) { + this.parseBigDecimal = parseBigDecimal; + } + + public 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"); + } + } + if (parseBigDecimal != null) { + if (format instanceof DecimalFormat) { + ((DecimalFormat) format).setParseBigDecimal(parseBigDecimal); + } else { + logger.warn("Unable to call setParseBigDecimal; not a DecimalFormat"); + } + } + return format; + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerFormatter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerFormatter.java new file mode 100644 index 00000000000..22421b876f2 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerFormatter.java @@ -0,0 +1,64 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import org.springframework.ui.format.Formatter; + +/** + * A Long formatter for whole integer values. + * Delegates to {@link NumberFormat#getIntegerInstance(Locale)}. + * @author Keith Donald + */ +public class IntegerFormatter implements Formatter { + + private IntegerNumberFormatFactory formatFactory = new IntegerNumberFormatFactory(); + + private boolean lenient; + + public String format(Long integer, Locale locale) { + if (integer == null) { + return ""; + } + NumberFormat format = formatFactory.getNumberFormat(locale); + return format.format(integer); + } + + public Long parse(String formatted, Locale locale) + throws ParseException { + if (formatted.length() == 0) { + return null; + } + NumberFormat format = formatFactory.getNumberFormat(locale); + ParsePosition position = new ParsePosition(0); + Long integer = (Long) format.parse(formatted, position); + if (position.getErrorIndex() != -1) { + throw new ParseException(formatted, position.getIndex()); + } + if (!lenient) { + if (formatted.length() != position.getIndex()) { + // indicates a part of the string that was not parsed + throw new ParseException(formatted, position.getIndex()); + } + } + return integer; + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerNumberFormatFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerNumberFormatFactory.java new file mode 100644 index 00000000000..a7079cfb08c --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/IntegerNumberFormatFactory.java @@ -0,0 +1,31 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.text.NumberFormat; +import java.util.Locale; + +/** + * Produces NumberFormat instances that format integer values. + * + * @author Keith Donald + * @see NumberFormat + */ +final class IntegerNumberFormatFactory extends NumberFormatFactory { + public NumberFormat getNumberFormat(Locale locale) { + return NumberFormat.getIntegerInstance(locale); + } +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/NumberFormatFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/NumberFormatFactory.java new file mode 100644 index 00000000000..c8135140310 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/NumberFormatFactory.java @@ -0,0 +1,36 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.text.NumberFormat; +import java.util.Locale; + +/** + * A factory for {@link NumberFormat} objects. Conceals the complexity associated with configuring, constructing, and/or + * caching number format instances. + * + * @author Keith Donald + */ +abstract class NumberFormatFactory { + + /** + * Factory method that returns a fully-configured {@link NumberFormat} instance to use to format an object for + * display. + * @return the number format + */ + public abstract NumberFormat getNumberFormat(Locale locale); + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentFormatter.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentFormatter.java new file mode 100644 index 00000000000..c57c4e92a4a --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentFormatter.java @@ -0,0 +1,66 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.math.BigDecimal; +import java.text.NumberFormat; +import java.text.ParseException; +import java.text.ParsePosition; +import java.util.Locale; + +import org.springframework.ui.format.Formatter; + +/** + * A BigDecimal formatter for percent values. + * Delegates to {@link NumberFormat#getPercentInstance(Locale)}. + * Configures BigDecimal parsing so there is no loss in precision. + * @author Keith Donald + */ +public class PercentFormatter implements Formatter { + + private PercentNumberFormatFactory percentFormatFactory = new PercentNumberFormatFactory(); + + private boolean lenient; + + public String format(BigDecimal decimal, Locale locale) { + if (decimal == null) { + return ""; + } + NumberFormat format = percentFormatFactory.getNumberFormat(locale); + return format.format(decimal); + } + + public BigDecimal parse(String formatted, Locale locale) + throws ParseException { + if (formatted.length() == 0) { + return null; + } + NumberFormat format = percentFormatFactory.getNumberFormat(locale); + ParsePosition position = new ParsePosition(0); + BigDecimal decimal = (BigDecimal) format.parse(formatted, position); + if (position.getErrorIndex() != -1) { + throw new ParseException(formatted, position.getIndex()); + } + if (!lenient) { + if (formatted.length() != position.getIndex()) { + // indicates a part of the string that was not parsed + throw new ParseException(formatted, position.getIndex()); + } + } + return decimal; + } + +} \ No newline at end of file diff --git a/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentNumberFormatFactory.java b/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentNumberFormatFactory.java new file mode 100644 index 00000000000..1e2e914aa39 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/ui/format/number/PercentNumberFormatFactory.java @@ -0,0 +1,34 @@ +/* + * Copyright 2004-2009 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.ui.format.number; + +import java.text.DecimalFormat; +import java.text.NumberFormat; +import java.util.Locale; + +/** + * Produces NumberFormat instances that format percent values. + * + * @see NumberFormat + * @author Keith Donald + */ +final class PercentNumberFormatFactory extends NumberFormatFactory { + public NumberFormat getNumberFormat(Locale locale) { + DecimalFormat format = (DecimalFormat) NumberFormat.getPercentInstance(locale); + format.setParseBigDecimal(true); + return format; + } +} \ No newline at end of file diff --git a/org.springframework.context/src/test/java/org/springframework/ui/format/number/CurrencyFormatterTests.java b/org.springframework.context/src/test/java/org/springframework/ui/format/number/CurrencyFormatterTests.java new file mode 100644 index 00000000000..5a1c8b8ab5c --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/ui/format/number/CurrencyFormatterTests.java @@ -0,0 +1,50 @@ +package org.springframework.ui.format.number; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.Locale; + +import org.junit.Test; + +public class CurrencyFormatterTests { + + private CurrencyFormatter formatter = new CurrencyFormatter(); + + @Test + public void formatValue() { + assertEquals("$23.00", formatter.format(new BigDecimal("23"), Locale.US)); + } + + @Test + public void parseValue() throws ParseException { + assertEquals(new BigDecimal("23.56"), formatter.parse("$23.56", Locale.US)); + } + + @Test + public void parseEmptyValue() throws ParseException { + assertEquals(null, formatter.parse("", Locale.US)); + } + + @Test(expected = ParseException.class) + public void parseBogusValue() throws ParseException { + formatter.parse("bogus", Locale.US); + } + + @Test + public void parseValueDefaultRoundDown() throws ParseException { + assertEquals(new BigDecimal("23.56"), formatter.parse("$23.567", Locale.US)); + } + + @Test + public void parseWholeValue() throws ParseException { + assertEquals(new BigDecimal("23.00"), formatter.parse("$23", Locale.US)); + } + + @Test(expected=ParseException.class) + public void parseValueNotLenientFailure() throws ParseException { + formatter.parse("$23.56bogus", Locale.US); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/ui/format/number/DecimalFormatterTests.java b/org.springframework.context/src/test/java/org/springframework/ui/format/number/DecimalFormatterTests.java new file mode 100644 index 00000000000..268cb71bf7e --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/ui/format/number/DecimalFormatterTests.java @@ -0,0 +1,40 @@ +package org.springframework.ui.format.number; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.Locale; + +import org.junit.Test; + +public class DecimalFormatterTests { + + private DecimalFormatter formatter = new DecimalFormatter(); + + @Test + public void formatValue() { + assertEquals("23.56", formatter.format(new BigDecimal("23.56"), Locale.US)); + } + + @Test + public void parseValue() throws ParseException { + assertEquals(new BigDecimal("23.56"), formatter.parse("23.56", Locale.US)); + } + + @Test + public void parseEmptyValue() throws ParseException { + assertEquals(null, formatter.parse("", Locale.US)); + } + + @Test(expected = ParseException.class) + public void parseBogusValue() throws ParseException { + formatter.parse("bogus", Locale.US); + } + + @Test(expected = ParseException.class) + public void parsePercentValueNotLenientFailure() throws ParseException { + formatter.parse("23.56bogus", Locale.US); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/ui/format/number/IntegerFormatterTests.java b/org.springframework.context/src/test/java/org/springframework/ui/format/number/IntegerFormatterTests.java new file mode 100644 index 00000000000..b8b88209f39 --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/ui/format/number/IntegerFormatterTests.java @@ -0,0 +1,39 @@ +package org.springframework.ui.format.number; + +import static org.junit.Assert.assertEquals; + +import java.text.ParseException; +import java.util.Locale; + +import org.junit.Test; + +public class IntegerFormatterTests { + + private IntegerFormatter formatter = new IntegerFormatter(); + + @Test + public void formatValue() { + assertEquals("23", formatter.format(23L, Locale.US)); + } + + @Test + public void parseValue() throws ParseException { + assertEquals((Long) 2356L, formatter.parse("2356", Locale.US)); + } + + @Test + public void parseEmptyValue() throws ParseException { + assertEquals(null, formatter.parse("", Locale.US)); + } + + @Test(expected = ParseException.class) + public void parseBogusValue() throws ParseException { + formatter.parse("bogus", Locale.US); + } + + @Test(expected = ParseException.class) + public void parsePercentValueNotLenientFailure() throws ParseException { + formatter.parse("23.56", Locale.US); + } + +} diff --git a/org.springframework.context/src/test/java/org/springframework/ui/format/number/PercentFormatterTests.java b/org.springframework.context/src/test/java/org/springframework/ui/format/number/PercentFormatterTests.java new file mode 100644 index 00000000000..13e276fa84e --- /dev/null +++ b/org.springframework.context/src/test/java/org/springframework/ui/format/number/PercentFormatterTests.java @@ -0,0 +1,41 @@ +package org.springframework.ui.format.number; + +import static org.junit.Assert.assertEquals; + +import java.math.BigDecimal; +import java.text.ParseException; +import java.util.Locale; + +import org.junit.Test; + +public class PercentFormatterTests { + + private PercentFormatter formatter = new PercentFormatter(); + + @Test + public void formatValue() { + assertEquals("23%", formatter.format(new BigDecimal(".23"), Locale.US)); + } + + @Test + public void parseValue() throws ParseException { + assertEquals(new BigDecimal(".2356"), formatter.parse("23.56%", + Locale.US)); + } + + @Test + public void parseEmptyValue() throws ParseException { + assertEquals(null, formatter.parse("", Locale.US)); + } + + @Test(expected = ParseException.class) + public void parseBogusValue() throws ParseException { + formatter.parse("bogus", Locale.US); + } + + @Test(expected = ParseException.class) + public void parsePercentValueNotLenientFailure() throws ParseException { + formatter.parse("23.56%bogus", Locale.US); + } + +}