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 value = value.replace('\u00a0', ' ');
143 changed = true;
144 }
145
146 formatCurrency(format);
147
148 try
149 {
150 return format.parse(value);
151 }
152 catch (ParseException e)
153 {
154 if(changed)
155 {
156 dfs.setGroupingSeparator('\u00a0');
157 df.setDecimalFormatSymbols(dfs);
158 }
159 try
160 {
161 return format.parse(value);
162 }
163 catch (ParseException pe)
164 {
165
166 if(getPattern() != null)
167 {
168 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
169 PATTERN_ID,
170 new Object[]{value, "$###,###", _MessageUtils.getLabel(facesContext, uiComponent)}));
171 }
172 else if(getType().equals("number"))
173 {
174 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
175 NUMBER_ID,
176 new Object[]{value, format.format(21),
177 _MessageUtils.getLabel(facesContext, uiComponent)}));
178 }
179 else if(getType().equals("currency"))
180 {
181 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
182 CURRENCY_ID,
183 new Object[]{value, format.format(42.25),
184 _MessageUtils.getLabel(facesContext, uiComponent)}));
185 }
186 else if(getType().equals("percent"))
187 {
188 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext,
189 PERCENT_ID,
190 new Object[]{value, format.format(.90),
191 _MessageUtils.getLabel(facesContext, uiComponent)}));
192 }
193 }
194 }
195 }
196 }
197 return null;
198 }
199
200 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
201 {
202 if (facesContext == null)
203 {
204 throw new NullPointerException("facesContext");
205 }
206 if (uiComponent == null)
207 {
208 throw new NullPointerException("uiComponent");
209 }
210
211 if (value == null)
212 {
213 return "";
214 }
215 if (value instanceof String)
216 {
217 return (String)value;
218 }
219
220 NumberFormat format = getNumberFormat(facesContext);
221 format.setGroupingUsed(_groupingUsed);
222 if (_maxFractionDigitsSet)
223 {
224 format.setMaximumFractionDigits(_maxFractionDigits);
225 }
226 if (_maxIntegerDigitsSet)
227 {
228 format.setMaximumIntegerDigits(_maxIntegerDigits);
229 }
230 if (_minFractionDigitsSet)
231 {
232 format.setMinimumFractionDigits(_minFractionDigits);
233 }
234 if (_minIntegerDigitsSet)
235 {
236 format.setMinimumIntegerDigits(_minIntegerDigits);
237 }
238 formatCurrency(format);
239 try
240 {
241 return format.format(value);
242 }
243 catch (Exception e)
244 {
245 throw new ConverterException(_MessageUtils.getErrorMessage(facesContext, STRING_ID,
246 new Object[]{value,_MessageUtils.getLabel(facesContext, uiComponent)}),e);
247 }
248 }
249
250 private NumberFormat getNumberFormat(FacesContext facesContext)
251 {
252 Locale locale = _locale != null ? _locale : facesContext.getViewRoot().getLocale();
253
254 if (_pattern == null && _type == null)
255 {
256 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
257 }
258
259
260 if (_pattern != null)
261 {
262 return new DecimalFormat(_pattern, new DecimalFormatSymbols(locale));
263 }
264
265
266 if (_type.equals("number"))
267 {
268 return NumberFormat.getNumberInstance(locale);
269 }
270 else if (_type.equals("currency"))
271 {
272 return NumberFormat.getCurrencyInstance(locale);
273 }
274 else if (_type.equals("percent"))
275 {
276 return NumberFormat.getPercentInstance(locale);
277 }
278 throw new ConverterException("Cannot get NumberFormat, illegal type " + _type);
279 }
280
281 private void formatCurrency(NumberFormat format)
282 {
283 if (_currencyCode == null && _currencySymbol == null)
284 {
285 return;
286 }
287
288 boolean useCurrencyCode;
289 if (JAVA_VERSION_14)
290 {
291 useCurrencyCode = _currencyCode != null;
292 }
293 else
294 {
295 useCurrencyCode = _currencySymbol == null;
296 }
297
298 if (useCurrencyCode)
299 {
300
301 try
302 {
303 format.setCurrency(Currency.getInstance(_currencyCode));
304 }
305 catch (Exception e)
306 {
307 throw new ConverterException("Unable to get Currency instance for currencyCode " +
308 _currencyCode);
309 }
310 }
311 else if (format instanceof DecimalFormat)
312
313 {
314 DecimalFormat dFormat = (DecimalFormat)format;
315 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
316 symbols.setCurrencySymbol(_currencySymbol);
317 dFormat.setDecimalFormatSymbols(symbols);
318 }
319 }
320
321
322 public void restoreState(FacesContext facesContext, Object state)
323 {
324 if (state != null)
325 {
326 Object values[] = (Object[])state;
327 _currencyCode = (String)values[0];
328 _currencySymbol = (String)values[1];
329 _locale = (Locale)values[2];
330 Integer value = (Integer)values[3];
331 _maxFractionDigits = value != null ? value.intValue() : 0;
332 value = (Integer)values[4];
333 _maxIntegerDigits = value != null ? value.intValue() : 0;
334 value = (Integer)values[5];
335 _minFractionDigits = value != null ? value.intValue() : 0;
336 value = (Integer)values[6];
337 _minIntegerDigits = value != null ? value.intValue() : 0;
338 _pattern = (String)values[7];
339 _type = (String)values[8];
340 _groupingUsed = ((Boolean)values[9]).booleanValue();
341 _integerOnly = ((Boolean)values[10]).booleanValue();
342 _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
343 _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
344 _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
345 _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
346 }
347 }
348
349 public Object saveState(FacesContext facesContext)
350 {
351 if (!initialStateMarked())
352 {
353 Object values[] = new Object[15];
354 values[0] = _currencyCode;
355 values[1] = _currencySymbol;
356 values[2] = _locale;
357 values[3] = _maxFractionDigitsSet ? Integer.valueOf(_maxFractionDigits) : null;
358 values[4] = _maxIntegerDigitsSet ? Integer.valueOf(_maxIntegerDigits) : null;
359 values[5] = _minFractionDigitsSet ? Integer.valueOf(_minFractionDigits) : null;
360 values[6] = _minIntegerDigitsSet ? Integer.valueOf(_minIntegerDigits) : null;
361 values[7] = _pattern;
362 values[8] = _type;
363 values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
364 values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
365 values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
366 values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
367 values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
368 values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
369 return values;
370 }
371 return null;
372 }
373
374
375
376
377
378
379
380 @JSFProperty
381 public String getCurrencyCode()
382 {
383 return _currencyCode != null ?
384 _currencyCode :
385 getDecimalFormatSymbols().getInternationalCurrencySymbol();
386 }
387
388 public void setCurrencyCode(String currencyCode)
389 {
390 _currencyCode = currencyCode;
391 clearInitialState();
392 }
393
394
395
396
397
398
399 @JSFProperty
400 public String getCurrencySymbol()
401 {
402 return _currencySymbol != null ?
403 _currencySymbol :
404 getDecimalFormatSymbols().getCurrencySymbol();
405 }
406
407 public void setCurrencySymbol(String currencySymbol)
408 {
409 _currencySymbol = currencySymbol;
410 clearInitialState();
411 }
412
413
414
415
416
417 @JSFProperty(deferredValueType="java.lang.Boolean")
418 public boolean isGroupingUsed()
419 {
420 return _groupingUsed;
421 }
422
423 public void setGroupingUsed(boolean groupingUsed)
424 {
425 _groupingUsed = groupingUsed;
426 clearInitialState();
427 }
428
429
430
431
432
433 @JSFProperty(deferredValueType="java.lang.Boolean")
434 public boolean isIntegerOnly()
435 {
436 return _integerOnly;
437 }
438
439 public void setIntegerOnly(boolean integerOnly)
440 {
441 _integerOnly = integerOnly;
442 clearInitialState();
443 }
444
445
446
447
448
449
450 @JSFProperty(deferredValueType="java.lang.Object")
451 public Locale getLocale()
452 {
453 if (_locale != null)
454 {
455 return _locale;
456 }
457 FacesContext context = FacesContext.getCurrentInstance();
458 return context.getViewRoot().getLocale();
459 }
460
461 public void setLocale(Locale locale)
462 {
463 _locale = locale;
464 clearInitialState();
465 }
466
467
468
469
470
471 @JSFProperty(deferredValueType="java.lang.Integer")
472 public int getMaxFractionDigits()
473 {
474 return _maxFractionDigits;
475 }
476
477 public void setMaxFractionDigits(int maxFractionDigits)
478 {
479 _maxFractionDigitsSet = true;
480 _maxFractionDigits = maxFractionDigits;
481 clearInitialState();
482 }
483
484
485
486
487
488 @JSFProperty(deferredValueType="java.lang.Integer")
489 public int getMaxIntegerDigits()
490 {
491 return _maxIntegerDigits;
492 }
493
494 public void setMaxIntegerDigits(int maxIntegerDigits)
495 {
496 _maxIntegerDigitsSet = true;
497 _maxIntegerDigits = maxIntegerDigits;
498 clearInitialState();
499 }
500
501
502
503
504
505 @JSFProperty(deferredValueType="java.lang.Integer")
506 public int getMinFractionDigits()
507 {
508 return _minFractionDigits;
509 }
510
511 public void setMinFractionDigits(int minFractionDigits)
512 {
513 _minFractionDigitsSet = true;
514 _minFractionDigits = minFractionDigits;
515 clearInitialState();
516 }
517
518
519
520
521
522 @JSFProperty(deferredValueType="java.lang.Integer")
523 public int getMinIntegerDigits()
524 {
525 return _minIntegerDigits;
526 }
527
528 public void setMinIntegerDigits(int minIntegerDigits)
529 {
530 _minIntegerDigitsSet = true;
531 _minIntegerDigits = minIntegerDigits;
532 clearInitialState();
533 }
534
535
536
537
538
539 @JSFProperty
540 public String getPattern()
541 {
542 return _pattern;
543 }
544
545 public void setPattern(String pattern)
546 {
547 _pattern = pattern;
548 clearInitialState();
549 }
550
551 public boolean isTransient()
552 {
553 return _transient;
554 }
555
556 public void setTransient(boolean aTransient)
557 {
558 _transient = aTransient;
559 }
560
561
562
563
564
565
566 @JSFProperty
567 public String getType()
568 {
569 return _type;
570 }
571
572 public void setType(String type)
573 {
574
575 _type = type;
576 clearInitialState();
577 }
578
579 private static boolean checkJavaVersion14()
580 {
581 String version = System.getProperty("java.version");
582 if (version == null)
583 {
584 return false;
585 }
586 byte java14 = 0;
587 for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
588 {
589 if (idx > 0)
590 {
591 byte value = Byte.parseByte(version.substring(0, 1));
592 version = version.substring(idx + 1, version.length());
593 idx = version.indexOf('.');
594 switch (i)
595 {
596 case 0:
597 if (value == 1)
598 {
599 java14 = 1;
600 break;
601 }
602 else if (value > 1)
603 {
604 java14 = 2;
605 }
606
607 case 1:
608 if (java14 > 0 && value >= 4)
609 {
610 java14 = 2;
611 }
612
613
614 default:
615 idx = 0;
616 version = null;
617 break;
618 }
619 }
620 else
621 {
622 byte value = Byte.parseByte(version.substring(0, 1));
623 if (java14 > 0 && value >= 4)
624 {
625 java14 = 2;
626 }
627 break;
628 }
629 }
630 return java14 == 2;
631 }
632
633
634 private DecimalFormatSymbols getDecimalFormatSymbols()
635 {
636 return new DecimalFormatSymbols(getLocale());
637 }
638
639 private boolean _initialStateMarked = false;
640
641 public void clearInitialState()
642 {
643 _initialStateMarked = false;
644 }
645
646 public boolean initialStateMarked()
647 {
648 return _initialStateMarked;
649 }
650
651 public void markInitialState()
652 {
653 _initialStateMarked = true;
654 }
655 }