Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
134 changes: 82 additions & 52 deletions api/src/main/java/jakarta/faces/convert/NumberConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand All @@ -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;
}

Expand Down Expand Up @@ -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());
Expand Down
3 changes: 3 additions & 0 deletions extensions/quarkus/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
<properties>
<quarkus.version>3.2.9.Final</quarkus.version>
<xml-combiner.version>3.0.0</xml-combiner.version>
<java.version>17</java.version>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>

<build>
Expand Down
4 changes: 2 additions & 2 deletions impl/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<url>https://myfaces.apache.org/#/core40</url>

<properties>
<openwebbeans.version>2.0.19</openwebbeans.version>
<openwebbeans.version>2.0.27</openwebbeans.version>
</properties>

<build>
Expand Down Expand Up @@ -579,7 +579,7 @@
<value>COMPAT</value>
</property>
</systemProperties>
<argLine>-Djava.locale.providers=COMPAT</argLine>
<argLine>-Djava.locale.providers=COMPAT --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.security=ALL-UNNAMED</argLine>

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May not be needed anymore. I could remove.

</configuration>

<executions>
Expand Down
5 changes: 1 addition & 4 deletions parent/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -195,13 +195,10 @@
<version>1.9.1</version>
</plugin>

<!-- Version 4.1.0 and higher does not output the version ranges for some packages
when specified by <Import-Package> in API/IMPL plugins
See https://issues.apache.org/jira/browse/FELIX-6566 -->
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>4.0.0</version>
<version>5.1.9</version>
</plugin>

<plugin>
Expand Down