1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package javax.faces.convert;
20
21 import java.math.BigDecimal;
22 import java.text.DecimalFormat;
23 import java.text.DecimalFormatSymbols;
24 import java.text.NumberFormat;
25 import java.text.ParseException;
26 import java.util.Currency;
27 import java.util.Locale;
28
29 import javax.el.ValueExpression;
30 import javax.faces.component.PartialStateHolder;
31 import javax.faces.component.UIComponent;
32 import javax.faces.context.FacesContext;
33
34 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
35 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFJspProperty;
36 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
37
38
39
40
41
42
43
44
45
46
47
48
49 @JSFConverter(
50 name="f:convertNumber",
51 bodyContent="empty",
52 tagClass="org.apache.myfaces.taglib.core.ConvertNumberTag")
53 @JSFJspProperty(
54 name="binding",
55 returnType = "javax.faces.convert.NumberConverter",
56 longDesc = "A ValueExpression that evaluates to a NumberConverter.")
57 public class NumberConverter
58 implements Converter, PartialStateHolder
59 {
60
61 public static final String CONVERTER_ID = "javax.faces.Number";
62 public static final String STRING_ID = "javax.faces.converter.STRING";
63 public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
64 public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
65 public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
66 public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
67
68 private static final boolean JAVA_VERSION_14;
69
70 static
71 {
72 JAVA_VERSION_14 = checkJavaVersion14();
73 }
74
75 private String _currencyCode;
76 private String _currencySymbol;
77 private Locale _locale;
78 private int _maxFractionDigits;
79 private int _maxIntegerDigits;
80 private int _minFractionDigits;
81 private int _minIntegerDigits;
82 private String _pattern;
83 private String _type = "number";
84 private boolean _groupingUsed = true;
85 private boolean _integerOnly = false;
86 private boolean _transient;
87
88 private boolean _maxFractionDigitsSet;
89 private boolean _maxIntegerDigitsSet;
90 private boolean _minFractionDigitsSet;
91 private boolean _minIntegerDigitsSet;
92
93
94
95 public NumberConverter()
96 {
97 }
98
99
100 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
101 {
102 if (facesContext == null)
103 {
104 throw new NullPointerException("facesContext");
105 }
106 if (uiComponent == null)
107 {
108 throw new NullPointerException("uiComponent");
109 }
110
111 if (value != null)
112 {
113 value = value.trim();
114 if (value.length() > 0)
115 {
116 NumberFormat format = getNumberFormat(facesContext);
117 format.setParseIntegerOnly(_integerOnly);
118
119 DecimalFormat df = (DecimalFormat)format;
120
121
122
123
124
125
126 ValueExpression valueBinding = uiComponent.getValueExpression("value");
127 if (valueBinding != null)
128 {
129 Class<?> destType = valueBinding.getType(facesContext.getELContext());
130 if (destType != null && BigDecimal.class.isAssignableFrom(destType))
131 {
132 df.setParseBigDecimal(true);
133 }
134 }
135
136 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
137 boolean changed = false;
138 if(dfs.getGroupingSeparator() == '\u00a0')
139 {
140 dfs.setGroupingSeparator(' ');
141 df.setDecimalFormatSymbols(dfs);
142 changed = true;
143 }
144
145 formatCurrency(format);
146
147 try
148 {
149 return format.parse(value);
150 }
151 catch (ParseException e)
152 {
153 if(changed)
154 {
155 dfs.setGroupingSeparator('\u00a0');
156 df.setDecimalFormatSymbols(dfs);
157 }
158 try
159 {
160 return format.parse(value);
161 }
162 catch (ParseException pe)
163 {
164
165 if(getPattern() != null)
166 {
167 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
168 PATTERN_ID,
169 new Object[]{value, "$###,###", _MessageUtils.getLabel(facesContext, uiComponent)}));
170 }
171 else if(getType().equals("number"))
172 {
173 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
174 NUMBER_ID,
175 new Object[]{value, format.format(21),
176 _MessageUtils.getLabel(facesContext, uiComponent)}));
177 }
178 else if(getType().equals("currency"))
179 {
180 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
181 CURRENCY_ID,
182 new Object[]{value, format.format(42.25),
183 _MessageUtils.getLabel(facesContext, uiComponent)}));
184 }
185 else if(getType().equals("percent"))
186 {
187 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
188 PERCENT_ID,
189 new Object[]{value, format.format(.90),
190 _MessageUtils.getLabel(facesContext, uiComponent)}));
191 }
192 }
193 }
194 }
195 }
196 return null;
197 }
198
199 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
200 {
201 if (facesContext == null)
202 {
203 throw new NullPointerException("facesContext");
204 }
205 if (uiComponent == null)
206 {
207 throw new NullPointerException("uiComponent");
208 }
209
210 if (value == null)
211 {
212 return "";
213 }
214 if (value instanceof String)
215 {
216 return (String)value;
217 }
218
219 NumberFormat format = getNumberFormat(facesContext);
220 format.setGroupingUsed(_groupingUsed);
221 if (_maxFractionDigitsSet)
222 {
223 format.setMaximumFractionDigits(_maxFractionDigits);
224 }
225 if (_maxIntegerDigitsSet)
226 {
227 format.setMaximumIntegerDigits(_maxIntegerDigits);
228 }
229 if (_minFractionDigitsSet)
230 {
231 format.setMinimumFractionDigits(_minFractionDigits);
232 }
233 if (_minIntegerDigitsSet)
234 {
235 format.setMinimumIntegerDigits(_minIntegerDigits);
236 }
237 formatCurrency(format);
238 try
239 {
240 return format.format(value);
241 }
242 catch (Exception e)
243 {
244 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID,
245 new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
246 }
247 }
248
249 private NumberFormat getNumberFormat(FacesContext facesContext)
250 {
251 Locale locale = _locale != null ? _locale : facesContext.getViewRoot().getLocale();
252
253 if (_pattern == null && _type == null)
254 {
255 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
256 }
257
258
259 if (_pattern != null)
260 {
261 return new DecimalFormat(_pattern, new DecimalFormatSymbols(locale));
262 }
263
264
265 if (_type.equals("number"))
266 {
267 return NumberFormat.getNumberInstance(locale);
268 }
269 else if (_type.equals("currency"))
270 {
271 return NumberFormat.getCurrencyInstance(locale);
272 }
273 else if (_type.equals("percent"))
274 {
275 return NumberFormat.getPercentInstance(locale);
276 }
277 throw new ConverterException("Cannot get NumberFormat, illegal type " + _type);
278 }
279
280 private void formatCurrency(NumberFormat format)
281 {
282 if (_currencyCode == null && _currencySymbol == null)
283 {
284 return;
285 }
286
287 boolean useCurrencyCode;
288 if (JAVA_VERSION_14)
289 {
290 useCurrencyCode = _currencyCode != null;
291 }
292 else
293 {
294 useCurrencyCode = _currencySymbol == null;
295 }
296
297 if (useCurrencyCode)
298 {
299
300 try
301 {
302 format.setCurrency(Currency.getInstance(_currencyCode));
303 }
304 catch (Exception e)
305 {
306 throw new ConverterException("Unable to get Currency instance for currencyCode " +
307 _currencyCode);
308 }
309 }
310 else if (format instanceof DecimalFormat)
311
312 {
313 DecimalFormat dFormat = (DecimalFormat)format;
314 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
315 symbols.setCurrencySymbol(_currencySymbol);
316 dFormat.setDecimalFormatSymbols(symbols);
317 }
318 }
319
320
321 public void restoreState(FacesContext facesContext, Object state)
322 {
323 if (state != null)
324 {
325 Object values[] = (Object[])state;
326 _currencyCode = (String)values[0];
327 _currencySymbol = (String)values[1];
328 _locale = (Locale)values[2];
329 Integer value = (Integer)values[3];
330 _maxFractionDigits = value != null ? value.intValue() : 0;
331 value = (Integer)values[4];
332 _maxIntegerDigits = value != null ? value.intValue() : 0;
333 value = (Integer)values[5];
334 _minFractionDigits = value != null ? value.intValue() : 0;
335 value = (Integer)values[6];
336 _minIntegerDigits = value != null ? value.intValue() : 0;
337 _pattern = (String)values[7];
338 _type = (String)values[8];
339 _groupingUsed = ((Boolean)values[9]).booleanValue();
340 _integerOnly = ((Boolean)values[10]).booleanValue();
341 _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
342 _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
343 _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
344 _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
345 }
346 }
347
348 public Object saveState(FacesContext facesContext)
349 {
350 if (!initialStateMarked())
351 {
352 Object values[] = new Object[15];
353 values[0] = _currencyCode;
354 values[1] = _currencySymbol;
355 values[2] = _locale;
356 values[3] = _maxFractionDigitsSet ? Integer.valueOf(_maxFractionDigits) : null;
357 values[4] = _maxIntegerDigitsSet ? Integer.valueOf(_maxIntegerDigits) : null;
358 values[5] = _minFractionDigitsSet ? Integer.valueOf(_minFractionDigits) : null;
359 values[6] = _minIntegerDigitsSet ? Integer.valueOf(_minIntegerDigits) : null;
360 values[7] = _pattern;
361 values[8] = _type;
362 values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
363 values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
364 values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
365 values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
366 values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
367 values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
368 return values;
369 }
370 return null;
371 }
372
373
374
375
376
377
378
379 @JSFProperty
380 public String getCurrencyCode()
381 {
382 return _currencyCode != null ?
383 _currencyCode :
384 getDecimalFormatSymbols().getInternationalCurrencySymbol();
385 }
386
387 public void setCurrencyCode(String currencyCode)
388 {
389 _currencyCode = currencyCode;
390 clearInitialState();
391 }
392
393
394
395
396
397
398 @JSFProperty
399 public String getCurrencySymbol()
400 {
401 return _currencySymbol != null ?
402 _currencySymbol :
403 getDecimalFormatSymbols().getCurrencySymbol();
404 }
405
406 public void setCurrencySymbol(String currencySymbol)
407 {
408 _currencySymbol = currencySymbol;
409 clearInitialState();
410 }
411
412
413
414
415
416 @JSFProperty(deferredValueType="java.lang.Boolean")
417 public boolean isGroupingUsed()
418 {
419 return _groupingUsed;
420 }
421
422 public void setGroupingUsed(boolean groupingUsed)
423 {
424 _groupingUsed = groupingUsed;
425 clearInitialState();
426 }
427
428
429
430
431
432 @JSFProperty(deferredValueType="java.lang.Boolean")
433 public boolean isIntegerOnly()
434 {
435 return _integerOnly;
436 }
437
438 public void setIntegerOnly(boolean integerOnly)
439 {
440 _integerOnly = integerOnly;
441 clearInitialState();
442 }
443
444
445
446
447
448
449 @JSFProperty(deferredValueType="java.lang.Object")
450 public Locale getLocale()
451 {
452 if (_locale != null)
453 {
454 return _locale;
455 }
456 FacesContext context = FacesContext.getCurrentInstance();
457 return context.getViewRoot().getLocale();
458 }
459
460 public void setLocale(Locale locale)
461 {
462 _locale = locale;
463 clearInitialState();
464 }
465
466
467
468
469
470 @JSFProperty(deferredValueType="java.lang.Integer")
471 public int getMaxFractionDigits()
472 {
473 return _maxFractionDigits;
474 }
475
476 public void setMaxFractionDigits(int maxFractionDigits)
477 {
478 _maxFractionDigitsSet = true;
479 _maxFractionDigits = maxFractionDigits;
480 clearInitialState();
481 }
482
483
484
485
486
487 @JSFProperty(deferredValueType="java.lang.Integer")
488 public int getMaxIntegerDigits()
489 {
490 return _maxIntegerDigits;
491 }
492
493 public void setMaxIntegerDigits(int maxIntegerDigits)
494 {
495 _maxIntegerDigitsSet = true;
496 _maxIntegerDigits = maxIntegerDigits;
497 clearInitialState();
498 }
499
500
501
502
503
504 @JSFProperty(deferredValueType="java.lang.Integer")
505 public int getMinFractionDigits()
506 {
507 return _minFractionDigits;
508 }
509
510 public void setMinFractionDigits(int minFractionDigits)
511 {
512 _minFractionDigitsSet = true;
513 _minFractionDigits = minFractionDigits;
514 clearInitialState();
515 }
516
517
518
519
520
521 @JSFProperty(deferredValueType="java.lang.Integer")
522 public int getMinIntegerDigits()
523 {
524 return _minIntegerDigits;
525 }
526
527 public void setMinIntegerDigits(int minIntegerDigits)
528 {
529 _minIntegerDigitsSet = true;
530 _minIntegerDigits = minIntegerDigits;
531 clearInitialState();
532 }
533
534
535
536
537
538 @JSFProperty
539 public String getPattern()
540 {
541 return _pattern;
542 }
543
544 public void setPattern(String pattern)
545 {
546 _pattern = pattern;
547 clearInitialState();
548 }
549
550 public boolean isTransient()
551 {
552 return _transient;
553 }
554
555 public void setTransient(boolean aTransient)
556 {
557 _transient = aTransient;
558 }
559
560
561
562
563
564
565 @JSFProperty
566 public String getType()
567 {
568 return _type;
569 }
570
571 public void setType(String type)
572 {
573
574 _type = type;
575 clearInitialState();
576 }
577
578 private static boolean checkJavaVersion14()
579 {
580 String version = System.getProperty("java.version");
581 if (version == null)
582 {
583 return false;
584 }
585 byte java14 = 0;
586 for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
587 {
588 if (idx > 0)
589 {
590 byte value = Byte.parseByte(version.substring(0, 1));
591 version = version.substring(idx + 1, version.length());
592 idx = version.indexOf('.');
593 switch (i)
594 {
595 case 0:
596 if (value == 1)
597 {
598 java14 = 1;
599 break;
600 }
601 else if (value > 1)
602 {
603 java14 = 2;
604 }
605
606 case 1:
607 if (java14 > 0 && value >= 4)
608 {
609 java14 = 2;
610 }
611
612
613 default:
614 idx = 0;
615 version = null;
616 break;
617 }
618 }
619 else
620 {
621 byte value = Byte.parseByte(version.substring(0, 1));
622 if (java14 > 0 && value >= 4)
623 {
624 java14 = 2;
625 }
626 break;
627 }
628 }
629 return java14 == 2;
630 }
631
632
633 private DecimalFormatSymbols getDecimalFormatSymbols()
634 {
635 return new DecimalFormatSymbols(getLocale());
636 }
637
638 private boolean _initialStateMarked = false;
639
640 public void clearInitialState()
641 {
642 _initialStateMarked = false;
643 }
644
645 public boolean initialStateMarked()
646 {
647 return _initialStateMarked;
648 }
649
650 public void markInitialState()
651 {
652 _initialStateMarked = true;
653 }
654 }