IReports & JasperReports: Data Source
Hi:
I'm trying to generate and print reports using the IReport and JasperReports.
I've realised that this program is able to work with data from diferent sources (XML, Databases, etc), but not from Arrays and Vectors. Do you know if is possible to use this program and obtain the information from these structures?
Lots of thanks!!!
[360 byte] By [
pujolsa] at [2007-10-3 4:22:41]

You would have to implement a custom data source and potentially a datasource provider, depending on if you would be filling the report programaticially or through the iReports GUI. Just be forewarned.. iReports has known bugs with custom data sources, it may be better to fill the Report programaticially. Alternatively, you can use JasperAssistant to design your reports.
If you had a vector then each element in the vector would be 1 iteration of the detail band in the report, and then you would have to access the "Fields" of the element returned from the vector in your custom data source. So if you had a vector of "Students" (name, student_num as simple fields) the data source would be (a very simple example)...
import java.util.Vector;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
public class TestDataSource implements JRDataSource {
private int m_nIdx;
private Vector<Student> v;
public TestDataSource() {
this (new Vector<Student>());
}
public TestDataSource(Vector<Student> v) {
m_nIdx = -1;
this.v = v;
}
public Object getFieldValue(JRField field) throws JRException {
Object o = null;
String sName = field.getName();
Student currStudent = v.elementAt(m_nIdx);
if (currStudent == null)
return null;
if (sName.equals("student_name"))
o = currStudent.getStudentName();
else if (sName.equals("student_number"))
o = currStudent.getStudentNum();
return o;
}
public boolean next() throws JRException {
m_nIdx++;
return (m_nIdx < v.size());
}
}
You can use a Data source provider to describe to iReports what fields are available in your data source.
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRDataSourceProvider;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JasperReport;
public class TestDataSourceProvider implements JRDataSourceProvider {
public TestDataSourceProvider() {
}
public JRDataSource create(JasperReport report) throws JRException {
TestDataSource ds = new TestDataSource(/**ADD_VECTOR_HERE_SOMEHOW*/);
return ds;
}
public void dispose(JRDataSource dataSource) throws JRException {
// nothing to dispose
}
public JRField[] getFields(JasperReport arg0) throws JRException, UnsupportedOperationException {
JRField[] fields = new JRField[2];
fields[0] = new JRBasicField("Student Name", "student_name", java.lang.String.class, "java.lang.String");
fields[1] = new JRBasicField("Student Number", "student_number", java.lang.String.class, "java.lang.String");
return fields;
}
public boolean supportsGetFieldsOperation() {
// TODO Auto-generated method stub
return true;
}
}
Based on the provider class above, we can see that your report would have 2 fields, $F{student_name} and $F{student_num}
My appologies!
JRBasicField is a class I created, I should have included it in the post above....
import net.sf.jasperreports.engine.JRField;
public class JRBasicField implements JRField {
private String description;
private String name;
private Class valueClass;
private String valueClassName;
public JRBasicField(String description, String name, Class valueClass, String valueClassName) {
super();
this.description = description;
this.name = name;
this.valueClass = valueClass;
this.valueClassName = valueClassName;
}
public String getDescription() {
return description;
}
public String getName() {
return name;
}
public Class getValueClass() {
return valueClass;
}
public String getValueClassName() {
return valueClassName;
}
public void setDescription(String desc) {
description = desc;
}
}
When you implement this class, the error in .create() method should go away. (Remember you must pass the vector in yourself if your using the Provider under iReports. Filling the report programaticially, you must pass the vector to the data source.. the provider class isn't required if you fill the report programaticially).
As a note: if you implement your objects in the vector as proper beans, you can use a JRBeanCollectionDataSource object, which is part of the JasperReports API.