Clojure向JRBeanCollectionDataSource传记录列表空值及HashMap传参问题
问题解决方案
问题1:PDF所有字段值为null
原因
JRBeanCollectionDataSource 基于 JavaBean 规范读取属性,要求对象提供 getXxx 格式的 getter 方法。Clojure 的 defrecord 生成的属性访问方法为直接的字段名方法(如 .id、.name),不符合 getId、getName 的命名规则,导致 JasperReports 无法读取到对应值。
解决方案
替换使用 JRMapCollectionDataSource 替代 JRBeanCollectionDataSource。Clojure 的 record 天生实现了 Map 接口,该数据源会直接按照字段名作为 key 读取值,完美匹配你报告模板中的字段定义。
修改点:
- 导入对应类:在 import 块中添加
net.sf.jasperreports.engine.data.JRMapCollectionDataSource - 初始化数据源时替换类:
(def ds (JRMapCollectionDataSource. data))
问题2:无法直接传入{}作为空参数Map
原因
Clojure 的字面量 {} 是不可变的 Map 实现,而 JasperReports 内部会对传入的参数 Map 进行写入操作,直接传入不可变 Map 会抛出 UnsupportedOperationException 异常。Groovy 的 [:] 默认生成可变 Map,所以可以直接使用。
解决方案
如果是空参数,你现有代码中的 (HashMap.) 写法已经是正确的。如果需要传入自定义参数,将 Clojure 不可变 Map 转为可变 HashMap 即可:
;; 带参数示例 (def params (into (HashMap.) {:report-title "车辆价格报表"}))
修改后可正常运行的完整Clojure代码
(ns jasper.core (:import (net.sf.jasperreports.engine JasperCompileManager JasperFillManager JasperExportManager) (net.sf.jasperreports.engine.data JRMapCollectionDataSource)) (: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") (defn -main [] (let [jrReport (JasperCompileManager/compileReport xmlFile) params (HashMap.) ds (JRMapCollectionDataSource. data) jrPrint (JasperFillManager/fillReport jrReport params ds)] (JasperExportManager/exportReportToPdfFile jrPrint "report.pdf")))
注:将报表相关逻辑移到-main函数内,避免命名空间加载时提前执行IO操作导致的路径异常
内容的提问来源于stack exchange,提问作者Jan Bodnar
相关产品推荐
相关产品推荐

