format system initial commit
This commit is contained in:
parent
9f4480a1b8
commit
07f19f7441
|
|
@ -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 <T> the type of object this formatter can format
|
||||||
|
*/
|
||||||
|
public interface Formatter<T> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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;
|
||||||
|
}
|
||||||
|
|
@ -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 <T> The type of formatter
|
||||||
|
* @param formatter the formatter
|
||||||
|
* @param registry the converter registry
|
||||||
|
*/
|
||||||
|
public static <T> void add(Formatter<T> formatter,
|
||||||
|
ConverterRegistry registry) {
|
||||||
|
registry.add(new FormattingConverter<T>(formatter));
|
||||||
|
registry.add(new ParsingConverter<T>(formatter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the Formatter/converter adapters previously registered for the formatted type.
|
||||||
|
* @param <T> the formatted type
|
||||||
|
* @param formattedType the formatted type
|
||||||
|
* @param registry the converter registry
|
||||||
|
*/
|
||||||
|
public static <T> void remove(Class<T> formattedType,
|
||||||
|
ConverterRegistry registry) {
|
||||||
|
registry.removeConverter(formattedType, String.class);
|
||||||
|
registry.removeConverter(String.class, formattedType);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<T> implements Converter<T, String> {
|
||||||
|
|
||||||
|
private Formatter<T> formatter;
|
||||||
|
|
||||||
|
public FormattingConverter(Formatter<T> formatter) {
|
||||||
|
this.formatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String convert(T source) {
|
||||||
|
return formatter.format(source, LocaleContextHolder.getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<T> implements Converter<String, T> {
|
||||||
|
|
||||||
|
private Formatter<T> formatter;
|
||||||
|
|
||||||
|
public ParsingConverter(Formatter<T> formatter) {
|
||||||
|
this.formatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
public T convert(String source) throws ParseException {
|
||||||
|
return formatter.parse(source, LocaleContextHolder.getLocale());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<BigDecimal> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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<BigDecimal> {
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<Long> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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<BigDecimal> {
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue