I'm building a chart in iReports and when I compile in Eclipse I get the following error:
net.sf.jasperreports.engine.JRException: Errors were encountered when compiling report expressions class file:
1. net.sf.jasperreports.engine.JRBeanCollectionDataSource cannot be resolved to a type
value = new net.sf.jasperreports.engine.JRBeanCollectionDataSource(((java.lang.String)field_chartData46xAxis.getValue())); //$JR_EXPR_ID=11$
<---------------------------------------------------->
2. net.sf.jasperreports.engine.JRBeanCollectionDataSource cannot be resolved to a type
value = new net.sf.jasperreports.engine.JRBeanCollectionDataSource(((java.lang.String)field_chartData46xAxis.getOldValue())); //$JR_EXPR_ID=11$
<---------------------------------------------------->
3. net.sf.jasperreports.engine.JRBeanCollectionDataSource cannot be resolved to a type
value = new net.sf.jasperreports.engine.JRBeanCollectionDataSource(((java.lang.String)field_chartData46xAxis.getValue())); //$JR_EXPR_ID=11$
<---------------------------------------------------->3 errors
at net.sf.jasperreports.engine.design.JRAbstractCompiler.compileReport(JRAbstractCompiler.java:204)
at net.sf.jasperreports.engine.JasperCompileManager.compile(JasperCompileManager.java:240)
at net.sf.jasperreports.engine.JasperCompileManager.compile(JasperCompileManager.java:173)
at net.sf.jasperreports.engine.JasperCompileManager.compileReport(JasperCompileManager.java:448)
at org.reportprotojava.protosheet.Program.main(Program.java:122)
I pass an ArrayList of ProtoReport (only one right now while I test) to the jasper compiler. The ProtoReport class contains a ChartData class which in turns has two ArrayList of type Double, one for the X-axis and one for the Y-axis.
The definitions of the ProtoReport, ChartData classes, and main program are as follows(slightly abridged):
ProtoReport Class:
package org.reportprotojava.protosheet;
import java.util.ArrayList;
public class ProtoReport {
private String outputFileName;
private String title;
private String logoLocation;
private String paragraphText;
private ArrayList<String> tableData;
private String picLocation;
private int[][] graphData; //TODO decide how to store chart data
private ChartData chartData;
private String path;
//default constructor
public ProtoReport() {
// Initialize object fields
outputFileName = "PrototypeReport";
title = "Prototype Report";
paragraphText = "Default text";
tableData = new ArrayList<String>();
chartData = new ChartData();
//set path to working directory
path = System.getProperty("user.dir");
//default to assumed report location
//(ie same folder as .jrxml and .jasper files)
logoLocation = path + "\\reports\\logo.jpg";
picLocation = path + "\\reports\\pic.jpg";
}
ChartData Class:
package org.reportprotojava.protosheet;
import java.util.ArrayList;
public class ChartData {
private ArrayList<Double> xAxis;
private ArrayList<Double> yAxis;
/**
* @param xAxis
* @param yAxis
*/
//default constructor
public ChartData(){
xAxis = new ArrayList<Double>();
yAxis = new ArrayList<Double>();
}
//constructor
public ChartData(ArrayList<Double> xAxis, ArrayList<Double> yAxis) {
super();
this.xAxis = xAxis;
this.yAxis = yAxis;
}
Main Program
public class Program {
/**
* @param args
*
*Program runs our ProtoReport class and its supporting classes
* In the end we will have generated a .pdf from the
* previously defined .jrxml file
*/
//Generate some random data for the chart
public static ArrayList<Double> randomData(int size) {
ArrayList<Double> arrayList = new ArrayList<Double>();
double randNumber;
for (int i = 0; i < size; i++) {
randNumber = Math.random();
arrayList.add(randNumber);
}
return arrayList;
}
public static void main(String[] args) {
ArrayList<ProtoReport> listOfReports = new ArrayList<ProtoReport>();
ProtoReport protoReport1 = new ProtoReport();
ProtoReport protoReport2 = new ProtoReport();
//Simple Fields and text
protoReport1.setTitle("Example<br/>Fact Sheet");
protoReport1.setLogoLocation(protoReport1.getPath() + "\\reports\\logo.gif");
ChartData chartData = new ChartData();
chartData.setYAxis(randomData(20));
for (Double i = (double) 0; i < chartData.getYAxis().size(); i++) {
chartData.getXAxis().add(i);
}
protoReport1.setChartData(chartData);
String jrxmlLocation = protoReport1.getPath()
+ "\\reports\\ReportPrototype.jrxml";
String outputFileName = protoReport1.getPath()
+ "\\reports\\generated\\" + protoReport1.getOutputFileName() + ".pdf";
listOfReports.add(protoReport1);
//and wrap the ArrayList in a JRBeanCollectionDataSource
JRBeanCollectionDataSource beanBurritoWrap = new JRBeanCollectionDataSource(listOfReports);
//build the jasper report
JasperReport jasperReport;
JasperPrint jasperPrint;
HashMap<String, Object> hashMap = new HashMap<>();
boolean reportCreated;
try {
jasperReport = JasperCompileManager.compileReport(jrxmlLocation);
jasperPrint = JasperFillManager.fillReport(jasperReport, hashMap, beanBurritoWrap);
JasperExportManager.exportReportToPdfFile(jasperPrint, outputFileName);
reportCreated=true;
}
catch (JRException e) {
e.printStackTrace();
reportCreated=false;
}
}
I've googled the problem and come up with this and this, and read the datasource section on jasper sourceforge but none of these have helped solve the problem, and I've made sure that I've used
new net.sf.jasperreports.engine.JRBeanCollectionDataSource($F{chartData.xAxis})
in my chart data source expression(and updated it when I change field names) and the fields are set to the List type in the iReport properties.
Here is my .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="ReportPrototype.jrxml" pageWidth="595" pageHeight="842" columnWidth="495" leftMargin="57" rightMargin="43" topMargin="43" bottomMargin="43" uuid="10825c57-f953-4166-bf03-8ecabe8a8f47">
<property name="ireport.zoom" value="0.75"/>
<property name="ireport.x" value="0"/>
<property name="ireport.y" value="232"/>
<subDataset name="ChartData" uuid="fc9ec0af-3e1a-40a7-8eb4-9ad30a266dee">
<field name="chartData.xAxis" class="java.lang.String"/>
</subDataset>
<queryString language="SQL">
<![CDATA[]]>
</queryString>
<field name="title" class="java.lang.String"/>
<field name="logoLocation" class="java.lang.String"/>
<field name="picLocation" class="java.lang.String"/>
<field name="chartData.xAxis" class="java.lang.String"/>
<detail>
<band height="740" splitType="Stretch">
<textField isStretchWithOverflow="true" pattern="">
<reportElement uuid="519c6bb5-72f9-4c25-8e91-47865ae0c9df" mode="Opaque" x="39" y="75" width="378" height="45" forecolor="#000099"/>
<textElement textAlignment="Center" verticalAlignment="Middle" markup="html">
<font size="26"/>
</textElement>
<textFieldExpression><![CDATA[$F{title}]]></textFieldExpression>
</textField>
<image onErrorType="Icon">
<reportElement uuid="3759a707-32a4-49ef-a9c6-b0ad7136f738" x="216" y="264" width="279" height="246"/>
<imageExpression><![CDATA[$F{picLocation}]]></imageExpression>
</image>
<image onErrorType="Icon">
<reportElement uuid="f989f871-32ea-4f13-ae3f-3f487cde76dd" x="295" y="0" width="200" height="42"/>
<imageExpression><![CDATA[$F{logoLocation}]]></imageExpression>
</image>
<xyLineChart>
<chart>
<reportElement uuid="ae87fc13-b92e-4a2a-b218-d395343f6028" x="0" y="537" width="495" height="203"/>
<chartTitle/>
<chartSubtitle/>
<chartLegend/>
</chart>
<xyDataset>
<dataset>
<datasetRun subDataset="ChartData" uuid="de7fb84d-17ea-4e5e-82bf-2015e72e4982">
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.JRBeanCollectionDataSource($F{chartData.xAxis})]]></dataSourceExpression>
</datasetRun>
</dataset>
</xyDataset>
<linePlot>
<plot/>
</linePlot>
</xyLineChart>
</band>
</detail>
<pageFooter>
<band height="16">
<break>
<reportElement uuid="0d30dea4-a6af-4e41-b7be-c288f3188dbf" x="0" y="11" width="100" height="1"/>
</break>
</band>
</pageFooter>
In iReports I've tried:
-Creating and naming fields ProtoReport.ChartData.xAxis and ProtoReport.ChartData.yAxis under Fields and the fields under the ChartData source I added
-Renaming the fields to ChartData.xAxis and ChartData.yAxis
-Renaming the fields to chartData.xAxis and chartData.yAxis
-Just using the fields under Field
-Just using the fields under ChartData - Fields
All give me an error. Any ideas what I'm doing wrong?
Additional questions:
-As it stands my chart will likely only produce the xAxis data points. How can I use the contents of one ArrayList for the X-axis and the other for the Y-Axis? ie my xAxis and yAxis fields in ChartData object.
-The randomData() method I declared before main would not run until I declared it static, why is that?
Edit
To state my question more clearly: How do I name my fields, setup my datasources, and configure my datasets in order to solve this problem?
I am following the tutorial listed in the comments (sorry for the non-hyper link; as a new user I've used all my hyperlinks already), and making changes to it for my needs, but his data structure is more simple than mine and I'd like to learn how to deal with more complex objects and datasets in jasper reports.
In the .jrxml the data source for the chart is defined as:
<![CDATA[new net.sf.jasperreports.engine.JRBeanCollectionDataSource($F{chartData.xAxis})]]>
This come from the iReports 4.7.0 autofill when you select Use datasource expression under Connection/Datasource exp in the details pane, the default expression from iReports is:
new net.sf.jasperreports.engine.JREmptyDataSource(1)
But this expression is wrong because .data is missing. It should read:
new net.sf.jasperreports.engine.data.JREmptyDataSource(1)
and then I changed the JREmptyDataSource(1) to JRBeanCollectionDataSource($F{chartData}) of course
This fixes the compile time error and then I had to reorganize and redefine my Lists and POJO's so that I could easily access the data point pairs in my List of ChartData objects. Essentially this meant that instead of a single ChartData object with two lists of doubles (one for X-Axis and one for Y-Axis), I now have a list of ChartData objects, each with just one XY point. This seems to work well for now.