diff --git a/api/src/main/java/jakarta/faces/convert/NumberConverter.java b/api/src/main/java/jakarta/faces/convert/NumberConverter.java index c1ed215037..b45a9fdcfa 100755 --- a/api/src/main/java/jakarta/faces/convert/NumberConverter.java +++ b/api/src/main/java/jakarta/faces/convert/NumberConverter.java @@ -27,6 +27,7 @@ import java.text.ParsePosition; import java.util.Currency; import java.util.Locale; +import java.util.regex.Pattern; import jakarta.el.ValueExpression; import jakarta.faces.component.PartialStateHolder; @@ -61,6 +62,11 @@ public class NumberConverter implements Converter, PartialStateHolder public static final String PATTERN_ID = "jakarta.faces.converter.NumberConverter.PATTERN"; public static final String PERCENT_ID = "jakarta.faces.converter.NumberConverter.PERCENT"; + private static final Pattern FIXED_WIDTH_WHITESPACE = + Pattern.compile("[\u00a0\u1680\u2000-\u200a\u202f\u205f\u3000]"); + private static final Pattern ZERO_WIDTH_WHITESPACE = + Pattern.compile("[\u200b-\u200d\u2060\ufeff]"); + private String _currencyCode; private String _currencySymbol; private Locale _locale; @@ -89,17 +95,11 @@ public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, St Assert.notNull(facesContext, "facesContext"); Assert.notNull(uiComponent, "uiComponent"); - if (value == null) - { - return null; - } - - value = value.trim(); - if (value.length() < 1) + if (value == null || value.isBlank()) { return null; } - + NumberFormat format = getNumberFormat(facesContext); format.setParseIntegerOnly(_integerOnly); @@ -122,65 +122,89 @@ public Object getAsObject(FacesContext facesContext, UIComponent uiComponent, St } } - DecimalFormatSymbols dfs = df.getDecimalFormatSymbols(); - boolean changed = false; - if(dfs.getGroupingSeparator() == '\u00a0') - { - dfs.setGroupingSeparator(' '); - df.setDecimalFormatSymbols(dfs); - value = value.replace('\u00a0', ' '); - changed = true; - } - formatCurrency(format); try { + DecimalFormatSymbols symbols = df.getDecimalFormatSymbols(); + char origGroupingSep = symbols.getGroupingSeparator(); + String origPrefix = df.getPositivePrefix(); + String origSuffix = df.getPositiveSuffix(); + String origNegPrefix = df.getNegativePrefix(); + String origNegSuffix = df.getNegativeSuffix(); + + boolean hasFixedWidthWhitespace = + FIXED_WIDTH_WHITESPACE.matcher(String.valueOf(origGroupingSep)).matches() + || FIXED_WIDTH_WHITESPACE.matcher(origPrefix).find() + || FIXED_WIDTH_WHITESPACE.matcher(origSuffix).find() + || FIXED_WIDTH_WHITESPACE.matcher(origNegPrefix).find() + || FIXED_WIDTH_WHITESPACE.matcher(origNegSuffix).find(); + + if (hasFixedWidthWhitespace) + { + String normalizedValue = normalizeWhitespace(value); + + if (FIXED_WIDTH_WHITESPACE.matcher(String.valueOf(origGroupingSep)).matches()) + { + symbols.setGroupingSeparator(' '); + symbols.setMonetaryGroupingSeparator(' '); + } + + df.setDecimalFormatSymbols(symbols); + df.setPositivePrefix(normalizeWhitespace(origPrefix)); + df.setPositiveSuffix(normalizeWhitespace(origSuffix)); + df.setNegativePrefix(normalizeWhitespace(origNegPrefix)); + df.setNegativeSuffix(normalizeWhitespace(origNegSuffix)); + + try + { + return parse(normalizedValue, format, destType); + } + catch (ParseException pe) + { + symbols.setGroupingSeparator(origGroupingSep); + symbols.setMonetaryGroupingSeparator(origGroupingSep); + df.setDecimalFormatSymbols(symbols); + df.setPositivePrefix(origPrefix); + df.setPositiveSuffix(origSuffix); + df.setNegativePrefix(origNegPrefix); + df.setNegativeSuffix(origNegSuffix); + } + } + return parse(value, format, destType); } catch (ParseException e) { - if(changed) + if (getPattern() != null) { - dfs.setGroupingSeparator('\u00a0'); - df.setDecimalFormatSymbols(dfs); + throw new ConverterException(MessageUtils.getErrorMessage(facesContext, + PATTERN_ID, + new Object[]{value, "$###,###", MessageUtils.getLabel(facesContext, uiComponent)})); } - try + else if (getType().equals("number")) { - return parse(value, format, destType); + throw new ConverterException(MessageUtils.getErrorMessage(facesContext, + NUMBER_ID, + new Object[]{value, format.format(21), + MessageUtils.getLabel(facesContext, uiComponent)})); } - catch (ParseException pe) + else if (getType().equals("currency")) { - if (getPattern() != null) - { - throw new ConverterException(MessageUtils.getErrorMessage(facesContext, - PATTERN_ID, - new Object[]{value, "$###,###", MessageUtils.getLabel(facesContext, uiComponent)})); - } - else if (getType().equals("number")) - { - throw new ConverterException(MessageUtils.getErrorMessage(facesContext, - NUMBER_ID, - new Object[]{value, format.format(21), - MessageUtils.getLabel(facesContext, uiComponent)})); - } - else if (getType().equals("currency")) - { - throw new ConverterException(MessageUtils.getErrorMessage(facesContext, - CURRENCY_ID, - new Object[]{value, format.format(42.25), - MessageUtils.getLabel(facesContext, uiComponent)})); - } - else if (getType().equals("percent")) - { - throw new ConverterException(MessageUtils.getErrorMessage(facesContext, - PERCENT_ID, - new Object[]{value, format.format(.90), - MessageUtils.getLabel(facesContext, uiComponent)})); - } + throw new ConverterException(MessageUtils.getErrorMessage(facesContext, + CURRENCY_ID, + new Object[]{value, format.format(42.25), + MessageUtils.getLabel(facesContext, uiComponent)})); + } + else if (getType().equals("percent")) + { + throw new ConverterException(MessageUtils.getErrorMessage(facesContext, + PERCENT_ID, + new Object[]{value, format.format(.90), + MessageUtils.getLabel(facesContext, uiComponent)})); } } - + return null; } @@ -587,6 +611,12 @@ public void setType(String type) clearInitialState(); } + private static String normalizeWhitespace(String text) + { + String normalized = FIXED_WIDTH_WHITESPACE.matcher(text).replaceAll(" "); + return ZERO_WIDTH_WHITESPACE.matcher(normalized).replaceAll(""); + } + private DecimalFormatSymbols getDecimalFormatSymbols() { return new DecimalFormatSymbols(getLocale()); diff --git a/extensions/quarkus/pom.xml b/extensions/quarkus/pom.xml index dc5e55437f..f62f0992e4 100644 --- a/extensions/quarkus/pom.xml +++ b/extensions/quarkus/pom.xml @@ -43,6 +43,9 @@ 3.2.9.Final 3.0.0 + 17 + 17 + 17 diff --git a/impl/pom.xml b/impl/pom.xml index 945bcc51f8..1a3b631bbf 100644 --- a/impl/pom.xml +++ b/impl/pom.xml @@ -35,7 +35,7 @@ https://myfaces.apache.org/#/core40 - 2.0.19 + 2.0.27 @@ -579,7 +579,7 @@ COMPAT - -Djava.locale.providers=COMPAT + -Djava.locale.providers=COMPAT --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED diff --git a/parent/pom.xml b/parent/pom.xml index c20fb3d4cc..b3906be95c 100644 --- a/parent/pom.xml +++ b/parent/pom.xml @@ -195,13 +195,10 @@ 1.9.1 - org.apache.felix maven-bundle-plugin - 4.0.0 + 5.1.9