Как исправить java.lang.ClassCastException: java.lang.Double нельзя привести к ошибке java.math.BigDecimal для выражения переменной? - PullRequest
0 голосов
/ 25 апреля 2019

У меня есть переменная, которая возвращает ошибку при включении в отчет (предварительный просмотр), но не при ошибке при компиляции.

Предполагается, что переменная будет выводить в отчете двузначное число в зависимости от количества полей.

У меня есть поле $F{total balance} типа java.lang.String и переменная $V{Total_balance_num}который преобразует его в число.Переменная $V{Total_balance_num} имеет тип java.math.BigDecimal:

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

Основная часть заключается в печати другого двухзначного числа в отчете на основе суммы $V{Total_balance_num}.Эта переменная называется $V{groups} типа 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>

Мне нужно начинать с общего баланса поля, который имеет тип string.При компиляции ошибки нет.Но если я создаю поле для вывода переменной и затем нажимаю на предварительный просмотр, я получаю эту ошибку:

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

Пример кода, чтобы воспроизвести проблему:

<?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>

А также XML-код дляиспользовать в качестве адаптера для входных данных (сохраните его как XML -> создайте новый адаптер данных в студии Jaspersoft -> выберите XML-документ -> выберите файл и выберите использовать выражение Xpath отчета при заполнении отчета -> закончить)

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

1 Ответ

1 голос
/ 26 апреля 2019

Что не так?

Выражение переменной groups является правильным. Вы получили исключение, потому что другое выражение неверно:

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

Вы получили исключение Caused by: java.lang.ClassCastException: java.lang.Double cannot be cast to java.math.BigDecimal, поскольку пытаетесь присвоить двойное значение объекту типа BigDecimal .

Правильная версия:

<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>

Вы можете получить NumberFormatException с этим выражением. Чтобы предотвратить эту проблему, вы можете добавить проверку, что $F{total_balance} является числовым, например, с помощью org.apache.commons.lang3.StringUtils.isNumeric метода. В этом случае вам нужно добавить импорт в jrxml и добавить Apache Commons Lang библиотеку в classpath.

Фрагмент 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>

Оптимизация 1. Использование правильного типа поля

Вы можете объявить поле как <field name="total_balance" class="java.math.BigDecimal">. В этом случае ваш отчет будет выглядеть так:

<?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>

С вашими тестовыми данными эта версия отчета работает хорошо.

Оптимизация 2. Правильно сравнивайте объекты BigDecimal

Правильный метод для сравнения BigDecimal объекта должен использовать BigDecimal.compareTo (BigDecimal) метод.


Дополнительная информация:

...