Fix printDecimal regression for decimal values wider than a long - #96
Conversation
|
Thanks for the patch and for the clear write-up - the diagnosis is right, and the operand swap is a pure short-circuit reordering with no semantic change (under However, I think it's an incomplete fix: the That shape isn't hypothetical -
if (scale == 0 || (value.signum() == 0 && scale < 0)) {
return intStr;
}I ran the full all correct, including the zero-with-negative-scale case the branch exists for. On the test: assertEquals("100000000000000000000", XsTypeConverter.printDecimal(new BigDecimal("1E+20")));
assertEquals("-100000000000000000000", XsTypeConverter.printDecimal(new BigDecimal("-1E+20")));
assertEquals("0", XsTypeConverter.printDecimal(new BigDecimal("0E+5")));Minor: with the |
Regression introduced in 5.4.0: printing an xsd:decimal that does not fit into a
long throws IllegalArgumentException("Value can't be converted to long"). 5.3.0
prints the same value correctly.
XsTypeConverter.printDecimal used MathUtil.toLong(value) == 0 to test whether the
value is zero. toLong() throws for anything wider than a long, so the check blew
up on values it was only ever meant to classify. 5.3.0 used BigDecimal.longValue()
here, which truncates silently; MathUtil was added in 5.4.0 and toLong() replaced
longValue() on this line.
Use signum() instead, as in the original Harmony code this method is derived from:
same semantics, cannot throw, O(1), and it keeps MathUtil off the serialization
path entirely.
Seen in the wild as a WSDL2Java code generation failure: xmlbeans could no longer
save a compiled schema type system containing a high-precision decimal.
8dbf28b to
976aec5
Compare
|
The negative-scale case reproduces exactly as described - I added the three cases as a test against the operand-swap version first, and 1E+20 failed with the same "Value can't be converted to long". So the swap only narrowed the window rather than closing it. Switched to signum(). Agreed it is the right level to fix this at: the branch is a zero test, signum() states that directly, and it takes MathUtil off the serialization path. Also dropped the && evaluation-order comment, which no longer applies. Tests now cover positive scale, negative scale and zero with both signs of scale. XsTypeConverterTest (32), TestMathUtil (14), SchemaTypesTests and NumeralsTests all pass. |
|
thanks - merged It looks like we might have a few similar issues. I have a Claude Opus task looking into it. |
Regression introduced in 5.4.0: printing any xsd:decimal that has a non-zero scale and does not fit into a long throws IllegalArgumentException("Value can't be converted to long"). 5.3.0 prints the same value correctly.
XsTypeConverter.printDecimal calls MathUtil.toLong(value) as the left operand of an && whose right operand is the "scale < 0" guard. Java evaluates && left to right, so toLong() runs for every value with a non-zero scale. Its result only matters when the scale is negative - in which case the value is integral and always fits into a long - but by then the exception has already been thrown.
5.3.0 used BigDecimal.longValue() on that line, which truncates silently instead of throwing, so the condition was simply false and printing proceeded. MathUtil was added in 5.4.0 and toLong() replaced longValue() here.
Swapping the operands restores the old behaviour without changing the semantics.
Seen in the wild as a WSDL2Java code generation failure: xmlbeans could no longer save a compiled schema type system containing a high-precision decimal.