1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.commons.converter;
20
21 import java.text.DecimalFormat;
22 import java.text.DecimalFormatSymbols;
23 import java.text.NumberFormat;
24 import java.text.ParseException;
25 import java.util.Currency;
26 import java.util.Locale;
27
28 import javax.el.ValueExpression;
29 import javax.faces.application.FacesMessage;
30 import javax.faces.component.StateHolder;
31 import javax.faces.component.UIComponent;
32 import javax.faces.context.FacesContext;
33 import javax.faces.convert.ConverterException;
34
35 import org.apache.commons.beanutils.ConvertUtils;
36 import org.apache.commons.beanutils.Converter;
37 import org.apache.myfaces.commons.util.MessageUtils;
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 public class TypedNumberConverter implements javax.faces.convert.Converter, StateHolder
57 {
58 public static final String CONVERTER_ID = "org.apache.myfaces.custom.convertNumber.TypedNumberConverter";
59
60 private Class destType;
61
62 public TypedNumberConverter()
63 {
64 }
65
66 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
67 {
68 Object convertedValue = _getAsObject(facesContext, uiComponent, value);
69 if (convertedValue == null)
70 {
71 return null;
72 }
73
74 Class destType = getDestType();
75 if (destType == null)
76 {
77 ValueExpression valueBinding = uiComponent.getValueExpression("value");
78 if (valueBinding != null)
79 {
80 destType = valueBinding.getType(facesContext.getELContext());
81 }
82 }
83
84 if (destType != null)
85 {
86 Converter converter = ConvertUtils.lookup(destType);
87 if (converter == null)
88 {
89 throw new UnsupportedOperationException("cant deal with " + destType);
90 }
91
92
93 convertedValue = converter.convert(null, convertedValue);
94 }
95
96
97 return convertedValue;
98 }
99
100 public void restoreState(FacesContext facesContext, Object state)
101 {
102 Object[] states = (Object[]) state;
103 _restoreState(facesContext, states[0]);
104 destType = (Class) states[1];
105 }
106
107 public Object saveState(FacesContext facesContext)
108 {
109 return new Object[]
110 {
111 _saveState(facesContext),
112 destType
113 };
114 }
115
116
117
118
119
120
121
122
123 public Class getDestType()
124 {
125 return destType;
126 }
127
128 public void setDestType(Class destType)
129 {
130 this.destType = destType;
131 }
132
133
134
135
136 private static final String CONVERSION_MESSAGE_ID = "javax.faces.convert.NumberConverter.CONVERSION";
137
138
139 private static final boolean JAVA_VERSION_14;
140
141 static
142 {
143 JAVA_VERSION_14 = checkJavaVersion14();
144 }
145
146 private String _currencyCode;
147 private String _currencySymbol;
148 private Locale _locale;
149 private int _maxFractionDigits;
150 private int _maxIntegerDigits;
151 private int _minFractionDigits;
152 private int _minIntegerDigits;
153 private String _pattern;
154 private String _type = "number";
155 private boolean _groupingUsed = true;
156 private boolean _integerOnly = false;
157 private boolean _transient;
158
159 private boolean _maxFractionDigitsSet;
160 private boolean _maxIntegerDigitsSet;
161 private boolean _minFractionDigitsSet;
162 private boolean _minIntegerDigitsSet;
163
164
165
166 public Object _getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
167 {
168 if (facesContext == null) throw new NullPointerException("facesContext");
169 if (uiComponent == null) throw new NullPointerException("uiComponent");
170
171 if (value != null)
172 {
173 value = value.trim();
174 if (value.length() > 0)
175 {
176 NumberFormat format = getNumberFormat(facesContext);
177 format.setParseIntegerOnly(_integerOnly);
178 try
179 {
180 return format.parse(value);
181 }
182 catch (ParseException e)
183 {
184 FacesMessage message = MessageUtils.getMessage(facesContext, CONVERSION_MESSAGE_ID, new Object[]{uiComponent.getId(),value});
185 message.setSeverity(FacesMessage.SEVERITY_ERROR);
186
187 throw new ConverterException(message, e);
188 }
189 }
190 }
191 return null;
192 }
193
194 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
195 {
196 if (facesContext == null) throw new NullPointerException("facesContext");
197 if (uiComponent == null) throw new NullPointerException("uiComponent");
198
199 if (value == null)
200 {
201 return "";
202 }
203 if (value instanceof String)
204 {
205 return (String)value;
206 }
207
208 NumberFormat format = getNumberFormat(facesContext);
209 format.setGroupingUsed(_groupingUsed);
210 if (_maxFractionDigitsSet) format.setMaximumFractionDigits(_maxFractionDigits);
211 if (_maxIntegerDigitsSet) format.setMaximumIntegerDigits(_maxIntegerDigits);
212 if (_minFractionDigitsSet) format.setMinimumFractionDigits(_minFractionDigits);
213 if (_minIntegerDigitsSet) format.setMinimumIntegerDigits(_minIntegerDigits);
214 formatCurrency(format);
215 try
216 {
217 return format.format(value);
218 }
219 catch (Exception e)
220 {
221 throw new ConverterException("Cannot convert value '" + value + "'");
222 }
223 }
224
225 private NumberFormat getNumberFormat(FacesContext facesContext)
226 {
227 Locale lokale = _locale != null ? _locale : facesContext.getViewRoot().getLocale();
228
229 if (_pattern == null && _type == null)
230 {
231 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
232 }
233
234
235 if (_pattern != null)
236 {
237 return new DecimalFormat(_pattern, new DecimalFormatSymbols(lokale));
238 }
239
240
241 if (_type.equals("number"))
242 {
243 return NumberFormat.getNumberInstance(lokale);
244 }
245 else if (_type.equals("currency"))
246 {
247 return NumberFormat.getCurrencyInstance(lokale);
248 }
249 else if (_type.equals("percent"))
250 {
251 return NumberFormat.getPercentInstance(lokale);
252 }
253 throw new ConverterException("Cannot get NumberFormat, illegal type " + _type);
254 }
255
256 private void formatCurrency(NumberFormat format)
257 {
258 if (_currencyCode == null && _currencySymbol == null)
259 {
260 return;
261 }
262
263 boolean useCurrencyCode;
264 if (JAVA_VERSION_14)
265 {
266 useCurrencyCode = _currencyCode != null;
267 }
268 else
269 {
270 useCurrencyCode = _currencySymbol == null;
271 }
272
273 if (useCurrencyCode)
274 {
275
276 try
277 {
278 format.setCurrency(Currency.getInstance(_currencyCode));
279 }
280 catch (Exception e)
281 {
282 throw new ConverterException("Unable to get Currency instance for currencyCode " +
283 _currencyCode);
284 }
285 }
286 else if (format instanceof DecimalFormat)
287
288 {
289 DecimalFormat dFormat = (DecimalFormat)format;
290 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
291 symbols.setCurrencySymbol(_currencySymbol);
292 dFormat.setDecimalFormatSymbols(symbols);
293 }
294 }
295
296
297 public void _restoreState(FacesContext facesContext, Object state)
298 {
299 Object values[] = (Object[])state;
300 _currencyCode = (String)values[0];
301 _currencySymbol = (String)values[1];
302 _locale = (Locale)values[2];
303 Integer value = (Integer)values[3];
304 _maxFractionDigits = value != null ? value.intValue() : 0;
305 value = (Integer)values[4];
306 _maxIntegerDigits = value != null ? value.intValue() : 0;
307 value = (Integer)values[5];
308 _minFractionDigits = value != null ? value.intValue() : 0;
309 value = (Integer)values[6];
310 _minIntegerDigits = value != null ? value.intValue() : 0;
311 _pattern = (String)values[7];
312 _type = (String)values[8];
313 _groupingUsed = ((Boolean)values[9]).booleanValue();
314 _integerOnly = ((Boolean)values[10]).booleanValue();
315 _maxFractionDigitsSet = ((Boolean)values[11]).booleanValue();
316 _maxIntegerDigitsSet = ((Boolean)values[12]).booleanValue();
317 _minFractionDigitsSet = ((Boolean)values[13]).booleanValue();
318 _minIntegerDigitsSet = ((Boolean)values[14]).booleanValue();
319 }
320
321 public Object _saveState(FacesContext facesContext)
322 {
323 Object values[] = new Object[15];
324 values[0] = _currencyCode;
325 values[1] = _currencySymbol;
326 values[2] = _locale;
327 values[3] = _maxFractionDigitsSet ? Integer.valueOf(_maxFractionDigits) : null;
328 values[4] = _maxIntegerDigitsSet ? Integer.valueOf(_maxIntegerDigits) : null;
329 values[5] = _minFractionDigitsSet ? Integer.valueOf(_minFractionDigits) : null;
330 values[6] = _minIntegerDigitsSet ? Integer.valueOf(_minIntegerDigits) : null;
331 values[7] = _pattern;
332 values[8] = _type;
333 values[9] = _groupingUsed ? Boolean.TRUE : Boolean.FALSE;
334 values[10] = _integerOnly ? Boolean.TRUE : Boolean.FALSE;
335 values[11] = _maxFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
336 values[12] = _maxIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
337 values[13] = _minFractionDigitsSet ? Boolean.TRUE : Boolean.FALSE;
338 values[14] = _minIntegerDigitsSet ? Boolean.TRUE : Boolean.FALSE;
339 return values;
340 }
341
342
343
344
345
346
347
348
349 public String getCurrencyCode()
350 {
351 return _currencyCode != null ?
352 _currencyCode :
353 getDecimalFormatSymbols().getInternationalCurrencySymbol();
354 }
355
356 public void setCurrencyCode(String currencyCode)
357 {
358 _currencyCode = currencyCode;
359 }
360
361
362
363
364
365
366
367
368 public String getCurrencySymbol()
369 {
370 return _currencySymbol != null ?
371 _currencySymbol :
372 getDecimalFormatSymbols().getCurrencySymbol();
373 }
374
375 public void setCurrencySymbol(String currencySymbol)
376 {
377 _currencySymbol = currencySymbol;
378 }
379
380
381
382
383
384
385
386
387 public boolean isGroupingUsed()
388 {
389 return _groupingUsed;
390 }
391
392 public void setGroupingUsed(boolean groupingUsed)
393 {
394 _groupingUsed = groupingUsed;
395 }
396
397
398
399
400
401
402
403
404 public boolean isIntegerOnly()
405 {
406 return _integerOnly;
407 }
408
409 public void setIntegerOnly(boolean integerOnly)
410 {
411 _integerOnly = integerOnly;
412 }
413
414
415
416
417
418
419
420 public Locale getLocale()
421 {
422 if (_locale != null) return _locale;
423 FacesContext context = FacesContext.getCurrentInstance();
424 return context.getViewRoot().getLocale();
425 }
426
427 public void setLocale(Locale locale)
428 {
429 _locale = locale;
430 }
431
432
433
434
435
436
437 public int getMaxFractionDigits()
438 {
439 return _maxFractionDigits;
440 }
441
442 public void setMaxFractionDigits(int maxFractionDigits)
443 {
444 _maxFractionDigitsSet = true;
445 _maxFractionDigits = maxFractionDigits;
446 }
447
448
449
450
451
452
453 public int getMaxIntegerDigits()
454 {
455 return _maxIntegerDigits;
456 }
457
458 public void setMaxIntegerDigits(int maxIntegerDigits)
459 {
460 _maxIntegerDigitsSet = true;
461 _maxIntegerDigits = maxIntegerDigits;
462 }
463
464
465
466
467
468
469 public int getMinFractionDigits()
470 {
471 return _minFractionDigits;
472 }
473
474 public void setMinFractionDigits(int minFractionDigits)
475 {
476 _minFractionDigitsSet = true;
477 _minFractionDigits = minFractionDigits;
478 }
479
480
481
482
483
484
485 public int getMinIntegerDigits()
486 {
487 return _minIntegerDigits;
488 }
489
490 public void setMinIntegerDigits(int minIntegerDigits)
491 {
492 _minIntegerDigitsSet = true;
493 _minIntegerDigits = minIntegerDigits;
494 }
495
496
497
498
499
500
501 public String getPattern()
502 {
503 return _pattern;
504 }
505
506 public void setPattern(String pattern)
507 {
508 _pattern = pattern;
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
527
528 public String getType()
529 {
530 return _type;
531 }
532
533 public void setType(String type)
534 {
535
536 _type = type;
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 }