1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.joda.money.format;
17
18 import java.io.Serializable;
19 import java.lang.reflect.Method;
20 import java.text.DecimalFormat;
21 import java.text.DecimalFormatSymbols;
22 import java.text.NumberFormat;
23 import java.util.Locale;
24 import java.util.concurrent.ConcurrentHashMap;
25 import java.util.concurrent.ConcurrentMap;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51 public final class MoneyAmountStyle implements Serializable {
52
53
54
55
56
57
58 public static final MoneyAmountStyle ASCII_DECIMAL_POINT_GROUP3_COMMA =
59 new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.FULL, ',', 3, false);
60
61
62
63
64
65 public static final MoneyAmountStyle ASCII_DECIMAL_POINT_GROUP3_SPACE =
66 new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.FULL, ' ', 3, false);
67
68
69
70
71
72 public static final MoneyAmountStyle ASCII_DECIMAL_POINT_NO_GROUPING =
73 new MoneyAmountStyle('0', '+', '-', '.', GroupingStyle.NONE, ',', 3, false);
74
75
76
77
78
79 public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_GROUP3_DOT =
80 new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.FULL, '.', 3, false);
81
82
83
84
85
86 public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_GROUP3_SPACE =
87 new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.FULL, ' ', 3, false);
88
89
90
91
92
93 public static final MoneyAmountStyle ASCII_DECIMAL_COMMA_NO_GROUPING =
94 new MoneyAmountStyle('0', '+', '-', ',', GroupingStyle.NONE, '.', 3, false);
95
96
97
98
99 public static final MoneyAmountStyle LOCALIZED_GROUPING =
100 new MoneyAmountStyle(-1, -1, -1, -1, GroupingStyle.FULL, -1, -1, false);
101
102
103
104
105 public static final MoneyAmountStyle LOCALIZED_NO_GROUPING =
106 new MoneyAmountStyle(-1, -1, -1, -1, GroupingStyle.NONE, -1, -1, false);
107
108
109
110 private static final ConcurrentMap<Locale, MoneyAmountStyle> LOCALIZED_CACHE = new ConcurrentHashMap<Locale, MoneyAmountStyle>();
111
112
113
114 private static final long serialVersionUID = 1L;
115
116
117
118
119 private final int zeroCharacter;
120
121
122
123 private final int positiveCharacter;
124
125
126
127 private final int negativeCharacter;
128
129
130
131 private final int decimalPointCharacter;
132
133
134
135 private final GroupingStyle groupingStyle;
136
137
138
139 private final int groupingCharacter;
140
141
142
143 private final int groupingSize;
144
145
146
147 private final boolean forceDecimalPoint;
148
149
150
151
152
153
154
155
156
157
158
159 public static MoneyAmountStyle of(Locale locale) {
160 return getLocalizedStyle(locale);
161 }
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176 private MoneyAmountStyle(
177 int zeroCharacter,
178 int positiveCharacter, int negativeCharacter,
179 int decimalPointCharacter, GroupingStyle groupingStyle,
180 int groupingCharacter, int groupingSize, boolean forceDecimalPoint) {
181 this.zeroCharacter = zeroCharacter;
182 this.positiveCharacter = positiveCharacter;
183 this.negativeCharacter = negativeCharacter;
184 this.decimalPointCharacter = decimalPointCharacter;
185 this.groupingStyle = groupingStyle;
186 this.groupingCharacter = groupingCharacter;
187 this.groupingSize = groupingSize;
188 this.forceDecimalPoint = forceDecimalPoint;
189 }
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206 public MoneyAmountStyle localize(Locale locale) {
207 MoneyFormatter.checkNotNull(locale, "Locale must not be null");
208 MoneyAmountStyle result = this;
209 MoneyAmountStyle protoStyle = null;
210 if (zeroCharacter < 0) {
211 protoStyle = getLocalizedStyle(locale);
212 result = result.withZeroCharacter(protoStyle.getZeroCharacter());
213 }
214 if (positiveCharacter < 0) {
215 protoStyle = getLocalizedStyle(locale);
216 result = result.withPositiveSignCharacter(protoStyle.getPositiveSignCharacter());
217 }
218 if (negativeCharacter < 0) {
219 protoStyle = getLocalizedStyle(locale);
220 result = result.withNegativeSignCharacter(protoStyle.getNegativeSignCharacter());
221 }
222 if (decimalPointCharacter < 0) {
223 protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
224 result = result.withDecimalPointCharacter(protoStyle.getDecimalPointCharacter());
225 }
226 if (groupingCharacter < 0) {
227 protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
228 result = result.withGroupingCharacter(protoStyle.getGroupingCharacter());
229 }
230 if (groupingSize < 0) {
231 protoStyle = (protoStyle == null ? getLocalizedStyle(locale) : protoStyle);
232 result = result.withGroupingSize(protoStyle.getGroupingSize());
233 }
234 return result;
235 }
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250 private static MoneyAmountStyle getLocalizedStyle(Locale locale) {
251 MoneyAmountStyle protoStyle = LOCALIZED_CACHE.get(locale);
252 if (protoStyle == null) {
253 DecimalFormatSymbols symbols;
254 try {
255 Method method = DecimalFormatSymbols.class.getMethod("getInstance", new Class[] {Locale.class});
256 symbols = (DecimalFormatSymbols) method.invoke(null, new Object[] {locale});
257 } catch (Exception ex) {
258 symbols = new DecimalFormatSymbols(locale);
259 }
260 NumberFormat format = NumberFormat.getCurrencyInstance(locale);
261 int size = (format instanceof DecimalFormat ? ((DecimalFormat) format).getGroupingSize() : 3);
262 protoStyle = new MoneyAmountStyle(
263 symbols.getZeroDigit(),
264 '+', symbols.getMinusSign(),
265 symbols.getMonetaryDecimalSeparator(),
266 GroupingStyle.FULL, symbols.getGroupingSeparator(), size, false);
267 LOCALIZED_CACHE.putIfAbsent(locale, protoStyle);
268 }
269 return protoStyle;
270 }
271
272
273
274
275
276
277
278
279
280
281
282 public Character getZeroCharacter() {
283 return zeroCharacter < 0 ? null : (char) zeroCharacter;
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299 public MoneyAmountStyle withZeroCharacter(Character zeroCharacter) {
300 int zeroVal = (zeroCharacter == null ? -1 : zeroCharacter);
301 if (zeroVal == this.zeroCharacter) {
302 return this;
303 }
304 return new MoneyAmountStyle(
305 zeroVal,
306 positiveCharacter, negativeCharacter,
307 decimalPointCharacter, groupingStyle,
308 groupingCharacter, groupingSize, forceDecimalPoint);
309 }
310
311
312
313
314
315
316
317
318
319 public Character getPositiveSignCharacter() {
320 return positiveCharacter < 0 ? null : (char) positiveCharacter;
321 }
322
323
324
325
326
327
328
329
330
331 public MoneyAmountStyle withPositiveSignCharacter(Character positiveCharacter) {
332 int positiveVal = (positiveCharacter == null ? -1 : positiveCharacter);
333 if (positiveVal == this.positiveCharacter) {
334 return this;
335 }
336 return new MoneyAmountStyle(
337 zeroCharacter,
338 positiveVal, negativeCharacter,
339 decimalPointCharacter, groupingStyle,
340 groupingCharacter, groupingSize, forceDecimalPoint);
341 }
342
343
344
345
346
347
348
349
350
351 public Character getNegativeSignCharacter() {
352 return negativeCharacter < 0 ? null : (char) negativeCharacter;
353 }
354
355
356
357
358
359
360
361
362
363 public MoneyAmountStyle withNegativeSignCharacter(Character negativeCharacter) {
364 int negativeVal = (negativeCharacter == null ? -1 : negativeCharacter);
365 if (negativeVal == this.negativeCharacter) {
366 return this;
367 }
368 return new MoneyAmountStyle(
369 zeroCharacter,
370 positiveCharacter, negativeVal,
371 decimalPointCharacter, groupingStyle,
372 groupingCharacter, groupingSize, forceDecimalPoint);
373 }
374
375
376
377
378
379
380
381 public Character getDecimalPointCharacter() {
382 return decimalPointCharacter < 0 ? null : (char) decimalPointCharacter;
383 }
384
385
386
387
388
389
390
391
392
393 public MoneyAmountStyle withDecimalPointCharacter(Character decimalPointCharacter) {
394 int dpVal = (decimalPointCharacter == null ? -1 : decimalPointCharacter);
395 if (dpVal == this.decimalPointCharacter) {
396 return this;
397 }
398 return new MoneyAmountStyle(
399 zeroCharacter,
400 positiveCharacter, negativeCharacter,
401 dpVal, groupingStyle,
402 groupingCharacter, groupingSize, forceDecimalPoint);
403 }
404
405
406
407
408
409
410
411 public Character getGroupingCharacter() {
412 return groupingCharacter < 0 ? null : (char) groupingCharacter;
413 }
414
415
416
417
418
419
420
421
422
423 public MoneyAmountStyle withGroupingCharacter(Character groupingCharacter) {
424 int groupingVal = (groupingCharacter == null ? -1 : groupingCharacter);
425 if (groupingVal == this.groupingCharacter) {
426 return this;
427 }
428 return new MoneyAmountStyle(
429 zeroCharacter,
430 positiveCharacter, negativeCharacter,
431 decimalPointCharacter, groupingStyle,
432 groupingVal, groupingSize, forceDecimalPoint);
433 }
434
435
436
437
438
439
440
441 public Integer getGroupingSize() {
442 return groupingSize < 0 ? null : groupingSize;
443 }
444
445
446
447
448
449
450
451
452
453 public MoneyAmountStyle withGroupingSize(Integer groupingSize) {
454 int sizeVal = (groupingSize == null ? -1 : groupingSize);
455 if (groupingSize != null && sizeVal <= 0) {
456 throw new IllegalArgumentException("Grouping size must be greater than zero");
457 }
458 if (sizeVal == this.groupingSize) {
459 return this;
460 }
461 return new MoneyAmountStyle(
462 zeroCharacter,
463 positiveCharacter, negativeCharacter,
464 decimalPointCharacter, groupingStyle,
465 groupingCharacter, sizeVal, forceDecimalPoint);
466 }
467
468
469
470
471
472
473
474
475 @Deprecated
476 public boolean isGrouping() {
477 return getGroupingStyle() == GroupingStyle.FULL;
478 }
479
480
481
482
483
484
485
486
487 @Deprecated
488 public MoneyAmountStyle withGrouping(boolean grouping) {
489 return withGroupingStyle(grouping ? GroupingStyle.FULL : GroupingStyle.NONE);
490 }
491
492
493
494
495
496
497
498 public GroupingStyle getGroupingStyle() {
499 return groupingStyle;
500 }
501
502
503
504
505
506
507
508 public MoneyAmountStyle withGroupingStyle(GroupingStyle groupingStyle) {
509 MoneyFormatter.checkNotNull(groupingStyle, "groupingStyle");
510 if (this.groupingStyle == groupingStyle) {
511 return this;
512 }
513 return new MoneyAmountStyle(
514 zeroCharacter,
515 positiveCharacter, negativeCharacter,
516 decimalPointCharacter, groupingStyle,
517 groupingCharacter, groupingSize, forceDecimalPoint);
518 }
519
520
521
522
523
524
525
526 public boolean isForcedDecimalPoint() {
527 return forceDecimalPoint;
528 }
529
530
531
532
533
534
535
536 public MoneyAmountStyle withForcedDecimalPoint(boolean forceDecimalPoint) {
537 if (this.forceDecimalPoint == forceDecimalPoint) {
538 return this;
539 }
540 return new MoneyAmountStyle(
541 zeroCharacter,
542 positiveCharacter, negativeCharacter,
543 decimalPointCharacter, groupingStyle,
544 groupingCharacter, groupingSize, forceDecimalPoint);
545 }
546
547
548
549
550
551
552
553
554 @Override
555 public boolean equals(Object other) {
556 if (other == this) {
557 return true;
558 }
559 if (other instanceof MoneyAmountStyle == false) {
560 return false;
561 }
562 MoneyAmountStyle otherStyle = (MoneyAmountStyle) other;
563 return (zeroCharacter == otherStyle.zeroCharacter) &&
564 (positiveCharacter == otherStyle.positiveCharacter) &&
565 (negativeCharacter == otherStyle.negativeCharacter) &&
566 (decimalPointCharacter == otherStyle.decimalPointCharacter) &&
567 (groupingStyle == otherStyle.groupingStyle) &&
568 (groupingCharacter == otherStyle.groupingCharacter) &&
569 (groupingSize == otherStyle.groupingSize) &&
570 (forceDecimalPoint == otherStyle.forceDecimalPoint);
571 }
572
573
574
575
576
577
578 @Override
579 public int hashCode() {
580 int hash = 13;
581 hash += zeroCharacter * 17;
582 hash += positiveCharacter * 17;
583 hash += negativeCharacter * 17;
584 hash += decimalPointCharacter * 17;
585 hash += groupingStyle.hashCode() * 17;
586 hash += groupingCharacter * 17;
587 hash += groupingSize * 17;
588 hash += (forceDecimalPoint ? 2 : 4);
589 return hash;
590 }
591
592
593
594
595
596
597
598 @Override
599 public String toString() {
600 return "MoneyAmountStyle['" + getZeroCharacter() + "','" + getPositiveSignCharacter() + "','" +
601 getNegativeSignCharacter() + "','" + getDecimalPointCharacter() + "','" +
602 getGroupingStyle() + "," + getGroupingCharacter() + "','" + getGroupingSize() + "'," +
603 isForcedDecimalPoint() + "]";
604 }
605
606 }