Skip to content

Commit

Permalink
Fixed: Support non-breaking spaces in numeric strings (OFBIZ-13168) (#…
Browse files Browse the repository at this point in the history
…847)

In forms, numeric fields are represented by an input with type "text", which allows user to enter/paste all characters, including non-breaking spaces ('\u00A0', '\u202F', '\u2007'), like "29 000" (the space is \u202F). More specifically, a user can copy/paste a string from an external tool which uses non-breaking spaces as a thousands separator, and expect that a visually correct string will be correctly interpreted by OFBiz.

OFBiz uses java.text.NumberFormat::parse method, which does not support non-breaking spaces : characters after this kind of spaces are simply ignored, and "29 000" becomes "29".

This PR only illustrates the problem and a way of fixing it, I'm not sure that this would be a good solution (maybe handle submitted strings elsewhere ? maybe more upstream ?).

Thanks: Nereide team
  • Loading branch information
JacquesLeRoux authored Nov 6, 2024
1 parent 74ca62b commit f41e0a3
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -330,6 +331,15 @@ public static Object simpleTypeOrObjectConvert(Object obj, String type, String f
}

if (converter != null) {
// numeric types : replace non-breaking spaces (which break parsing) by normal spaces
List<?> numericClasses = UtilMisc.toList(BigDecimal.class, Double.class, Float.class);
if (obj instanceof String && numericClasses.contains(targetClass)) {
final String[] tmp = {String.valueOf(obj)};
List<Character> nonBreakingWhitespaces = UtilMisc.toList('\u00A0', '\u202F', '\u2007');
nonBreakingWhitespaces.forEach(character -> tmp[0] = tmp[0].replace(character, ' '));
obj = tmp[0];
}

if (converter instanceof LocalizedConverter) {
LocalizedConverter<Object, Object> localizedConverter = UtilGenerics.cast(converter);
if (timeZone == null) {
Expand All @@ -345,6 +355,7 @@ public static Object simpleTypeOrObjectConvert(Object obj, String type, String f
throw new GeneralException(e.getMessage(), e);
}
}

try {
return converter.convert(obj);
} catch (ConversionException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public class ObjectTypeTests {
// These numbers are all based on 1 / 128, which is a binary decimal
// that can be represented by both float and double
private final BigDecimal dcml = new BigDecimal("781.25");
private final BigDecimal largeBigDecimal = new BigDecimal("29000");
private final Double dbl = Double.valueOf("7.8125E2");
private final Float flt = Float.valueOf("7.8125E2");
private final Long lng = Long.valueOf("781");
Expand Down Expand Up @@ -385,6 +386,12 @@ public void testString() throws GeneralException, Exception {
new String[] {"TimeDuration", "org.apache.ofbiz.base.util.TimeDuration"}, duration);
simpleTypeOrObjectConvertTestError("String->error-TimeDuration", "o",
new String[] {"TimeDuration", "org.apache.ofbiz.base.util.TimeDuration"});

// usual pattern assumes that the String->BigDecimal conversion will break with bad timezone/locale
// which is not the case for this particular test
assertEquals("String->BigDecimal supports NBSP",
simpleTypeOrObjectConvert("29 000", "BigDecimal", null, LOCALE_DATA.goodTimeZone,
LOCALE_DATA.goodLocale, false), largeBigDecimal);
}

@Test
Expand Down

0 comments on commit f41e0a3

Please sign in to comment.