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