はじめに
2021nに「JaperReports」を利用してPDF帳票を出力するアプリケーションを作成したのですが、
アプリの仕様変更に伴い、3年ぶりに帳票のレイアウトファイル(.jrxml)に手を加えることとなりました。
帳票から一部の項目消す程度の簡単な作業だったので、再コンパイルしてデプロイし直せば終わりと、余裕をこいて作業をしていたら、
まさかまさかのエラーにぶち当たり、解決まで時間がかかってしまいました汗。
どこかで誰かが同じエラーにハマるかもしれないと思い、私のはまったエラーと解決方法を載せておきます。
※JasperReportsとは、Java で動作するオープンソースの帳票出力ライブラリです。xml定義ファイルから帳票を生成することができます。
詳しくはJaspersoft Communityを参照ください。
対象読者
- 新しいJasperReportsを利用してエラーにハマった
- 随分と触っていないJasperReportsを利用したアプリケーションに心当たりがある
- 当時の開発環境がなくなっている
前提条件
エラーが発生した開発環境は以下です。
- Windows 10
- Eclipse 2020-12
- JasperReportsAPI 6.2.2
- iText 2.1.7
- Jaspersoft Studio 6.16.0(Eclipseプラグインを利用)
3年前に利用したJasperReportsに関する情報は以下です。
- Eclipse 2018-09 かそれ以前
- Jaspersoft Studio 6.5.1
アプリケーション情報
レイアウトファイルと、アプリケーションは以下のように配置して利用していました。
レイアウトを作成するプロジェクト、帳票を出力するプロジェクトの2つのプロジェクトを作り、
帳票を出力するプロジェクトのアプリケーション(以下のtestprogram.jar)は、外に配置されたレイアウトファイル(以下のtest.jasper,test.jrxml)を利用して帳票を出力します。
以下、帳票を出力するアプリケーションを帳票出力アプリと表現します。
applicationフォルダ
├──lib
├──log
├──resources
│ ├──test.jasper
│ └──test.jrxml
└──testprogram.jar
発生した現象
エラーに対して以下の順々に対応し、そのときに発生した現象を記載します。
試行錯誤の様子も記載しているので、結果だけ見たい方は、まとめに進んでください。
①Eclipseプラグインがインストールできない
②最新のEclipseプラグインを利用して作成したレイアウトファイルを使うと実行時エラーになる
③Eclipseプラグインで互換性機能を利用してもエラーになる
①Eclipseプラグインがインストールできない
開発当初と同じ環境を作ろうと、いざEclipseプラグインをインストールしようとしたら、まずつまずきました。やる気なくしますね。
原因
現在、Jaspersoft StudioをEclipseプラグインで利用できるのは、Eclipse2018-12以降であるため、
当時利用していたEclipseのバージョン(2018-09)では、Jaspersoft Studioを利用できなくなっていた。
実施した対策
対応しているEclipseに変える。(Eclipse2020-12に変更しました。)
対象バージョン情報は、Eclipseマーケットプレイスで確認できます。
https://marketplace.eclipse.org/content/jaspersoft-studio
②最新のEclipseプラグインを利用して作成したレイアウトファイルを使うと実行時エラーになる
次は、EclipseプラグインがインストールできるEclipseを利用してみました。
しかし、最新のEclipseプラグイン(Jaspersoft Studio 6.16.0)で作成したコンパイル済ファイル(.jasper)を
古いJasperReportsAPI(6.2.2)を利用しているJavaプログラムで使用すると、
実行時にClassNotFoundExceptionが発生しました。
net.sf.jasperreports.engine.JRException: Class not found when loading object from file: ./resources/test.jasper.
at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:152)
at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:116)
at net.sf.jasperreports.engine.JasperFillManager.fill(JasperFillManager.java:579)
at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:929)
~~~~JapserReportsのメソッドを呼び出している箇所が記載されていましたが、情報保護のため割愛します~~~~~
Caused by: java.lang.ClassNotFoundException: net.sf.jasperreports.compilers.ReportExpressionEvaluationData
at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:348)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:685)
at net.sf.jasperreports.engine.util.ContextClassLoaderObjectInputStream.resolveClass(ContextClassLoaderObjectInputStream.java:89)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1867)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2041)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1572)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2286)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2210)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2068)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1572)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2286)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2210)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2068)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1572)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:430)
at net.sf.jasperreports.engine.util.JRLoader.loadObject(JRLoader.java:140)
... 10 common frames omitted
原因
コンパイル済ファイルのJasperReportsコンパイルバージョンと、帳票出力アプリ側のライブラリのバージョンの間に、
クラスの依存関係が変わるほどの大きな差が出てしまったから。
※こちらを見ると、net.sf.jasperreports.compilers.ReportExpressionEvaluationDataが登場したのは、jasper report api 6.13.0以降のようです。
実施した対策
- Eclipseプラグインの互換性機能を利用する
- 帳票出力アプリ側のJasperReportAPIのバージョンをJaspersoftStudioに合わせて6.16.0にあげる
→ライブラリを変更した場合、影響範囲の再テストを実施する必要があると思い、影響範囲を小さくするため、Eclipseプラグインの互換性機能で対応してみることにしました。(③へ続く)
③Eclipseプラグインで互換性機能を利用してもエラーになる
EclipseプラグインのJaspersoft Studio(6.16.0)を利用した場合に、互換性設定でコンパイルバージョンを指定できます。その機能を使って、コンパイルバージョンを開発当時と同じ6.5.xにしてコンパイルをしたら、
Eclipse上でコンパイルエラーが発生し、かつ、実行時に、 java.lang.ClassNotFoundException: net.sf.jasperreports.compilers.ReportExpressionEvaluationDataが発生しました。
※コンパイルバージョンを指定する方法はこちらを参考にしました。
https://community.jaspersoft.com/wiki/compile-older-jasperreports-version-jaspersoft-studio
https://stackoverrun.com/ja/q/11089550
※コンパイル用のプログラムのダウンロードはこちらからできます。
https://sourceforge.net/projects/jasperreports/
https://github.com/TIBCOSoftware/jasperreports/releases
原因
こちらに関しては、原因が特定できませんでした。誰かわかる方がいましたら、教えてください。
Jaspersoft Communityに掲載されていた方法を利用しても、解決できなかったので、Eclipseプラグインを利用する方法以外に、影響が少ない方法を検討することにしました。
実施した対策
- Jaspersoft Studioを単独でインストールして利用する
Jaspersoft StudioはEclipseプラグインではなく、それ単独で利用できる専用のエディタとしても提供されているので、Jaspersoft Studioを単独でインストールして利用する。
古いバージョンは、Jaspersoft Communityのサイトからはダウンロードできないので(Jaspersoft Communityは6.8.0以降、アカウント登録も求められ退会方法が不明…)、こちらを利用する。
https://sourceforge.net/projects/jasperstudio/
最終的に、この方法で、無事、レイアウトファイルを変更し、ビルドすることができました!!!
まとめ
新しいJasperReportsを利用してエラーに遭遇したら、Eclipseプラグインを利用せず、当時のビルドバージョンに合わせたJaspersoft Studioを単独でインストールしてビルドしてください。
ここまで読んでくださってありがとうございました。同じ悩みに遭遇してしまった誰かの助けになれば幸いです。