【问题标题】:Clojure: passing a list of records to a Java objectClojure:将记录列表传递给 Java 对象
【发布时间】:2021-10-17 18:53:30
【问题描述】:

我正在试验 Clojure。我能够在 JasperReports 中生成报告,但是 它给出空值。有问题的 Java 对象是JRBeanCollectionDataSource。 我将记录列表传递给它,但不知何故,PDF 只包含空值。

另外,为什么我不能将{} 作为一个空的HashMap 传递?在 Groovy 中,[:] 语法工作正常。

(ns jasper.core
  (:import
   (net.sf.jasperreports.engine JasperCompileManager
                                JasperFillManager
                                JasperExportManager)
   (net.sf.jasperreports.engine.data JRBeanCollectionDataSource)))
(import 'java.util.HashMap)


(defrecord Car [id name price])

(def data [(->Car 1, "Audi", 52642)
           (->Car 2, "Mercedes", 57127)
           (->Car 3, "Skoda", 9000)
           (->Car 4, "Volvo", 29000)
           (->Car 5, "Bentley", 350000)
           (->Car 6, "Citroen", 21000)
           (->Car 7, "Hummer", 41400)
           (->Car 8, "Volkswagen", 21600)])

(def xmlFile "resources/report.xml")
(def jrReport (JasperCompileManager/compileReport xmlFile))

;; (def params {})
(def params (HashMap.))

(def ds (JRBeanCollectionDataSource. data))
(println (.toString ds))

(def jrPrint (JasperFillManager/fillReport jrReport params ds))

(defn -main
  []
  (JasperExportManager/exportReportToPdfFile jrPrint "report.pdf"))

这是对以下 Groovy 解决方案的重写:

@Grab(group='net.sf.jasperreports', module='jasperreports', version='6.17.0')

import net.sf.jasperreports.engine.JasperCompileManager
import net.sf.jasperreports.engine.JasperFillManager
import net.sf.jasperreports.engine.JasperExportManager
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource
import groovy.transform.Immutable

@Immutable
class Car {
    Long id;
    String name;
    int price;
}

def data = [
    new Car(1L, 'Audi', 52642),
    new Car(2L, 'Mercedes', 57127),
    new Car(3L, 'Skoda', 9000),
    new Car(4L, 'Volvo', 29000),
    new Car(5L, 'Bentley', 350000),
    new Car(6L, 'Citroen', 21000),
    new Car(7L, 'Hummer', 41400),
    new Car(8L, 'Volkswagen', 21600),
]

def empty = []

def xmlFile = "report.xml"

def jrReport = JasperCompileManager.compileReport(xmlFile)
def ds = new JRBeanCollectionDataSource(data)

def params = [:]
def jrPrint = JasperFillManager.fillReport(jrReport, params, ds)

JasperExportManager.exportReportToPdfFile(jrPrint, "report.pdf")

编辑对于一个完整的工作示例,将以下文件放置在 Groovy 的当前工作目录和 Clojure 的资源目录中。

<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
        "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<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"
              whenNoDataType="NoDataSection"
              name="report" topMargin="20" bottomMargin="20">

    <field name="id" class="java.lang.Long"/>
    <field name="name"/>
    <field name="price" class="java.lang.Integer"/>

    <detail>
        <band height="15">

            <textField>
                <reportElement x="0" y="0" width="50" height="15"/>

                <textElement textAlignment="Right" verticalAlignment="Middle"/>

                <textFieldExpression class="java.lang.Long">
                    <![CDATA[$F{id}]]>
                </textFieldExpression>
            </textField>

            <textField>
                <reportElement x="150" y="0" width="100" height="15" />

                <textElement textAlignment="Left" verticalAlignment="Middle"/>

                <textFieldExpression class="java.lang.String">
                    <![CDATA[$F{name}]]>
                </textFieldExpression>
            </textField>

            <textField>
                <reportElement x="200" y="0" width="100" height="15" />
                <textElement textAlignment="Right" verticalAlignment="Middle"/>

                <textFieldExpression class="java.lang.Integer">
                    <![CDATA[$F{price}]]>
                </textFieldExpression>
            </textField>

        </band>
    </detail>

    <noData>
        <band height="15">
            <staticText>
                <reportElement x="0" y="0" width="200" height="15"/>
                <box>
                    <bottomPen lineWidth="1.0" lineColor="#CCCCCC"/>
                </box>
                <textElement />
                <text><![CDATA[The report has no data]]></text>
            </staticText>
        </band>
    </noData>

</jasperReport>

【问题讨论】:

  • 可以肯定地说,没有完全可重现的示例,但{} 创建了一个不可变的Map 实例,它不是HashMap 的实例。此外,[] 不会创建数组 - 它会创建一个不可变向量,它是 List 的一个实例。最后,defrecord 创造的东西与@Immutable class 给你的东西不同,可能在某种程度上在这里很重要。
  • 对于一个完整的工作示例,需要使用一个 XML 文件;我已经添加了这个文件。如果它是由类型不匹配引起的,我希望该示例会因异常而失败。
  • 对我来说例外是:Execution error (UnsupportedOperationException) at net.sf.jasperreports.engine.fill.JRFillDataset/setDatasourceParameterValue (JRFillDataset.java:1291)
  • @cfrick 当我将参数定义为(def params {}) 时,我得到了这个确切的例外。如果我使用(def params (HashMap.)),编译工作正常。那么问题出在(def ds (JRBeanCollectionDataSource. data));数据由于某种原因未正确处理,我在最终报告中得到空值。
  • 正如我在文档中看到的 JRBeanCollectionDataSource 期望收集 JavaBeans。 @Immutable 创建一个 JavaBean(关键是 getter,参见 here),而 Clojure 记录不是 JB。 clj-bean 在这里可能会有所帮助。

标签: groovy clojure jasper-reports


【解决方案1】:

借助 cmets 的提示,我能够解决问题。问题是 Clojure 记录没有实现 JavaBeans 规范,而 JRBeanCollectionDataSource 需要这样的 bean。

使用clj-bean 库,我能够让它工作。

(defbean Car
 [[Long id]
  [String name]
  [Integer price]])

(def data [(Car. 1 "Audi" 52642),
           (Car. 2 "Mercedes" 57127),
           (Car. 3 "Skoda" 9000),
           (Car. 4 "Volvo" 29000),
           (Car. 5 "Bentley" 350000),
           (Car. 6 "Citroen" 21000),
           (Car. 7 "Hummer" 41400),
           (Car. 8 "Volkswagen" 21600)])

现在报告包含数据。

【讨论】:

    猜你喜欢
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-19
    • 2014-10-07
    • 2018-03-05
    相关资源
    最近更新 更多