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