Jasperreports 不能在嵌套列表父级上使用排序字段

Jasperreports can't use sort fields on nested list parent

我有以下 JSON:

{
    "data": [
  {
    "name": "apple",
    "sorts": [
      { "name": "green", "number": "6", "comment": "green apples are nice", "suppliers": [{"name": "Supplier1"},{"name": "Supplier2"}] },
      { "name": "yellow", "number": "1", "suppliers": [] },
      { "name": "red", "number": "2", "suppliers": [{"name": "supplier1"}] }
    ]
  },
  {
    "name": "banana",
    "sorts": [
    ]
  },
  {
    "name": "pear",
    "sorts": [
      { "name": "green", "number": "6", "comment": "green pears are sour", "suppliers": [{"name": "supplier4"}] },
      { "name": "purple", "number": "0", "comment": "so far we haven't seen purple pears", "suppliers": [{"name": "supplier1"},{"name": "supplier4"}] }
    ]
  }
]
}

这是我的 JRXML:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.13.0.final using JasperReports Library version 6.13.0-46ada4d1be8f3c5985fd0b6146f3ed44caed6f05  -->
<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="Blank_A4" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="af456afc-4615-4564-8841-81929ce2447f">
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="Adapter"/>
    <style name="listRow">
        <conditionalStyle>
            <conditionExpression><![CDATA[$V{REPORT_COUNT} % 2 == 0]]></conditionExpression>
            <style mode="Opaque" backcolor="#FFFF00"/>
        </conditionalStyle>
    </style>
    <subDataset name="DatasetFruitsSortAll" uuid="5961129e-70f0-4d98-8d4e-524f2bbb28f9">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="Adapter"/>
        <queryString language="JSONQL">
            <![CDATA[data.sorts]]>
        </queryString>
        <field name="fruitName" class="java.lang.String">
            <property name="net.sf.jasperreports.jsonql.field.expression" value="^^.name"/>
            <fieldDescription><![CDATA[fruitName]]></fieldDescription>
        </field>
        <field name="name" class="java.lang.String">
            <property name="net.sf.jasperreports.json.field.expression" value="name"/>
            <fieldDescription><![CDATA[name]]></fieldDescription>
        </field>
        <field name="number" class="java.lang.Integer">
            <property name="net.sf.jasperreports.json.field.expression" value="number"/>
            <fieldDescription><![CDATA[number]]></fieldDescription>
        </field>
        <field name="comment" class="java.lang.String">
            <property name="net.sf.jasperreports.json.field.expression" value="comment"/>
            <fieldDescription><![CDATA[comment]]></fieldDescription>
        </field>
    </subDataset>
    <subDataset name="DatasetSuppliers" uuid="4af8f526-8e16-4e58-8c2e-0a7dcf7998ba">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="Adapter"/>
        <queryString language="JSON">
            <![CDATA[data.sorts.suppliers]]>
        </queryString>
        <field name="name" class="java.lang.String">
            <property name="net.sf.jasperreports.json.field.expression" value="name"/>
            <fieldDescription><![CDATA[name]]></fieldDescription>
        </field>
    </subDataset>
    <queryString language="JSONQL">
        <![CDATA[]]>
    </queryString>
    <detail>
        <band height="125" splitType="Stretch">
            <componentElement>
                <reportElement x="0" y="0" width="595" height="30" isRemoveLineWhenBlank="true" uuid="c4206620-ee0d-4e50-9336-1e1be2723c6f"/>
                <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
                    <datasetRun subDataset="DatasetFruitsSortAll" uuid="b9df9d8f-7ada-47eb-84e6-4870547e7bd9">
                        <dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("data.sorts.*")]]></dataSourceExpression>
                    </datasetRun>
                    <jr:listContents height="30" width="595">
                        <frame>
                            <reportElement style="listRow" x="0" y="0" width="590" height="30" uuid="3b3fba3d-e4c5-499c-a752-b6caa847a448"/>
                            <textField>
                                <reportElement x="0" y="0" width="100" height="30" uuid="bd3ac2b2-1803-4e0f-afa8-a0bdcc54e6fb"/>
                                <textFieldExpression><![CDATA[$F{fruitName}]]></textFieldExpression>
                            </textField>
                            <textField>
                                <reportElement x="130" y="0" width="100" height="30" uuid="be871dcb-61a0-49bd-b565-af8aa27bc7f4"/>
                                <textFieldExpression><![CDATA[$F{number}]]></textFieldExpression>
                            </textField>
                            <textField isBlankWhenNull="true">
                                <reportElement x="230" y="0" width="190" height="30" uuid="bea6dae7-bca2-4c0a-a0b5-443a859c20ac"/>
                                <textFieldExpression><![CDATA[$F{comment}]]></textFieldExpression>
                            </textField>
                            <componentElement>
                                <reportElement x="490" y="0" width="100" height="30" uuid="af5e5156-cdae-45eb-b423-dbdbebad8879"/>
                                <jr:list>
                                    <datasetRun subDataset="DatasetSuppliers" uuid="d3430f43-a76c-47d8-b592-c6dae7fbf083">
                                        <dataSourceExpression><![CDATA[((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("suppliers")]]></dataSourceExpression>
                                    </datasetRun>
                                    <jr:listContents height="30" width="100">
                                        <textField>
                                            <reportElement x="0" y="0" width="100" height="30" uuid="8f7ab53c-b3c2-4d4d-8266-3f04efed81d7"/>
                                            <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
                                        </textField>
                                    </jr:listContents>
                                </jr:list>
                            </componentElement>
                        </frame>
                    </jr:listContents>
                </jr:list>
            </componentElement>
        </band>
    </detail>
</jasperReport>

结果如下:

现在我想根据水果名称对列表进行排序。我将 <sortField name="fruitName"/> 添加到子数据集。不幸的是我收到以下错误:

net.sf.jasperreports.engine.JRException: net.sf.jasperreports.engine.JRRuntimeException: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: ((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("suppliers")
    at com.jaspersoft.studio.editor.preview.view.control.ReportController.fillReport(ReportController.java:551)
    at com.jaspersoft.studio.editor.preview.view.control.ReportController.access(ReportController.java:526)
    at com.jaspersoft.studio.editor.preview.view.control.ReportController.run(ReportController.java:444)
    at org.eclipse.core.internal.jobs.Worker.run(Worker.java:63)
Caused by: net.sf.jasperreports.engine.JRRuntimeException: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: ((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("suppliers")
    at net.sf.jasperreports.components.list.VerticalFillList.prepare(VerticalFillList.java:150)
    at net.sf.jasperreports.engine.fill.JRFillComponentElement.prepare(JRFillComponentElement.java:152)
    at net.sf.jasperreports.engine.fill.JRFillElementContainer.prepareElements(JRFillElementContainer.java:542)
    at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:453)
    at net.sf.jasperreports.engine.fill.JRFillBand.fill(JRFillBand.java:428)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillColumnBand(JRVerticalFiller.java:2602)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillDetail(JRVerticalFiller.java:825)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:266)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:110)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:621)
    at net.sf.jasperreports.engine.fill.BaseFillHandle$ReportFill.run(BaseFillHandle.java:135)
    at java.lang.Thread.run(Thread.java:748)
Caused by: net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: ((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("suppliers")
    at net.sf.jasperreports.engine.fill.JREvaluator.handleEvaluationException(JREvaluator.java:294)
    at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:328)
    at net.sf.jasperreports.engine.fill.JRCalculator.evaluate(JRCalculator.java:673)
    at net.sf.jasperreports.engine.fill.JRCalculator.evaluate(JRCalculator.java:641)
    at net.sf.jasperreports.engine.fill.JRFillDataset.evaluateExpression(JRFillDataset.java:2028)
    at net.sf.jasperreports.components.list.FillDatasetRun.evaluateDatasetExpression(FillDatasetRun.java:237)
    at net.sf.jasperreports.components.list.BaseFillList.evaluate(BaseFillList.java:91)
    at net.sf.jasperreports.components.list.FillDatasetRun.evaluate(FillDatasetRun.java:131)
    at net.sf.jasperreports.components.list.BaseFillList.evaluate(BaseFillList.java:115)
    at net.sf.jasperreports.engine.fill.JRFillComponentElement.evaluate(JRFillComponentElement.java:110)
    at net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:383)
    at net.sf.jasperreports.engine.fill.JRFillFrame.evaluate(JRFillFrame.java:172)
    at net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:383)
    at net.sf.jasperreports.components.list.FillListContents.evaluateContents(FillListContents.java:85)
    at net.sf.jasperreports.components.list.VerticalFillList.prepare(VerticalFillList.java:110)
    ... 11 more
Caused by: java.lang.ClassCastException: net.sf.jasperreports.engine.fill.SortedDataSource cannot be cast to net.sf.jasperreports.engine.data.JsonQLDataSource
    at Blank_A4_DatasetFruitsSortAll_1598446444233_560474.evaluate(Blank_A4_DatasetFruitsSortAll_1598446444233_560474:86)
    at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:313)
    ... 24 more

我做错了什么?

定义排序字段将导致内存数据源用于报表,这意味着 $P{REPORT_DATA_SOURCE} 不再是原始 JsonQLDataSource 对象。

因此,数据源表达式 ((net.sf.jasperreports.engine.data.JsonQLDataSource)$P{REPORT_DATA_SOURCE}).subDataSource("suppliers") 失败。

解决方案是使用 SUB_DATA_SOURCE 内置函数而不是 JsonQLDataSource.subDataSource。表达式将如下所示:

<dataSourceExpression><![CDATA[SUB_DATA_SOURCE("suppliers")]]></dataSourceExpression>

您需要 JasperReports 6.13.0 或更新版本,以及您的应用程序中的 jasperreports-functions jar(您可以通过 Maven 获取)。