KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > databinding > conversion > StringToNumberParser


1 /*******************************************************************************
2  * Copyright (c) 2007 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  ******************************************************************************/

11
12 package org.eclipse.core.internal.databinding.conversion;
13
14 import java.math.BigDecimal JavaDoc;
15 import java.math.BigInteger JavaDoc;
16 import java.text.ParsePosition JavaDoc;
17
18 import org.eclipse.core.internal.databinding.BindingMessages;
19
20 import com.ibm.icu.text.NumberFormat;
21
22 /**
23  * Utility class for the parsing of strings to numbers.
24  *
25  * @since 1.0
26  */

27 public class StringToNumberParser {
28     private static final BigDecimal JavaDoc FLOAT_MAX_BIG_DECIMAL = new BigDecimal JavaDoc(
29             Float.MAX_VALUE);
30     private static final BigDecimal JavaDoc FLOAT_MIN_BIG_DECIMAL = new BigDecimal JavaDoc(
31             -Float.MAX_VALUE);
32
33     private static final BigDecimal JavaDoc DOUBLE_MAX_BIG_DECIMAL = new BigDecimal JavaDoc(
34             Double.MAX_VALUE);
35     private static final BigDecimal JavaDoc DOUBLE_MIN_BIG_DECIMAL = new BigDecimal JavaDoc(
36             -Double.MAX_VALUE);
37
38     /**
39      * @param value
40      * @param numberFormat
41      * @param primitive
42      * @return result
43      */

44     public static ParseResult parse(Object JavaDoc value, NumberFormat numberFormat,
45             boolean primitive) {
46         if (!(value instanceof String JavaDoc)) {
47             throw new IllegalArgumentException JavaDoc(
48                     "Value to convert is not a String"); //$NON-NLS-1$
49
}
50
51         String JavaDoc source = (String JavaDoc) value;
52         ParseResult result = new ParseResult();
53         if (!primitive && source.trim().length() == 0) {
54             return result;
55         }
56
57         synchronized (numberFormat) {
58             ParsePosition JavaDoc position = new ParsePosition JavaDoc(0);
59             Number JavaDoc parseResult = null;
60             parseResult = numberFormat.parse(source, position);
61
62             if (position.getIndex() != source.length()
63                     || position.getErrorIndex() > -1) {
64
65                 result.position = position;
66             } else {
67                 result.number = parseResult;
68             }
69         }
70
71         return result;
72     }
73
74     /**
75      * The result of a parse operation.
76      *
77      * @since 1.0
78      */

79     public static class ParseResult {
80         /* package */Number JavaDoc number;
81         /* package */ParsePosition JavaDoc position;
82
83         /**
84          * The number as a result of the conversion. <code>null</code> if the
85          * value could not be converted or if the type is not a primitive and
86          * the value was an empty string.
87          *
88          * @return number
89          */

90         public Number JavaDoc getNumber() {
91             return number;
92         }
93
94         /**
95          * ParsePosition if an error occurred while parsing. <code>null</code>
96          * if no error occurred.
97          *
98          * @return parse position
99          */

100         public ParsePosition JavaDoc getPosition() {
101             return position;
102         }
103     }
104
105     /**
106      * Formats an appropriate message for a parsing error.
107      *
108      * @param value
109      * @param position
110      * @return message
111      */

112     public static String JavaDoc createParseErrorMessage(String JavaDoc value,
113             ParsePosition JavaDoc position) {
114         int errorIndex = (position.getErrorIndex() > -1) ? position
115                 .getErrorIndex() : position.getIndex();
116
117         return BindingMessages.formatString("Validate_NumberParseError", //$NON-NLS-1$
118
new Object JavaDoc[] { value, new Integer JavaDoc(errorIndex + 1),
119                         new Character JavaDoc(value.charAt(errorIndex)) });
120     }
121
122     /**
123      * Formats an appropriate message for an out of range error.
124      *
125      * @param minValue
126      * @param maxValue
127      * @param numberFormat when accessed method synchronizes on instance
128      * @return message
129      */

130     public static String JavaDoc createOutOfRangeMessage(Number JavaDoc minValue,
131             Number JavaDoc maxValue, NumberFormat numberFormat) {
132         String JavaDoc min = null;
133         String JavaDoc max = null;
134         
135         synchronized (numberFormat) {
136             min = numberFormat.format(minValue);
137             max = numberFormat.format(maxValue);
138         }
139         
140         return BindingMessages.formatString(
141                 "Validate_NumberOutOfRangeError", new Object JavaDoc[] { min, max }); //$NON-NLS-1$
142
}
143
144     /**
145      * Returns <code>true</code> if the provided <code>number</code> is in
146      * the range of a integer.
147      *
148      * @param number
149      * @return <code>true</code> if a valid integer
150      * @throws IllegalArgumentException
151      * if the number type is unsupported
152      */

153     public static boolean inIntegerRange(Number JavaDoc number) {
154         return checkInteger(number, 31);
155     }
156
157     /**
158      * Validates the range of the provided <code>number</code>.
159      *
160      * @param number
161      * @param bitLength number of bits allowed to be in range
162      * @return <code>true</code> if in range
163      */

164     private static boolean checkInteger(Number JavaDoc number, int bitLength) {
165         BigInteger JavaDoc bigInteger = null;
166
167         if (number instanceof Integer JavaDoc || number instanceof Long JavaDoc) {
168             bigInteger = BigInteger.valueOf(number.longValue());
169         } else if (number instanceof Float JavaDoc || number instanceof Double JavaDoc) {
170             double doubleValue = number.doubleValue();
171             /*
172              * doubleValue == doubleValue is used to check for NaN because NaN !=
173              * NaN. The only way to check for NaN is to compare that the value
174              * is equal to itself.
175              */

176             if (doubleValue == doubleValue
177                     && doubleValue != Double.NEGATIVE_INFINITY
178                     && doubleValue != Double.POSITIVE_INFINITY) {
179                 bigInteger = new BigDecimal JavaDoc(doubleValue).toBigInteger();
180             } else {
181                 return false;
182             }
183         } else if (number instanceof BigInteger JavaDoc) {
184             bigInteger = (BigInteger JavaDoc) number;
185         } else if (number instanceof BigDecimal JavaDoc) {
186             bigInteger = ((BigDecimal JavaDoc) number).toBigInteger();
187         } else {
188             /*
189              * The else is necessary as the ICU4J plugin has it's own BigDecimal
190              * implementation which isn't part of the replacement plugin. So
191              * that this will work we fall back on the double value of the
192              * number.
193              */

194             bigInteger = new BigDecimal JavaDoc(number.doubleValue()).toBigInteger();
195         }
196
197         if (bigInteger != null) {
198             return bigInteger.bitLength() <= bitLength;
199         }
200
201         throw new IllegalArgumentException JavaDoc(
202                 "Number of type [" + number.getClass().getName() + "] is not supported."); //$NON-NLS-1$ //$NON-NLS-2$
203
}
204
205     /**
206      * Returns <code>true</code> if the provided <code>number</code> is in
207      * the range of a long.
208      *
209      * @param number
210      * @return <code>true</code> if in range
211      * @throws IllegalArgumentException
212      * if the number type is unsupported
213      */

214     public static boolean inLongRange(Number JavaDoc number) {
215         return checkInteger(number, 63);
216     }
217
218     /**
219      * Returns <code>true</code> if the provided <code>number</code> is in
220      * the range of a float.
221      *
222      * @param number
223      * @return <code>true</code> if in range
224      * @throws IllegalArgumentException
225      * if the number type is unsupported
226      */

227     public static boolean inFloatRange(Number JavaDoc number) {
228         return checkDecimal(number, FLOAT_MIN_BIG_DECIMAL, FLOAT_MAX_BIG_DECIMAL);
229     }
230     
231     private static boolean checkDecimal(Number JavaDoc number, BigDecimal JavaDoc min, BigDecimal JavaDoc max) {
232         BigDecimal JavaDoc bigDecimal = null;
233         if (number instanceof Integer JavaDoc || number instanceof Long JavaDoc) {
234             bigDecimal = new BigDecimal JavaDoc(number.doubleValue());
235         } else if (number instanceof Float JavaDoc || number instanceof Double JavaDoc) {
236             double doubleValue = number.doubleValue();
237
238             /*
239              * doubleValue == doubleValue is used to check for NaN because NaN !=
240              * NaN. The only way to check for NaN is to compare that the value
241              * is equal to itself.
242              */

243             if (doubleValue == doubleValue
244                     && doubleValue != Double.NEGATIVE_INFINITY
245                     && doubleValue != Double.POSITIVE_INFINITY) {
246                 bigDecimal = new BigDecimal JavaDoc(doubleValue);
247             } else {
248                 return false;
249             }
250         } else if (number instanceof BigInteger JavaDoc) {
251             bigDecimal = new BigDecimal JavaDoc((BigInteger JavaDoc) number);
252         } else if (number instanceof BigDecimal JavaDoc) {
253             bigDecimal = (BigDecimal JavaDoc) number;
254         } else {
255             /*
256              * The else is necessary as the ICU4J plugin has it's own BigDecimal
257              * implementation which isn't part of the replacement plugin. So
258              * that this will work we fall back on the double value of the
259              * number.
260              */

261             bigDecimal = new BigDecimal JavaDoc(number.doubleValue());
262         }
263         
264         if (bigDecimal != null) {
265             return max.compareTo(bigDecimal) >= 0
266                     && min.compareTo(bigDecimal) <= 0;
267         }
268
269         throw new IllegalArgumentException JavaDoc(
270                 "Number of type [" + number.getClass().getName() + "] is not supported."); //$NON-NLS-1$ //$NON-NLS-2$
271
}
272
273     /**
274      * Returns <code>true</code> if the provided <code>number</code> is in
275      * the range of a double.
276      *
277      * @param number
278      * @return <code>true</code> if in range
279      * @throws IllegalArgumentException
280      * if the number type is unsupported
281      */

282     public static boolean inDoubleRange(Number JavaDoc number) {
283         return checkDecimal(number, DOUBLE_MIN_BIG_DECIMAL, DOUBLE_MAX_BIG_DECIMAL);
284     }
285
286     /**
287      * Returns <code>true</code> if the provided <code>number</code> is in
288      * the range of a short.
289      *
290      * @param number
291      * @return <code>true</code> if in range
292      */

293     public static boolean inShortRange(Number JavaDoc number) {
294         return checkInteger(number, 15);
295     }
296
297     /**
298      * Returns <code>true</code> if the provided <code>number</code> is in
299      * the range of a byte.
300      *
301      * @param number
302      * @return <code>true</code> if in range
303      */

304     public static boolean inByteRange(Number JavaDoc number) {
305         return checkInteger(number, 7);
306     }
307 }
308
Popular Tags