使用DTO与JRXML创建Jasper Report交叉表遇类型转换错误求助
问题解决:Jasper交叉表动态列实现与ClassCastException修复
错误原因分析
你遇到的ClassCastException: java.util.ArrayList cannot be cast to java.lang.Comparable是因为:
- 交叉表的分组桶(bucket)要求元素必须实现
Comparable接口,用于分组排序,但你在列组的bucket表达式中直接使用了$F{chargeCode}(List<String>类型),ArrayList并未实现Comparable,导致排序时类型转换失败。 - 同时,当前的
MyDTO结构(一个job对应多个chargeCode和金额的列表)不符合交叉表的数据源要求:交叉表需要扁平化的原子数据(每行对应一个job、一个chargeCode、一个金额),而非嵌套列表结构。
解决方案
1. 调整数据源DTO结构
将嵌套的MyDTO转换为扁平化的DTO,每个实例对应一条job+chargeCode+金额的记录:
class FlatChargeDTO { private String jobNo; private String chargeCode; private BigDecimal chargeAmount; // 构造方法、getter/setter省略 }
转换示例(将原MyDTO列表转成FlatChargeDTO列表):
List<FlatChargeDTO> flatData = new ArrayList<>(); for (MyDTO dto : originalMyDTOList) { String jobNo = dto.getJobNo(); List<String> codes = dto.getChargeCode(); List<BigDecimal> amounts = dto.getChargeCodeTotal(); for (int i = 0; i < codes.size(); i++) { flatData.add(new FlatChargeDTO(jobNo, codes.get(i), amounts.get(i))); } }
2. 修改JRXML交叉表配置
调整字段、分组桶和度量的配置,适配扁平化数据源:
<?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="vendorBillingCompletedJobReport" leftMargin="5" rightMargin="5"> <!-- 定义扁平化数据源的字段 --> <field name="jobNo" class="java.lang.String"/> <field name="chargeCode" class="java.lang.String"/> <field name="chargeAmount" class="java.math.BigDecimal"/> <summary> <band height="60"> <crosstab> <reportElement width="782" y="0" x="0" height="60"/> <!-- 行组:按jobNo分组 --> <rowGroup name="jobNoGroup" width="100" totalPosition="End"> <bucket> <bucketExpression class="java.lang.String"> <![CDATA[$F{jobNo}]]> </bucketExpression> </bucket> <crosstabRowHeader> <cellContents> <box> <pen lineColor="black" lineWidth="1"/> </box> <textField> <reportElement width="100" y="0" x="0" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression><![CDATA[$V{jobNoGroup}]]></textFieldExpression> </textField> </cellContents> </crosstabRowHeader> <crosstabTotalRowHeader> <cellContents> <box> <pen lineColor="black" lineWidth="1"/> </box> <staticText> <reportElement x="0" y="0" width="100" height="20"/> <textElement verticalAlignment="Middle" textAlignment="Center"/> <text>TOTAL</text> </staticText> </cellContents> </crosstabTotalRowHeader> </rowGroup> <!-- 列组:按chargeCode动态生成列 --> <columnGroup name="chargeCodeGroup" height="20" totalPosition="End"> <bucket> <bucketExpression class="java.lang.String"> <![CDATA[$F{chargeCode}]]> </bucketExpression> </bucket> <crosstabColumnHeader> <cellContents> <box> <pen lineColor="black" lineWidth="1"/> </box> <textField isStretchWithOverflow="true"> <reportElement width="120" y="0" x="0" height="20"/> <textElement verticalAlignment="Middle" textAlignment="Center"/> <textFieldExpression><![CDATA[$V{chargeCodeGroup}]]></textFieldExpression> </textField> </cellContents> </crosstabColumnHeader> <crosstabTotalColumnHeader> <cellContents> <box> <pen lineColor="black" lineWidth="1"/> </box> <staticText> <reportElement width="120" y="0" x="0" height="20"/> <textElement verticalAlignment="Middle" textAlignment="Center"/> <text>TOTAL</text> </staticText> </cellContents> </crosstabTotalColumnHeader> </columnGroup> <!-- 度量:计算金额总和 --> <measure name="totalAmount" class="java.math.BigDecimal" calculation="Sum"> <measureExpression><![CDATA[$F{chargeAmount}]]></measureExpression> </measure> <!-- 交叉表单元格:显示金额 --> <crosstabCell height="20" width="120"> <cellContents backcolor="#FFFFFF"> <box> <pen lineColor="black" lineWidth="1"/> </box> <textField> <reportElement x="5" y="0" width="115" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.math.BigDecimal"><![CDATA[$V{totalAmount}]]></textFieldExpression> <pattern>#,##0.00</pattern> </textField> </cellContents> </crosstabCell> <!-- 总计单元格样式 --> <crosstabCell height="20" width="120" rowTotal="true"> <cellContents backcolor="#F0F0F0"> <box> <pen lineColor="black" lineWidth="1"/> </box> <textField> <reportElement x="5" y="0" width="115" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.math.BigDecimal"><![CDATA[$V{totalAmount}]]></textFieldExpression> <pattern>#,##0.00</pattern> </textField> </cellContents> </crosstabCell> <crosstabCell height="20" width="100" columnTotal="true"> <cellContents backcolor="#F0F0F0"> <box> <pen lineColor="black" lineWidth="1"/> </box> <textField> <reportElement x="5" y="0" width="95" height="20"/> <textElement textAlignment="Right" verticalAlignment="Middle"/> <textFieldExpression class="java.math.BigDecimal"><![CDATA[$V{totalAmount}]]></textFieldExpression> <pattern>#,##0.00</pattern> </textField> </cellContents> </crosstabCell> </crosstab> </band> </summary> </jasperReport>
关键调整说明
- 将行组和列组的bucket表达式改为
String类型(jobNo和chargeCode),它们天然实现Comparable,解决类型转换错误。 - 使用扁平化的
FlatChargeDTO作为数据源,让交叉表能正确按job和chargeCode分组,并聚合计算金额。 - 增加了金额格式化的
pattern,优化显示效果,同时配置了总计单元格的背景色区分。
内容的提问来源于stack exchange,提问作者ATWonder
相关产品推荐
相关产品推荐

