[ 
https://issues.apache.org/jira/browse/CONFIGURATION-766?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=16961984#comment-16961984
 ] 

Alex Herbert commented on CONFIGURATION-766:
--------------------------------------------

So there is an issue that conversion using Double.toString(double) always puts 
a decimal point in the output string. This results in BigDecimal having a 
different scale when constructed using 'BigDecimal.valueOf(double)' rather than 
'new BigDecimal(double)'. This is even documented in the BigDecimal source code 
as a problem when using BigDecimal.valueOf(0.0) that it cannot return 
BigDecimal.ZERO.

So in the following you test the double has a fractional part:
{code:java}
public static BigDecimal toBigDecimal(final Object value) throws 
ConversionException
{
    final Number n = toNumber(value, BigDecimal.class);
    if (n instanceof BigDecimal)
    {
        return (BigDecimal) n;
    }
    // Avoid 'new BigDecimal(double)' for non-integer valued doubles due to 
floating-point
    // conversion errors.
    // The BigDecimal constructor is used when a mathematical integer as the 
scale will
    // be set appropriately without a forced decimal point.
    // Note: Math.rint(double) works for values outside the range of a long but 
will ignore
    // non-finite numbers. These will result in an exception from BigDecimal 
which cannot
    // represent them.
    final double d = n.doubleValue();
    return Math.rint(d) == d ? new BigDecimal(d) : BigDecimal.valueOf(d);
}
{code}
This may not be the best solution but would fix the regression error. It may 
introduce a 'doubles should not be compared using equals' alert from sonar 
which we can ignore; this is exactly what we intend.

Note that Math.rint will return the same value if the number is NaN or infinite 
and usually this should be tested for using Double.isFinite(double). However 
these have no meaning in BigDecimal and result in a NumberFormatException being 
thrown. This can be tested:
{code:java}
@Test(expected = NumberFormatException.class)
public void testToBigDecimalWithInfinity() {
    PropertyConverter.toBigDecimal(Double.POSITIVE_INFINITY);
}
{code}
The alternative is to update the other failing test as you state to test 
against "42.0".

[~ggregory] What do you think?
 # Use the simple fix to always use BigDecimal.valueOf(double) and update the 
other failing test.
 # Use a detection of the type of double to be represented and avoid the 
regression failure.

> BigDecimal(double) should not be used
> -------------------------------------
>
>                 Key: CONFIGURATION-766
>                 URL: https://issues.apache.org/jira/browse/CONFIGURATION-766
>             Project: Commons Configuration
>          Issue Type: Bug
>         Environment: A single occurrence in file PropertyConverter.java, line 
> 393:
> {code:java}
> return new BigDecimal(n.doubleValue());
> {code}
>            Reporter: Haris Adzemovic
>            Priority: Minor
>
> Static analysis with SonarQube shows a violation of ruleĀ 
> [S2111|[https://rules.sonarsource.com/java/type/Bug/RSPEC-2111]] - a 
> dangerous use of the BigDecimal constructor.
> Fixed by using BigDecimal.valueOf(param) instead.



--
This message was sent by Atlassian Jira
(v8.3.4#803005)

Reply via email to