001: /*
002: * Copyright 2002-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.beans.propertyeditors;
018:
019: import java.beans.PropertyEditorSupport;
020: import java.text.NumberFormat;
021:
022: import org.springframework.util.NumberUtils;
023: import org.springframework.util.StringUtils;
024:
025: /**
026: * Property editor for any Number subclass like Integer, Long, Float, Double.
027: * Can use a given NumberFormat for (locale-specific) parsing and rendering,
028: * or alternatively the default <code>valueOf</code> respectively
029: * <code>toString</code> methods.
030: *
031: * <p>This is not meant to be used as system PropertyEditor but rather as
032: * locale-specific number editor within custom controller code, to parse
033: * user-entered number strings into Number properties of beans, and render
034: * them in the UI form.
035: *
036: * <p>In web MVC code, this editor will typically be registered with
037: * <code>binder.registerCustomEditor</code> calls in an implementation
038: * of BaseCommandController's <code>initBinder</code> method.
039: *
040: * @author Juergen Hoeller
041: * @since 06.06.2003
042: * @see java.lang.Number
043: * @see java.text.NumberFormat
044: * @see org.springframework.validation.DataBinder#registerCustomEditor
045: * @see org.springframework.web.servlet.mvc.BaseCommandController#initBinder
046: */
047: public class CustomNumberEditor extends PropertyEditorSupport {
048:
049: private final Class numberClass;
050:
051: private final NumberFormat numberFormat;
052:
053: private final boolean allowEmpty;
054:
055: /**
056: * Create a new CustomNumberEditor instance, using the default
057: * <code>valueOf</code> methods for parsing and <code>toString</code>
058: * methods for rendering.
059: * <p>The "allowEmpty" parameter states if an empty String should
060: * be allowed for parsing, i.e. get interpreted as <code>null</code> value.
061: * Else, an IllegalArgumentException gets thrown in that case.
062: * @param numberClass Number subclass to generate
063: * @param allowEmpty if empty strings should be allowed
064: * @throws IllegalArgumentException if an invalid numberClass has been specified
065: * @see org.springframework.util.NumberUtils#parseNumber(String, Class)
066: * @see Integer#valueOf
067: * @see Integer#toString
068: */
069: public CustomNumberEditor(Class numberClass, boolean allowEmpty)
070: throws IllegalArgumentException {
071: this (numberClass, null, allowEmpty);
072: }
073:
074: /**
075: * Create a new CustomNumberEditor instance, using the given NumberFormat
076: * for parsing and rendering.
077: * <p>The allowEmpty parameter states if an empty String should
078: * be allowed for parsing, i.e. get interpreted as <code>null</code> value.
079: * Else, an IllegalArgumentException gets thrown in that case.
080: * @param numberClass Number subclass to generate
081: * @param numberFormat NumberFormat to use for parsing and rendering
082: * @param allowEmpty if empty strings should be allowed
083: * @throws IllegalArgumentException if an invalid numberClass has been specified
084: * @see org.springframework.util.NumberUtils#parseNumber(String, Class, java.text.NumberFormat)
085: * @see java.text.NumberFormat#parse
086: * @see java.text.NumberFormat#format
087: */
088: public CustomNumberEditor(Class numberClass,
089: NumberFormat numberFormat, boolean allowEmpty)
090: throws IllegalArgumentException {
091:
092: if (numberClass == null
093: || !Number.class.isAssignableFrom(numberClass)) {
094: throw new IllegalArgumentException(
095: "Property class must be a subclass of Number");
096: }
097: this .numberClass = numberClass;
098: this .numberFormat = numberFormat;
099: this .allowEmpty = allowEmpty;
100: }
101:
102: /**
103: * Parse the Number from the given text, using the specified NumberFormat.
104: */
105: public void setAsText(String text) throws IllegalArgumentException {
106: if (this .allowEmpty && !StringUtils.hasText(text)) {
107: // Treat empty String as null value.
108: setValue(null);
109: } else if (this .numberFormat != null) {
110: // Use given NumberFormat for parsing text.
111: setValue(NumberUtils.parseNumber(text, this .numberClass,
112: this .numberFormat));
113: } else {
114: // Use default valueOf methods for parsing text.
115: setValue(NumberUtils.parseNumber(text, this .numberClass));
116: }
117: }
118:
119: /**
120: * Coerce a Number value into the required target class, if necessary.
121: */
122: public void setValue(Object value) {
123: if (value instanceof Number) {
124: super .setValue(NumberUtils.convertNumberToTargetClass(
125: (Number) value, this .numberClass));
126: } else {
127: super .setValue(value);
128: }
129: }
130:
131: /**
132: * Format the Number as String, using the specified NumberFormat.
133: */
134: public String getAsText() {
135: Object value = getValue();
136: if (value == null) {
137: return "";
138: }
139: if (this .numberFormat != null) {
140: // Use NumberFormat for rendering value.
141: return this .numberFormat.format(value);
142: } else {
143: // Use toString method for rendering value.
144: return value.toString();
145: }
146: }
147:
148: }
|