001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.text;
019:
020: import java.io.IOException;
021: import java.io.ObjectInputStream;
022: import java.io.ObjectOutputStream;
023: import java.io.ObjectStreamField;
024: import java.math.BigDecimal;
025: import java.math.BigInteger;
026: import java.security.AccessController;
027: import java.security.PrivilegedAction;
028: import java.util.Currency;
029: import java.util.Locale;
030:
031: /**
032: * DecimalFormat is used to format and parse numbers, both integers and
033: * fractions, based on a pattern. The pattern characters used can be either
034: * localized or non-localized.
035: */
036: public class DecimalFormat extends NumberFormat {
037:
038: private static final long serialVersionUID = 864413376551465018L;
039:
040: private transient boolean parseBigDecimal = false;
041:
042: private transient DecimalFormatSymbols symbols;
043:
044: private transient com.ibm.icu.text.DecimalFormat dform;
045:
046: private transient com.ibm.icu.text.DecimalFormatSymbols icuSymbols;
047:
048: private static final int CURRENT_SERIAL_VERTION = 3;
049:
050: private transient int serialVersionOnStream = 3;
051:
052: /**
053: * Constructs a new DecimalFormat for formatting and parsing numbers for the
054: * default Locale.
055: */
056: public DecimalFormat() {
057: Locale locale = Locale.getDefault();
058: icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
059: symbols = new DecimalFormatSymbols(locale);
060: dform = new com.ibm.icu.text.DecimalFormat();
061:
062: super
063: .setMaximumFractionDigits(dform
064: .getMaximumFractionDigits());
065: super .setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
066: super
067: .setMinimumFractionDigits(dform
068: .getMinimumFractionDigits());
069: super .setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
070: }
071:
072: /**
073: * Constructs a new DecimalFormat using the specified non-localized pattern
074: * and the DecimalFormatSymbols for the default Locale.
075: *
076: * @param pattern
077: * the non-localized pattern
078: *
079: * @exception IllegalArgumentException
080: * when the pattern cannot be parsed
081: */
082: public DecimalFormat(String pattern) {
083: Locale locale = Locale.getDefault();
084: icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
085: symbols = new DecimalFormatSymbols(locale);
086: dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols);
087:
088: super
089: .setMaximumFractionDigits(dform
090: .getMaximumFractionDigits());
091: super .setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
092: super
093: .setMinimumFractionDigits(dform
094: .getMinimumFractionDigits());
095: super .setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
096: }
097:
098: /**
099: * Constructs a new DecimalFormat using the specified non-localized pattern
100: * and DecimalFormatSymbols.
101: *
102: * @param pattern
103: * the non-localized pattern
104: * @param value
105: * the DecimalFormatSymbols
106: *
107: * @exception IllegalArgumentException
108: * when the pattern cannot be parsed
109: */
110: public DecimalFormat(String pattern, DecimalFormatSymbols value) {
111: symbols = (DecimalFormatSymbols) value.clone();
112: Locale locale = symbols.getLocale(); //$NON-NLS-1$
113: icuSymbols = new com.ibm.icu.text.DecimalFormatSymbols(locale);
114: copySymbols(icuSymbols, symbols);
115:
116: dform = new com.ibm.icu.text.DecimalFormat(pattern, icuSymbols);
117:
118: super
119: .setMaximumFractionDigits(dform
120: .getMaximumFractionDigits());
121: super .setMaximumIntegerDigits(dform.getMaximumIntegerDigits());
122: super
123: .setMinimumFractionDigits(dform
124: .getMinimumFractionDigits());
125: super .setMinimumIntegerDigits(dform.getMinimumIntegerDigits());
126: }
127:
128: /**
129: * Changes the pattern of this DecimalFormat to the specified pattern which
130: * uses localized pattern characters.
131: *
132: * @param pattern
133: * the localized pattern
134: *
135: * @exception IllegalArgumentException
136: * when the pattern cannot be parsed
137: */
138: public void applyLocalizedPattern(String pattern) {
139: dform.applyLocalizedPattern(pattern);
140: }
141:
142: /**
143: * Changes the pattern of this SimpleDateFormat to the specified pattern
144: * which uses non-localized pattern characters.
145: *
146: * @param pattern
147: * the non-localized pattern
148: *
149: * @exception IllegalArgumentException
150: * when the pattern cannot be parsed
151: */
152: public void applyPattern(String pattern) {
153:
154: dform.applyPattern(pattern);
155: }
156:
157: /**
158: * Answers a new instance of DecimalFormat with the same pattern and
159: * properties as this DecimalFormat.
160: *
161: * @return a shallow copy of this DecimalFormat
162: *
163: * @see java.lang.Cloneable
164: */
165: @Override
166: public Object clone() {
167: DecimalFormat clone = (DecimalFormat) super .clone();
168: clone.dform = (com.ibm.icu.text.DecimalFormat) dform.clone();
169: clone.symbols = (DecimalFormatSymbols) symbols.clone();
170: return clone;
171: }
172:
173: /**
174: * Compares the specified object to this DecimalFormat and answer if they
175: * are equal. The object must be an instance of DecimalFormat with the same
176: * pattern and properties.
177: *
178: * @param object
179: * the object to compare with this object
180: * @return true if the specified object is equal to this DecimalFormat,
181: * false otherwise
182: *
183: * @see #hashCode
184: */
185: @Override
186: public boolean equals(Object object) {
187: if (this == object) {
188: return true;
189: }
190: if (!(object instanceof DecimalFormat)) {
191: return false;
192: }
193: DecimalFormat format = (DecimalFormat) object;
194: return (this .dform == null ? format.dform == null : this .dform
195: .equals(format.dform));
196: }
197:
198: /**
199: * Formats the specified object using the rules of this DecimalNumberFormat
200: * and returns an AttributedCharacterIterator with the formatted number and
201: * attributes.
202: *
203: * @param object
204: * the object to format
205: * @return an AttributedCharacterIterator with the formatted number and
206: * attributes
207: *
208: * @exception NullPointerException
209: * when the object is null
210: * @exception IllegalArgumentException
211: * when the object cannot be formatted by this Format
212: */
213: @Override
214: public AttributedCharacterIterator formatToCharacterIterator(
215: Object object) {
216: if (object == null) {
217: throw new NullPointerException();
218: }
219: return dform.formatToCharacterIterator(object);
220: }
221:
222: /**
223: * Formats the double value into the specified StringBuffer using the
224: * pattern of this DecimalFormat. If the field specified by the
225: * FieldPosition is formatted, set the begin and end index of the formatted
226: * field in the FieldPosition.
227: *
228: * @param value
229: * the double to format
230: * @param buffer
231: * the StringBuffer
232: * @param position
233: * the FieldPosition
234: * @return the StringBuffer parameter <code>buffer</code>
235: */
236: @Override
237: public StringBuffer format(double value, StringBuffer buffer,
238: FieldPosition position) {
239: return dform.format(value, buffer, position);
240: }
241:
242: /**
243: * Formats the long value into the specified StringBuffer using the pattern
244: * of this DecimalFormat. If the field specified by the FieldPosition is
245: * formatted, set the begin and end index of the formatted field in the
246: * FieldPosition.
247: *
248: * @param value
249: * the long to format
250: * @param buffer
251: * the StringBuffer
252: * @param position
253: * the FieldPosition
254: * @return the StringBuffer parameter <code>buffer</code>
255: */
256: @Override
257: public StringBuffer format(long value, StringBuffer buffer,
258: FieldPosition position) {
259: return dform.format(value, buffer, position);
260: }
261:
262: /**
263: * Formats the number into the specified StringBuffer using the pattern of
264: * this DecimalFormat. If the field specified by the FieldPosition is
265: * formatted, set the begin and end index of the formatted field in the
266: * FieldPosition.
267: *
268: * @param number
269: * the object to format
270: * @param toAppendTo
271: * the StringBuffer
272: * @param pos
273: * the FieldPosition
274: * @return the StringBuffer parameter <code>buffer</code>
275: * @throws IllegalArgumentException
276: * if the given number is not instance of <code>Number</code>
277: */
278: @Override
279: public final StringBuffer format(Object number,
280: StringBuffer toAppendTo, FieldPosition pos) {
281: if (!(number instanceof Number)) {
282: throw new IllegalArgumentException();
283: }
284: if (toAppendTo == null || pos == null) {
285: throw new NullPointerException();
286: }
287: if (number instanceof BigInteger
288: || number instanceof BigDecimal) {
289: return dform.format(number, toAppendTo, pos);
290: }
291: return super .format(number, toAppendTo, pos);
292: }
293:
294: /**
295: * Answers the DecimalFormatSymbols used by this DecimalFormat.
296: *
297: * @return a DecimalFormatSymbols
298: */
299: public DecimalFormatSymbols getDecimalFormatSymbols() {
300: return (DecimalFormatSymbols) symbols.clone();
301: }
302:
303: /**
304: * Answers the currency used by this decimal format.
305: *
306: * @return currency of DecimalFormatSymbols used by this decimal format
307: * @see DecimalFormatSymbols#getCurrency()
308: */
309: @Override
310: public Currency getCurrency() {
311: final com.ibm.icu.util.Currency cur = dform.getCurrency();
312: final String code = (cur == null) ? "XXX" : cur.getCurrencyCode(); //$NON-NLS-1$
313:
314: return Currency.getInstance(code);
315: }
316:
317: /**
318: * Answers the number of digits grouped together by the grouping separator.
319: *
320: * @return the number of digits grouped together
321: */
322: public int getGroupingSize() {
323: return dform.getGroupingSize();
324: }
325:
326: /**
327: * Answers the multiplier which is applied to the number before formatting
328: * or after parsing.
329: *
330: * @return the multiplier
331: */
332: public int getMultiplier() {
333: return dform.getMultiplier();
334: }
335:
336: /**
337: * Answers the prefix which is formatted or parsed before a negative number.
338: *
339: * @return the negative prefix
340: */
341: public String getNegativePrefix() {
342: return dform.getNegativePrefix();
343: }
344:
345: /**
346: * Answers the suffix which is formatted or parsed after a negative number.
347: *
348: * @return the negative suffix
349: */
350: public String getNegativeSuffix() {
351: return dform.getNegativeSuffix();
352: }
353:
354: /**
355: * Answers the prefix which is formatted or parsed before a positive number.
356: *
357: * @return the positive prefix
358: */
359: public String getPositivePrefix() {
360: return dform.getPositivePrefix();
361: }
362:
363: /**
364: * Answers the suffix which is formatted or parsed after a positive number.
365: *
366: * @return the positive suffix
367: */
368: public String getPositiveSuffix() {
369: return dform.getPositiveSuffix();
370: }
371:
372: /**
373: * Answers an integer hash code for the receiver. Objects which are equal
374: * answer the same value for this method.
375: *
376: * @return the receiver's hash
377: *
378: * @see #equals
379: */
380: @Override
381: public int hashCode() {
382: return dform.hashCode();
383: }
384:
385: /**
386: * Answers whether the decimal separator is shown when there are no
387: * fractional digits.
388: *
389: * @return true if the decimal separator should always be formatted, false
390: * otherwise
391: */
392: public boolean isDecimalSeparatorAlwaysShown() {
393: return dform.isDecimalSeparatorAlwaysShown();
394: }
395:
396: /**
397: * This value indicates whether the return object of the parse operation
398: * will be of type BigDecimal. This value will default to false.
399: *
400: * @return true and parse will always return BigDecimals, false and the type
401: * of the result will be Long or Double.
402: */
403: public boolean isParseBigDecimal() {
404: return this .parseBigDecimal;
405: }
406:
407: /**
408: * When DecimalFormat is used to parsing, and this value is set to true,
409: * then all the resulting number will be of type
410: * <code>java.lang.Integer</code>. Except that, NaN, positive and
411: * negative infinity are still returned as <code>java.lang.Double</code>
412: *
413: * In this implementation, com.ibm.icu.text.DecimalFormat is wrapped to
414: * fulfill most of the format and parse feature. And this method is
415: * delegated to the wrapped instance of com.ibm.icu.text.DecimalFormat.
416: *
417: * @param value
418: * If set to true, all the resulting number will be of type
419: * java.lang.Integer except some special cases.
420: */
421: @Override
422: public void setParseIntegerOnly(boolean value) {
423: dform.setParseIntegerOnly(value);
424: }
425:
426: /**
427: * Returns true if this <code>DecimalFormat</code>'s all resulting number
428: * will be of type <code>java.lang.Integer</code>
429: *
430: * @return true if this <code>DecimalFormat</code>'s all resulting number
431: * will be of type <code>java.lang.Integer</code>
432: */
433: @Override
434: public boolean isParseIntegerOnly() {
435: return dform.isParseIntegerOnly();
436: }
437:
438: private static final Double NEGATIVE_ZERO_DOUBLE = new Double(-0.0);
439:
440: /**
441: * Parse a Long or Double from the specified String starting at the index
442: * specified by the ParsePosition. If the string is successfully parsed, the
443: * index of the ParsePosition is updated to the index following the parsed
444: * text.
445: *
446: * @param string
447: * the String to parse
448: * @param position
449: * the ParsePosition, updated on return with the index following
450: * the parsed text, or on error the index is unchanged and the
451: * error index is set to the index where the error occurred
452: * @return a Long or Double resulting from the parse, or null if there is an
453: * error. The result will be a Long if the parsed number is an
454: * integer in the range of a long, otherwise the result is a Double.
455: */
456: @Override
457: public Number parse(String string, ParsePosition position) {
458: Number number = dform.parse(string, position);
459: if (null == number) {
460: return null;
461: }
462: if (this .isParseBigDecimal()) {
463: if (number instanceof Long) {
464: return new BigDecimal(number.longValue());
465: }
466: if ((number instanceof Double)
467: && !((Double) number).isInfinite()
468: && !((Double) number).isNaN()) {
469:
470: return new BigDecimal(number.doubleValue());
471: }
472: if (number instanceof BigInteger) {
473: return new BigDecimal(number.doubleValue());
474: }
475: if (number instanceof com.ibm.icu.math.BigDecimal) {
476: return new BigDecimal(number.toString());
477: }
478: return number;
479: }
480: if ((number instanceof com.ibm.icu.math.BigDecimal)
481: || (number instanceof BigInteger)) {
482: return new Double(number.doubleValue());
483: }
484:
485: if (this .isParseIntegerOnly()
486: && number.equals(NEGATIVE_ZERO_DOUBLE)) {
487: return new Long(0);
488: }
489: return number;
490:
491: }
492:
493: /**
494: * Sets the DecimalFormatSymbols used by this DecimalFormat.
495: *
496: * @param value
497: * the DecimalFormatSymbols
498: */
499: public void setDecimalFormatSymbols(DecimalFormatSymbols value) {
500: if (value != null) {
501: symbols = (DecimalFormatSymbols) value.clone();
502: icuSymbols = dform.getDecimalFormatSymbols();
503: copySymbols(icuSymbols, symbols);
504: dform.setDecimalFormatSymbols(icuSymbols);
505: }
506: }
507:
508: /**
509: * Sets the currency used by this decimal format. The min and max fraction
510: * digits remain the same.
511: *
512: * @param currency
513: * @see DecimalFormatSymbols#setCurrency(Currency)
514: */
515: @Override
516: public void setCurrency(Currency currency) {
517: dform.setCurrency(com.ibm.icu.util.Currency
518: .getInstance(currency.getCurrencyCode()));
519: symbols.setCurrency(currency);
520: }
521:
522: /**
523: * Sets whether the decimal separator is shown when there are no fractional
524: * digits.
525: *
526: * @param value
527: * true if the decimal separator should always be formatted,
528: * false otherwise
529: */
530: public void setDecimalSeparatorAlwaysShown(boolean value) {
531: dform.setDecimalSeparatorAlwaysShown(value);
532: }
533:
534: /**
535: * Sets the number of digits grouped together by the grouping separator.
536: *
537: * @param value
538: * the number of digits grouped together
539: */
540: public void setGroupingSize(int value) {
541: dform.setGroupingSize(value);
542: }
543:
544: /**
545: * Sets whether or not grouping will be used in this format. Grouping
546: * affects both parsing and formatting.
547: *
548: * @param value
549: * true if uses grouping,false otherwise.
550: *
551: */
552: @Override
553: public void setGroupingUsed(boolean value) {
554: dform.setGroupingUsed(value);
555: }
556:
557: /**
558: * This value indicates whether grouping will be used in this format.
559: *
560: * @return true if grouping is used,false otherwise.
561: */
562: @Override
563: public boolean isGroupingUsed() {
564: return dform.isGroupingUsed();
565: }
566:
567: /**
568: * Sets the maximum number of fraction digits that are printed when
569: * formatting. If the maximum is less than the number of fraction digits,
570: * the least significant digits are truncated. Limit the maximum to
571: * DOUBLE_FRACTION_DIGITS.
572: *
573: * @param value
574: * the maximum number of fraction digits
575: */
576: @Override
577: public void setMaximumFractionDigits(int value) {
578: super .setMaximumFractionDigits(value);
579: dform.setMaximumFractionDigits(value);
580: }
581:
582: /**
583: * Sets the maximum number of integer digits that are printed when
584: * formatting. If the maximum is less than the number of integer digits, the
585: * most significant digits are truncated. Limit the maximum to
586: * DOUBLE_INTEGER_DIGITS.
587: *
588: * @param value
589: * the maximum number of integer digits
590: */
591: @Override
592: public void setMaximumIntegerDigits(int value) {
593: super .setMaximumIntegerDigits(value);
594: dform.setMaximumIntegerDigits(value);
595: }
596:
597: /**
598: * Sets the minimum number of fraction digits that are printed when
599: * formatting. Limit the minimum to DOUBLE_FRACTION_DIGITS.
600: *
601: * @param value
602: * the minimum number of fraction digits
603: */
604: @Override
605: public void setMinimumFractionDigits(int value) {
606: super .setMinimumFractionDigits(value);
607: dform.setMinimumFractionDigits(value);
608: }
609:
610: /**
611: * Sets the minimum number of integer digits that are printed when
612: * formatting. Limit the minimum to DOUBLE_INTEGER_DIGITS.
613: *
614: * @param value
615: * the minimum number of integer digits
616: */
617: @Override
618: public void setMinimumIntegerDigits(int value) {
619: super .setMinimumIntegerDigits(value);
620: dform.setMinimumIntegerDigits(value);
621: }
622:
623: /**
624: * Sets the multiplier which is applied to the number before formatting or
625: * after parsing.
626: *
627: * @param value
628: * the multiplier
629: */
630: public void setMultiplier(int value) {
631: dform.setMultiplier(value);
632: }
633:
634: /**
635: * Sets the prefix which is formatted or parsed before a negative number.
636: *
637: * @param value
638: * the negative prefix
639: */
640: public void setNegativePrefix(String value) {
641: dform.setNegativePrefix(value);
642: }
643:
644: /**
645: * Sets the suffix which is formatted or parsed after a negative number.
646: *
647: * @param value
648: * the negative suffix
649: */
650: public void setNegativeSuffix(String value) {
651: dform.setNegativeSuffix(value);
652: }
653:
654: /**
655: * Sets the prefix which is formatted or parsed before a positive number.
656: *
657: * @param value
658: * the positive prefix
659: */
660: public void setPositivePrefix(String value) {
661: dform.setPositivePrefix(value);
662: }
663:
664: /**
665: * Sets the suffix which is formatted or parsed after a positive number.
666: *
667: * @param value
668: * the positive suffix
669: */
670: public void setPositiveSuffix(String value) {
671: dform.setPositiveSuffix(value);
672: }
673:
674: /**
675: * Let users change the behavior of a DecimalFormat, If set to true all the
676: * returned objects will be of type BigDecimal
677: *
678: * @param newValue
679: * true if all the returned objects should be type of BigDecimal
680: */
681: public void setParseBigDecimal(boolean newValue) {
682: this .parseBigDecimal = newValue;
683: }
684:
685: /**
686: * Answers the pattern of this DecimalFormat using localized pattern
687: * characters.
688: *
689: * @return the localized pattern
690: */
691: public String toLocalizedPattern() {
692: return dform.toLocalizedPattern();
693: }
694:
695: /**
696: * Answers the pattern of this DecimalFormat using non-localized pattern
697: * characters.
698: *
699: * @return the non-localized pattern
700: */
701: public String toPattern() {
702: return dform.toPattern();
703: }
704:
705: // the fields list to be serialized
706: private static final ObjectStreamField[] serialPersistentFields = {
707: new ObjectStreamField("positivePrefix", String.class), //$NON-NLS-1$
708: new ObjectStreamField("positiveSuffix", String.class), //$NON-NLS-1$
709: new ObjectStreamField("negativePrefix", String.class), //$NON-NLS-1$
710: new ObjectStreamField("negativeSuffix", String.class), //$NON-NLS-1$
711: new ObjectStreamField("posPrefixPattern", String.class), //$NON-NLS-1$
712: new ObjectStreamField("posSuffixPattern", String.class), //$NON-NLS-1$
713: new ObjectStreamField("negPrefixPattern", String.class), //$NON-NLS-1$
714: new ObjectStreamField("negSuffixPattern", String.class), //$NON-NLS-1$
715: new ObjectStreamField("multiplier", int.class), //$NON-NLS-1$
716: new ObjectStreamField("groupingSize", byte.class), //$NON-NLS-1$
717: new ObjectStreamField(
718: "decimalSeparatorAlwaysShown", boolean.class), //$NON-NLS-1$
719: new ObjectStreamField("parseBigDecimal", boolean.class), //$NON-NLS-1$
720: new ObjectStreamField("symbols", DecimalFormatSymbols.class), //$NON-NLS-1$
721: new ObjectStreamField(
722: "useExponentialNotation", boolean.class), //$NON-NLS-1$
723: new ObjectStreamField("minExponentDigits", byte.class), //$NON-NLS-1$
724: new ObjectStreamField("maximumIntegerDigits", int.class), //$NON-NLS-1$
725: new ObjectStreamField("minimumIntegerDigits", int.class), //$NON-NLS-1$
726: new ObjectStreamField("maximumFractionDigits", int.class), //$NON-NLS-1$
727: new ObjectStreamField("minimumFractionDigits", int.class), //$NON-NLS-1$
728: new ObjectStreamField("serialVersionOnStream", int.class), }; //$NON-NLS-1$
729:
730: /**
731: * Writes serialized fields following serialized forms specified by Java
732: * specification.
733: *
734: * @param stream
735: * the output stream to write serialized bytes
736: * @throws IOException
737: * if some I/O error occurs
738: * @throws ClassNotFoundException
739: */
740: @SuppressWarnings("nls")
741: private void writeObject(ObjectOutputStream stream)
742: throws IOException, ClassNotFoundException {
743: ObjectOutputStream.PutField fields = stream.putFields();
744: fields.put("positivePrefix", dform.getPositivePrefix());
745: fields.put("positiveSuffix", dform.getPositiveSuffix());
746: fields.put("negativePrefix", dform.getNegativePrefix());
747: fields.put("negativeSuffix", dform.getNegativeSuffix());
748: String posPrefixPattern = (String) Format.getInternalField(
749: "posPrefixPattern", dform);
750: fields.put("posPrefixPattern", posPrefixPattern);
751: String posSuffixPattern = (String) Format.getInternalField(
752: "posSuffixPattern", dform);
753: fields.put("posSuffixPattern", posSuffixPattern);
754: String negPrefixPattern = (String) Format.getInternalField(
755: "negPrefixPattern", dform);
756: fields.put("negPrefixPattern", negPrefixPattern);
757: String negSuffixPattern = (String) Format.getInternalField(
758: "negSuffixPattern", dform);
759: fields.put("negSuffixPattern", negSuffixPattern);
760: fields.put("multiplier", dform.getMultiplier());
761: fields.put("groupingSize", (byte) dform.getGroupingSize());
762: fields.put("decimalSeparatorAlwaysShown", dform
763: .isDecimalSeparatorAlwaysShown());
764: fields.put("parseBigDecimal", parseBigDecimal);
765: fields.put("symbols", symbols);
766: boolean useExponentialNotation = ((Boolean) Format
767: .getInternalField("useExponentialNotation", dform))
768: .booleanValue();
769: fields.put("useExponentialNotation", useExponentialNotation);
770: byte minExponentDigits = ((Byte) Format.getInternalField(
771: "minExponentDigits", dform)).byteValue();
772: fields.put("minExponentDigits", minExponentDigits);
773: fields.put("maximumIntegerDigits", dform
774: .getMaximumIntegerDigits());
775: fields.put("minimumIntegerDigits", dform
776: .getMinimumIntegerDigits());
777: fields.put("maximumFractionDigits", dform
778: .getMaximumFractionDigits());
779: fields.put("minimumFractionDigits", dform
780: .getMinimumFractionDigits());
781: fields.put("serialVersionOnStream", CURRENT_SERIAL_VERTION);
782: stream.writeFields();
783: }
784:
785: /**
786: * Reads serialized fields following serialized forms specified by Java
787: * specification.
788: *
789: * @param stream
790: * the input stream to read serialized bytes
791: * @throws IOException
792: * if some I/O error occurs
793: * @throws ClassNotFoundException
794: * if some class of serialized objects or fields cannot be found
795: */
796: @SuppressWarnings("nls")
797: private void readObject(ObjectInputStream stream)
798: throws IOException, ClassNotFoundException {
799:
800: ObjectInputStream.GetField fields = stream.readFields();
801: String positivePrefix = (String) fields.get("positivePrefix",
802: "");
803: String positiveSuffix = (String) fields.get("positiveSuffix",
804: "");
805: String negativePrefix = (String) fields.get("negativePrefix",
806: "-");
807: String negativeSuffix = (String) fields.get("negativeSuffix",
808: "");
809:
810: String posPrefixPattern = (String) fields.get(
811: "posPrefixPattern", "");
812: String posSuffixPattern = (String) fields.get(
813: "posSuffixPattern", "");
814: String negPrefixPattern = (String) fields.get(
815: "negPrefixPattern", "-");
816: String negSuffixPattern = (String) fields.get(
817: "negSuffixPattern", "");
818:
819: int multiplier = fields.get("multiplier", 1);
820: byte groupingSize = fields.get("groupingSize", (byte) 3);
821: boolean decimalSeparatorAlwaysShown = fields.get(
822: "decimalSeparatorAlwaysShown", false);
823: boolean parseBigDecimal = fields.get("parseBigDecimal", false);
824: symbols = (DecimalFormatSymbols) fields.get("symbols", null);
825:
826: boolean useExponentialNotation = fields.get(
827: "useExponentialNotation", false);
828: byte minExponentDigits = fields.get("minExponentDigits",
829: (byte) 0);
830:
831: int maximumIntegerDigits = fields.get("maximumIntegerDigits",
832: 309);
833: int minimumIntegerDigits = fields.get("minimumIntegerDigits",
834: 309);
835: int maximumFractionDigits = fields.get("maximumFractionDigits",
836: 340);
837: int minimumFractionDigits = fields.get("minimumFractionDigits",
838: 340);
839: this .serialVersionOnStream = fields.get(
840: "serialVersionOnStream", 0);
841:
842: Locale locale = (Locale) Format.getInternalField("locale",
843: symbols);
844: dform = new com.ibm.icu.text.DecimalFormat("",
845: new com.ibm.icu.text.DecimalFormatSymbols(locale));
846: setInternalField("useExponentialNotation", dform, Boolean
847: .valueOf(useExponentialNotation));
848: setInternalField("minExponentDigits", dform, new Byte(
849: minExponentDigits));
850: dform.setPositivePrefix(positivePrefix);
851: dform.setPositiveSuffix(positiveSuffix);
852: dform.setNegativePrefix(negativePrefix);
853: dform.setNegativeSuffix(negativeSuffix);
854: setInternalField("posPrefixPattern", dform, posPrefixPattern);
855: setInternalField("posSuffixPattern", dform, posSuffixPattern);
856: setInternalField("negPrefixPattern", dform, negPrefixPattern);
857: setInternalField("negSuffixPattern", dform, negSuffixPattern);
858: dform.setMultiplier(multiplier);
859: dform.setGroupingSize(groupingSize);
860: dform
861: .setDecimalSeparatorAlwaysShown(decimalSeparatorAlwaysShown);
862: dform.setMinimumIntegerDigits(minimumIntegerDigits);
863: dform.setMaximumIntegerDigits(maximumIntegerDigits);
864: dform.setMinimumFractionDigits(minimumFractionDigits);
865: dform.setMaximumFractionDigits(maximumFractionDigits);
866: this .setParseBigDecimal(parseBigDecimal);
867:
868: if (serialVersionOnStream < 3) {
869: setMaximumIntegerDigits(super .getMaximumIntegerDigits());
870: setMinimumIntegerDigits(super .getMinimumIntegerDigits());
871: setMaximumFractionDigits(super .getMaximumFractionDigits());
872: setMinimumFractionDigits(super .getMinimumFractionDigits());
873: }
874: if (serialVersionOnStream < 1) {
875: this .setInternalField("useExponentialNotation", dform,
876: Boolean.FALSE);
877: }
878: serialVersionOnStream = 3;
879: }
880:
881: /*
882: * Copies decimal format symbols from text object to ICU one.
883: *
884: * @param icu the object which receives the new values. @param dfs the
885: * object which contains the new values.
886: */
887: private void copySymbols(
888: final com.ibm.icu.text.DecimalFormatSymbols icu,
889: final DecimalFormatSymbols dfs) {
890: Currency currency = dfs.getCurrency();
891: if (currency == null) {
892: icu.setCurrency(com.ibm.icu.util.Currency
893: .getInstance("XXX"));
894: } else {
895: icu.setCurrency(com.ibm.icu.util.Currency.getInstance(dfs
896: .getCurrency().getCurrencyCode()));
897: }
898:
899: icu.setCurrencySymbol(dfs.getCurrencySymbol());
900: icu.setDecimalSeparator(dfs.getDecimalSeparator());
901: icu.setDigit(dfs.getDigit());
902: icu.setGroupingSeparator(dfs.getGroupingSeparator());
903: icu.setInfinity(dfs.getInfinity());
904: icu.setInternationalCurrencySymbol(dfs
905: .getInternationalCurrencySymbol());
906: icu.setMinusSign(dfs.getMinusSign());
907: icu.setMonetaryDecimalSeparator(dfs
908: .getMonetaryDecimalSeparator());
909: icu.setNaN(dfs.getNaN());
910: icu.setPatternSeparator(dfs.getPatternSeparator());
911: icu.setPercent(dfs.getPercent());
912: icu.setPerMill(dfs.getPerMill());
913: icu.setZeroDigit(dfs.getZeroDigit());
914: }
915:
916: /*
917: * Sets private field value by reflection.
918: *
919: * @param fieldName the field name to be set @param target the object which
920: * field to be set @param value the value to be set
921: */
922: private void setInternalField(final String fieldName,
923: final Object target, final Object value) {
924: AccessController
925: .doPrivileged(new PrivilegedAction<java.lang.reflect.Field>() {
926: public java.lang.reflect.Field run() {
927: java.lang.reflect.Field field = null;
928: try {
929: field = target.getClass().getDeclaredField(
930: fieldName);
931: field.setAccessible(true);
932: field.set(target, value);
933: } catch (Exception e) {
934: return null;
935: }
936: return field;
937: }
938: });
939: }
940: }
|