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.StateHolder;
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, StateHolder
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 Object values[] = (Object[])state;
288 _currencyCode = (String)values[0];
289 _currencySymbol = (String)values[1];
290 _locale = (Locale)values[2];
291 Integer value = (Integer)values[3];
292 _maxFractionDigits = value != null ? value.intValue() : 0;
293 value = (Integer)values[4];
294 _maxIntegerDigits = value != null ? value.intValue() : 0;
295 value = (Integer)values[5];
296 _minFractionDigits = value != null ? value.intValue() : 0;
297 value = (Integer)values[6];
298 _minIntegerDigits = value != null ? value.intValue() : 0;
299 _pattern = (String)values[7];
300 _type = (String)values[8];
301 _groupingUsed = ((Boolean)values[9]).booleanValue();
302 _integerOnly = ((Boolean)values[10]).booleanValue();
303 _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
304 _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
305 _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
306 _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
307 }
308
309 public Object saveState(FacesContext facesContext)
310 {
311 Object values[] = new Object[15];
312 values[0] = _currencyCode;
313 values[1] = _currencySymbol;
314 values[2] = _locale;
315 values[3] = _maxFractionDigitsSet ? new Integer(_maxFractionDigits) : null;
316 values[4] = _maxIntegerDigitsSet ? new Integer(_maxIntegerDigits) : null;
317 values[5] = _minFractionDigitsSet ? new Integer(_minFractionDigits) : null;
318 values[6] = _minIntegerDigitsSet ? new Integer(_minIntegerDigits) : null;
319 values[7] = _pattern;
320 values[8] = _type;
321 values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
322 values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
323 values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
324 values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
325 values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
326 values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
327 return values;
328 }
329
330
331
332
333
334
335
336 @JSFProperty
337 public String getCurrencyCode()
338 {
339 return _currencyCode != null ?
340 _currencyCode :
341 getDecimalFormatSymbols().getInternationalCurrencySymbol();
342 }
343
344 public void setCurrencyCode(String currencyCode)
345 {
346 _currencyCode = currencyCode;
347 }
348
349
350
351
352
353
354 @JSFProperty
355 public String getCurrencySymbol()
356 {
357 return _currencySymbol != null ?
358 _currencySymbol :
359 getDecimalFormatSymbols().getCurrencySymbol();
360 }
361
362 public void setCurrencySymbol(String currencySymbol)
363 {
364 _currencySymbol = currencySymbol;
365 }
366
367
368
369
370
371 @JSFProperty
372 public boolean isGroupingUsed()
373 {
374 return _groupingUsed;
375 }
376
377 public void setGroupingUsed(boolean groupingUsed)
378 {
379 _groupingUsed = groupingUsed;
380 }
381
382
383
384
385
386 @JSFProperty
387 public boolean isIntegerOnly()
388 {
389 return _integerOnly;
390 }
391
392 public void setIntegerOnly(boolean integerOnly)
393 {
394 _integerOnly = integerOnly;
395 }
396
397
398
399
400
401
402 @JSFProperty
403 public Locale getLocale()
404 {
405 if (_locale != null) return _locale;
406 FacesContext context = FacesContext.getCurrentInstance();
407 return context.getViewRoot().getLocale();
408 }
409
410 public void setLocale(Locale locale)
411 {
412 _locale = locale;
413 }
414
415
416
417
418
419 @JSFProperty
420 public int getMaxFractionDigits()
421 {
422 return _maxFractionDigits;
423 }
424
425 public void setMaxFractionDigits(int maxFractionDigits)
426 {
427 _maxFractionDigitsSet = true;
428 _maxFractionDigits = maxFractionDigits;
429 }
430
431
432
433
434
435 @JSFProperty
436 public int getMaxIntegerDigits()
437 {
438 return _maxIntegerDigits;
439 }
440
441 public void setMaxIntegerDigits(int maxIntegerDigits)
442 {
443 _maxIntegerDigitsSet = true;
444 _maxIntegerDigits = maxIntegerDigits;
445 }
446
447
448
449
450
451 @JSFProperty
452 public int getMinFractionDigits()
453 {
454 return _minFractionDigits;
455 }
456
457 public void setMinFractionDigits(int minFractionDigits)
458 {
459 _minFractionDigitsSet = true;
460 _minFractionDigits = minFractionDigits;
461 }
462
463
464
465
466
467 @JSFProperty
468 public int getMinIntegerDigits()
469 {
470 return _minIntegerDigits;
471 }
472
473 public void setMinIntegerDigits(int minIntegerDigits)
474 {
475 _minIntegerDigitsSet = true;
476 _minIntegerDigits = minIntegerDigits;
477 }
478
479
480
481
482
483 @JSFProperty
484 public String getPattern()
485 {
486 return _pattern;
487 }
488
489 public void setPattern(String pattern)
490 {
491 _pattern = pattern;
492 }
493
494 public boolean isTransient()
495 {
496 return _transient;
497 }
498
499 public void setTransient(boolean aTransient)
500 {
501 _transient = aTransient;
502 }
503
504
505
506
507
508
509 @JSFProperty
510 public String getType()
511 {
512 return _type;
513 }
514
515 public void setType(String type)
516 {
517
518 _type = type;
519 }
520
521 private static boolean checkJavaVersion14()
522 {
523 String version = System.getProperty("java.version");
524 if (version == null)
525 {
526 return false;
527 }
528 byte java14 = 0;
529 for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
530 {
531 if (idx > 0)
532 {
533 byte value = Byte.parseByte(version.substring(0, 1));
534 version = version.substring(idx + 1, version.length());
535 idx = version.indexOf('.');
536 switch (i)
537 {
538 case 0:
539 if (value == 1)
540 {
541 java14 = 1;
542 break;
543 }
544 else if (value > 1)
545 {
546 java14 = 2;
547 }
548 case 1:
549 if (java14 > 0 && value >= 4)
550 {
551 java14 = 2;
552 }
553 ;
554 default:
555 idx = 0;
556 version = null;
557 break;
558 }
559 }
560 else
561 {
562 byte value = Byte.parseByte(version.substring(0, 1));
563 if (java14 > 0 && value >= 4)
564 {
565 java14 = 2;
566 }
567 break;
568 }
569 }
570 return java14 == 2;
571 }
572
573
574 private DecimalFormatSymbols getDecimalFormatSymbols()
575 {
576 return new DecimalFormatSymbols(getLocale());
577 }
578 }