Search code examples
jasper-reportsbigdecimal

How to fix java.lang.ClassCastException: java.lang.Double cannot be cast to java.math.BigDecimal error for variable expression?


I have a variable that returns an error when included in the report (preview) but no error when compiling.

The variable is supposed to output 2 digit number on the report based on the amount of a field.

I have a field $F{total balance} of java.lang.String type and a variable $V{Total_balance_num} that converts it to a number. The variable $V{Total_balance_num} has type java.math.BigDecimal:

<variable name="Total balance num" class="java.math.BigDecimal">
    <variableExpression><![CDATA[new Double(Double.parseDouble($F{total_balance}))]]></variableExpression>
</variable>

The main part is to print a different 2 digit number on the report based on the amount of $V{Total_balance_num}. This variable is called $V{groups} of type java.lang.String:

<variable name="groups" class="java.lang.String">
    <variableExpression><![CDATA[$V{Total balance num}.doubleValue() <= new java.math.BigDecimal(250).doubleValue() ? "15":
($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(1000).doubleValue() ? "30":
($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(10000).doubleValue() ? "30" :
  ($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(50000).doubleValue() ? "40":"0"
   )
 ))]]></variableExpression>
</variable>

I have to start from the field total balance that is of type string. When compiling there is no error. But if I create a field to output the variable and then click on preview I get this error:

net.sf.jasperreports.engine.fill.jrexpressionevalexception error evaluating expression
net.sf.jasperreports.engine.JRException: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression: 
Source text: $V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(250).doubleValue() ? "15":($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(1000).doubleValue() ? "30"  ($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(10000).doubleValue() ? "30" :   ($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(50000).doubleValue() ? "40":"0"    )  )  ) 
at com.jaspersoft.studio.editor.preview.view.control.ReportControler.fillReport(ReportControler.java:466) 
..
Caused by: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression : 
    Source text : $V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(250).doubleValue() ? "15":($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(1000).doubleValue() ? "30":   ($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(10000).doubleValue() ? "30"    ($V{Total_balance_num}.doubleValue() <= new java.math.BigDecimal(50000).doubleValue() ? "40":"0")     )      ) 
at net.sf.jasperreports.engine.fill.JREvaluator.evaluateEstimated(JREvaluator.java:327) 
...
Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to java.math.BigDecimal at S01_1556196241282_981700.evaluateEstimated(S01_1556196241282_981700:935) 
at net.sf.jasperreports.engine.fill.JREvaluator.evaluateEstimated(JREvaluator.java:314) ... 9 more

Sample code to reporoduce the issue:

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="S01" pageWidth="595" pageHeight="842" columnWidth="595" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0" uuid="9b44ef22-1966-46f3-acbe-4bfb10170dbc">
    <queryString language="xPath">
        <![CDATA[/letter/fields]]>
    </queryString>
    <field name="total_balance" class="java.lang.String">
        <fieldDescription><![CDATA[total_balance]]></fieldDescription>
    </field>
    <field name="name" class="java.lang.String">
        <fieldDescription><![CDATA[name]]></fieldDescription>
    </field>
    <variable name="Total balance num" class="java.math.BigDecimal">
        <variableExpression><![CDATA[new Double(Double.parseDouble($F{total_balance}))]]></variableExpression>
    </variable>
    <variable name="groups" class="java.lang.String">
        <variableExpression><![CDATA[$V{Total balance num}.doubleValue() <= new java.math.BigDecimal(250).doubleValue() ? "15":
    ($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(1000).doubleValue() ? "30":
    ($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(10000).doubleValue() ? "30" :
      ($V{Total balance num}.doubleValue() <= new java.math.BigDecimal(50000).doubleValue() ? "40":"0"
       )
     )
  )]]></variableExpression>
    </variable>
    <detail>
        <band height="841" splitType="Stretch">
            <textField>
                <reportElement x="62" y="136" width="238" height="15" uuid="85a6b895-3aa5-4607-b2e7-8959da279c1d">
                </reportElement>
                <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
            </textField>
            <staticText>
                <reportElement x="110" y="200" width="314" height="20" uuid="4d2918f5-b6d9-4d81-8be6-e68e1c19bd32"/>
                <textElement textAlignment="Center"/>
                <text><![CDATA[TEST TEXT]]></text>
            </staticText>
        </band>
    </detail>
</jasperReport>

And also xml code to use as an adaptor for the input data (save it as xml -> create new data adapter in Jaspersoft studio -> choose XML document -> select the file and choose use the report Xpath expression when filling the report -> finish)

<letter>
    <fields>
      <name>Jeff</name>
      <total_balance>14576.88</total_balance>
    </fields>
</letter>

Solution

  • What is wrong?

    The expression of groups variable is right. You got exception because another expression is wrong:

    <variable name="Total balance num" class="java.math.BigDecimal">
        <variableExpression><![CDATA[new Double(Double.parseDouble($F{total_balance}))]]></variableExpression>
    </variable>
    

    You got Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to java.math.BigDecimal exception because you are trying to assign double value to object of BigDecimal type.

    The right version is:

    <variable name="Total balance num" class="java.math.BigDecimal">
        <variableExpression><![CDATA[$F{total_balance} == null || $F{total_balance}.length() == 0 ? BigDecimal.ZERO : new BigDecimal($F{total_balance})]]></variableExpression>
    </variable>
    

    You can get NumberFormatException with this expression. To prevent this problem you can add check that $F{total_balance} is numeric, for example with help of org.apache.commons.lang3.StringUtils.isNumeric method. In this case you need to add import to jrxml and add Apache Commons Lang library to classpath.

    The snippet of jrxml:

    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport ... />
        <!-- ... -->
        <import value="org.apache.commons.lang3.StringUtils"/>
        <!-- ... -->
        <variable name="Total balance num" class="java.math.BigDecimal">
            <variableExpression><![CDATA[StringUtils.isNumeric($F{total_balance}) ? new BigDecimal($F{total_balance}) : BigDecimal.ZERO]]></variableExpression>
        </variable>
    

    Optimization 1. Using right type of field

    You can declare field as <field name="total_balance" class="java.math.BigDecimal">. In this case your report will be like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="S01" pageWidth="595" pageHeight="842" columnWidth="595" leftMargin="0" rightMargin="0" topMargin="0" bottomMargin="0" uuid="9b44ef22-1966-46f3-acbe-4bfb10170dbc">
        <queryString language="xPath">
            <![CDATA[/letter/fields]]>
        </queryString>
        <field name="total_balance" class="java.math.BigDecimal">
            <fieldDescription><![CDATA[total_balance]]></fieldDescription>
        </field>
        <field name="name" class="java.lang.String">
            <fieldDescription><![CDATA[name]]></fieldDescription>
        </field>
        <variable name="groups" class="java.lang.String">
            <variableExpression><![CDATA[$F{total_balance}.doubleValue() <= new java.math.BigDecimal(250).doubleValue() ? "15":
        ($F{total_balance}.doubleValue() <= new java.math.BigDecimal(1000).doubleValue() ? "30":
        ($F{total_balance}.doubleValue() <= new java.math.BigDecimal(10000).doubleValue() ? "30" :
          ($F{total_balance}.doubleValue() <= new java.math.BigDecimal(50000).doubleValue() ? "40":"0"
           )
         )
      )]]></variableExpression>
        </variable>
        <detail>
            <band height="30" splitType="Stretch">
                <textField>
                    <reportElement x="23" y="0" width="238" height="15" uuid="85a6b895-3aa5-4607-b2e7-8959da279c1d"/>
                    <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
                </textField>
                <textField>
                    <reportElement x="23" y="15" width="240" height="15" uuid="33a58249-b338-4741-ad5a-4c67846cf006">
                    <textFieldExpression><![CDATA[$V{groups}]]></textFieldExpression>
                </textField>
            </band>
        </detail>
    </jasperReport>
    

    With your test data this version of report works well.

    Optimization 2. Compare BigDecimal objects in right manner

    The right method for comparing BigDecimal object is to use BigDecimal.compareTo(BigDecimal) method.


    More info: