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.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.FacesException;
31 import javax.faces.application.FacesMessage;
32 import javax.faces.component.UIComponent;
33 import javax.faces.context.FacesContext;
34 import javax.faces.convert.ConverterException;
35
36 import org.apache.commons.beanutils.ConvertUtils;
37 import org.apache.commons.beanutils.Converter;
38 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFConverter;
39 import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFProperty;
40 import org.apache.myfaces.commons.util.MessageUtils;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 @JSFConverter(
56 name = "mcc:convertNumber",
57 clazz = "org.apache.myfaces.commons.converter.TypedNumberConverter",
58 tagClass = "org.apache.myfaces.commons.converter.TypedNumberConverterTag",
59 tagHandler = "org.apache.myfaces.commons.converter.TypedNumberConverterTagHandler",
60 serialuidtag = "-6592309048440572608L")
61 public abstract class AbstractTypedNumberConverter extends ConverterBase
62 {
63 public static final String CONVERTER_ID = "org.apache.myfaces.custom.convertNumber.TypedNumberConverter";
64
65 private Class destType;
66
67 public AbstractTypedNumberConverter()
68 {
69 }
70
71 public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
72 {
73 Object convertedValue = _getAsObject(facesContext, uiComponent, value);
74 if (convertedValue == null)
75 {
76 return null;
77 }
78
79 Class destType = getDestType();
80 if (destType == null)
81 {
82 ValueExpression valueBinding = uiComponent.getValueExpression("value");
83 if (valueBinding != null)
84 {
85 destType = valueBinding.getType(facesContext.getELContext());
86 }
87 }
88
89 if (destType != null)
90 {
91 Converter converter = ConvertUtils.lookup(destType);
92 if (converter == null)
93 {
94 throw new UnsupportedOperationException("cant deal with " + destType);
95 }
96
97
98 convertedValue = converter.convert(null, convertedValue);
99 }
100
101
102 return convertedValue;
103 }
104
105 public void restoreState(FacesContext facesContext, Object state)
106 {
107 Object[] states = (Object[]) state;
108 _restoreState(facesContext, states[0]);
109 destType = (Class) states[1];
110 }
111
112 public Object saveState(FacesContext facesContext)
113 {
114 return new Object[]
115 {
116 _saveState(facesContext),
117 destType
118 };
119 }
120
121
122
123
124
125
126
127 @JSFProperty
128 public Class getDestType()
129 {
130 return destType;
131 }
132
133 public void setDestType(Class destType)
134 {
135 this.destType = destType;
136 }
137
138
139
140
141
142 public static final String STRING_ID = "javax.faces.converter.STRING";
143 public static final String CURRENCY_ID = "javax.faces.converter.NumberConverter.CURRENCY";
144 public static final String NUMBER_ID = "javax.faces.converter.NumberConverter.NUMBER";
145 public static final String PATTERN_ID = "javax.faces.converter.NumberConverter.PATTERN";
146 public static final String PERCENT_ID = "javax.faces.converter.NumberConverter.PERCENT";
147
148 private static final boolean JAVA_VERSION_14;
149
150 static
151 {
152 JAVA_VERSION_14 = checkJavaVersion14();
153 }
154
155 private String _currencyCode;
156 private String _currencySymbol;
157 private Locale _locale;
158 private boolean _transient;
159
160
161
162
163 public Object _getAsObject(FacesContext facesContext, UIComponent uiComponent, String value)
164 {
165 if (facesContext == null) throw new NullPointerException("facesContext");
166 if (uiComponent == null) throw new NullPointerException("uiComponent");
167
168 if (value != null)
169 {
170 value = value.trim();
171 if (value.length() > 0)
172 {
173 NumberFormat format = getNumberFormat(facesContext);
174 format.setParseIntegerOnly(isIntegerOnly());
175
176 DecimalFormat df = (DecimalFormat)format;
177
178
179
180
181
182
183 Class destType = getDestType();
184 if (destType == null)
185 {
186 ValueExpression valueBinding = uiComponent.getValueExpression("value");
187 if (valueBinding != null)
188 {
189 destType = valueBinding.getType(facesContext.getELContext());
190 }
191 }
192 if (destType != null && BigDecimal.class.isAssignableFrom(destType))
193 {
194 df.setParseBigDecimal(true);
195 }
196
197 DecimalFormatSymbols dfs = df.getDecimalFormatSymbols();
198 boolean changed = false;
199 if(dfs.getGroupingSeparator() == '\u00a0')
200 {
201 dfs.setGroupingSeparator(' ');
202 df.setDecimalFormatSymbols(dfs);
203 changed = true;
204 }
205
206 formatCurrency(format);
207
208 try
209 {
210 return format.parse(value);
211 }
212 catch (ParseException e)
213 {
214 if(changed)
215 {
216 dfs.setGroupingSeparator('\u00a0');
217 df.setDecimalFormatSymbols(dfs);
218 }
219 try
220 {
221 return format.parse(value);
222 }
223 catch (ParseException pe)
224 {
225
226 if(getPattern() != null)
227 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
228 PATTERN_ID,
229 new Object[]{value,"$###,###",MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
230 else if(getType().equals("number"))
231 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
232 NUMBER_ID,
233 new Object[]{value,format.format(21),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
234 else if(getType().equals("currency"))
235 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
236 CURRENCY_ID,
237 new Object[]{value,format.format(42.25),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
238 else if(getType().equals("percent"))
239 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR,
240 PERCENT_ID,
241 new Object[]{value,format.format(.90),MessageUtils.getLabel(facesContext, uiComponent)},facesContext));
242 }
243 }
244 }
245 }
246 return null;
247 }
248
249 public String getAsString(FacesContext facesContext, UIComponent uiComponent, Object value)
250 {
251 if (facesContext == null) throw new NullPointerException("facesContext");
252 if (uiComponent == null) throw new NullPointerException("uiComponent");
253
254 if (value == null)
255 {
256 return "";
257 }
258 if (value instanceof String)
259 {
260 return (String)value;
261 }
262
263 NumberFormat format = getNumberFormat(facesContext);
264 format.setGroupingUsed(isGroupingUsed());
265 Integer maxFractionDigits = getMaxFractionDigits();
266 Integer maxIntegerDigits = getMaxIntegerDigits();
267 Integer minFractionDigits = getMinFractionDigits();
268 Integer minIntegerDigits = getMinIntegerDigits();
269 if (maxFractionDigits != null) format.setMaximumFractionDigits(maxFractionDigits);
270 if (maxIntegerDigits != null) format.setMaximumIntegerDigits(maxIntegerDigits);
271 if (minFractionDigits != null) format.setMinimumFractionDigits(minFractionDigits);
272 if (minIntegerDigits != null) format.setMinimumIntegerDigits(minIntegerDigits);
273 formatCurrency(format);
274 try
275 {
276 return format.format(value);
277 }
278 catch (Exception e)
279 {
280 throw new ConverterException(MessageUtils.getMessage(FacesMessage.FACES_MESSAGES, FacesMessage.SEVERITY_ERROR, STRING_ID, new Object[]{value,MessageUtils.getLabel(facesContext, uiComponent)}, facesContext),e);
281 }
282 }
283
284 private NumberFormat getNumberFormat(FacesContext facesContext)
285 {
286 Locale lokale = getLocale();
287
288 if (getPattern() == null && getType() == null)
289 {
290 throw new ConverterException("Cannot get NumberFormat, either type or pattern needed.");
291 }
292
293
294 if (getPattern() != null)
295 {
296 return new DecimalFormat(getPattern(), new DecimalFormatSymbols(lokale));
297 }
298
299
300 if (getType().equals("number"))
301 {
302 return NumberFormat.getNumberInstance(lokale);
303 }
304 else if (getType().equals("currency"))
305 {
306 return NumberFormat.getCurrencyInstance(lokale);
307 }
308 else if (getType().equals("percent"))
309 {
310 return NumberFormat.getPercentInstance(lokale);
311 }
312 throw new ConverterException("Cannot get NumberFormat, illegal type " + getType());
313 }
314
315 private void formatCurrency(NumberFormat format)
316 {
317 if (getLocalCurrencyCode() == null && getLocalCurrencySymbol() == null)
318 {
319 return;
320 }
321
322 boolean useCurrencyCode;
323 if (JAVA_VERSION_14)
324 {
325 useCurrencyCode = getLocalCurrencyCode() != null;
326 }
327 else
328 {
329 useCurrencyCode = getLocalCurrencySymbol() == null;
330 }
331
332 if (useCurrencyCode)
333 {
334
335 try
336 {
337 format.setCurrency(Currency.getInstance(getLocalCurrencyCode()));
338 }
339 catch (Exception e)
340 {
341 throw new ConverterException("Unable to get Currency instance for currencyCode " +
342 getLocalCurrencyCode());
343 }
344 }
345 else if (format instanceof DecimalFormat)
346
347 {
348 DecimalFormat dFormat = (DecimalFormat)format;
349 DecimalFormatSymbols symbols = dFormat.getDecimalFormatSymbols();
350 symbols.setCurrencySymbol(getLocalCurrencySymbol());
351 dFormat.setDecimalFormatSymbols(symbols);
352 }
353 }
354
355
356 public void _restoreState(FacesContext facesContext, Object state)
357 {
358 Object values[] = (Object[])state;
359 super.restoreState(facesContext, values[0]);
360 _currencyCode = (String)values[1];
361 _currencySymbol = (String)values[2];
362 _locale = (Locale)values[3];
363 }
364
365 public Object _saveState(FacesContext facesContext)
366 {
367 Object values[] = new Object[4];
368 values[0] = super.saveState(facesContext);
369 values[1] = _currencyCode;
370 values[2] = _currencySymbol;
371 values[3] = _locale;
372 return values;
373 }
374
375
376
377
378
379
380
381 @JSFProperty
382 public String getCurrencyCode()
383 {
384 if (_currencyCode != null)
385 {
386 return _currencyCode;
387 }
388 ValueExpression vb = getValueExpression("currencyCode");
389 if (vb != null)
390 {
391 return (String) vb.getValue(getFacesContext().getELContext());
392 }
393 return getDecimalFormatSymbols().getInternationalCurrencySymbol();
394 }
395
396 protected String getLocalCurrencyCode()
397 {
398 if (_currencyCode != null)
399 {
400 return _currencyCode;
401 }
402 ValueExpression vb = getValueExpression("currencyCode");
403 if (vb != null)
404 {
405 return (String) vb.getValue(getFacesContext().getELContext());
406 }
407 return null;
408 }
409
410 public void setCurrencyCode(String currencyCode)
411 {
412 this._currencyCode = currencyCode;
413 }
414
415
416
417
418
419
420
421 @JSFProperty
422 public String getCurrencySymbol()
423 {
424 if (_currencySymbol != null)
425 {
426 return _currencySymbol;
427 }
428 ValueExpression vb = getValueExpression("currencySymbol");
429 if (vb != null)
430 {
431 return (String) vb.getValue(getFacesContext().getELContext());
432 }
433 return getDecimalFormatSymbols().getCurrencySymbol();
434 }
435
436 public String getLocalCurrencySymbol()
437 {
438 if (_currencySymbol != null)
439 {
440 return _currencySymbol;
441 }
442 ValueExpression vb = getValueExpression("currencySymbol");
443 if (vb != null)
444 {
445 return (String) vb.getValue(getFacesContext().getELContext());
446 }
447 return null;
448 }
449
450 public void setCurrencySymbol(String currencySymbol)
451 {
452 this._currencySymbol = currencySymbol;
453 }
454
455
456
457
458
459
460
461 @JSFProperty(defaultValue="true")
462 public abstract boolean isGroupingUsed();
463
464
465
466
467
468
469
470 @JSFProperty(defaultValue="false")
471 public abstract boolean isIntegerOnly();
472
473
474
475
476
477
478 @JSFProperty(deferredValueType="java.lang.Object")
479 public Locale getLocale()
480 {
481 if (_locale != null)
482 {
483 return _locale;
484 }
485 ValueExpression vb = getValueExpression("locale");
486 if (vb != null)
487 {
488 Object _localeValue = vb.getValue(getFacesContext().getELContext());
489 if (_localeValue instanceof String)
490 {
491 _localeValue = org.apache.myfaces.commons.util.TagUtils.getLocale((String)_localeValue);
492 }
493 return (java.util.Locale)_localeValue;
494 }
495 FacesContext context = FacesContext.getCurrentInstance();
496 return context.getViewRoot().getLocale();
497 }
498
499 public void setLocale(Locale locale)
500 {
501 _locale = locale;
502 }
503
504
505
506
507
508 @JSFProperty
509 public abstract Integer getMaxFractionDigits();
510
511
512
513
514
515 @JSFProperty
516 public abstract Integer getMaxIntegerDigits();
517
518
519
520
521
522 @JSFProperty
523 public abstract Integer getMinFractionDigits();
524
525
526
527
528
529 @JSFProperty
530 public abstract Integer getMinIntegerDigits();
531
532
533
534
535
536 @JSFProperty
537 public abstract String getPattern();
538
539 public boolean isTransient()
540 {
541 return _transient;
542 }
543
544 public void setTransient(boolean aTransient)
545 {
546 _transient = aTransient;
547 }
548
549
550
551
552
553
554
555 @JSFProperty(defaultValue="number")
556 public abstract String getType();
557
558 private static boolean checkJavaVersion14()
559 {
560 String version = System.getProperty("java.version");
561 if (version == null)
562 {
563 return false;
564 }
565 byte java14 = 0;
566 for (int idx = version.indexOf('.'), i = 0; idx > 0 || version != null; i++)
567 {
568 if (idx > 0)
569 {
570 byte value = Byte.parseByte(version.substring(0, 1));
571 version = version.substring(idx + 1, version.length());
572 idx = version.indexOf('.');
573 switch (i)
574 {
575 case 0:
576 if (value == 1)
577 {
578 java14 = 1;
579 break;
580 }
581 else if (value > 1)
582 {
583 java14 = 2;
584 }
585 case 1:
586 if (java14 > 0 && value >= 4)
587 {
588 java14 = 2;
589 }
590 ;
591 default:
592 idx = 0;
593 version = null;
594 break;
595 }
596 }
597 else
598 {
599 byte value = Byte.parseByte(version.substring(0, 1));
600 if (java14 > 0 && value >= 4)
601 {
602 java14 = 2;
603 }
604 break;
605 }
606 }
607 return java14 == 2;
608 }
609
610
611 private DecimalFormatSymbols getDecimalFormatSymbols()
612 {
613 return new DecimalFormatSymbols(getLocale());
614 }
615 }