JasperReports can be built on any data having visual representation. In order to make the data "understandable" to the report object, it should be supplied through a JRDataSource interface. The JasperReports package supplies several implementations, which can be used with a RDBMS, xml, csv and object data sources.
In order to represent db4o objects in the most convenient way, we will build a special JRDataSource implementation - ObjectDataSource - using reflection to obtain object field values.
ObjectDataSource will accept data as a list of objects, because this is the way it is returned from a db4o query:
List <Pilot> pilots =
objectContainer.query(pilotPredicate);
01/** 02
* ObjectDataSource class is used to extract object field values for the report. 03
* <br><br> 04
* usage:<br> 05
* List pilots = ...<br> 06
* ObjectDataSource dataSource = new ObjectDataSource(pilots);<br> 07
* In the report (*.jrxml) you will need to define fields. For example: <br> 08
* <field name="Name" class="java.lang.String"/><br> 09
* where field name should correspond to your getter method:<br> 10
* "Name" - for getName()<br> 11
* "Id" - for getId()<br> 12
* 13
*/ 14
public class ObjectDataSource implements JRDataSource { 15
16
private Iterator iterator; 17
18
private Object currentValue; 19
20
public ObjectDataSource(List list) { 21
this.iterator = list.iterator(); 22
}
ObjectDataSource must implement 2 methods:
public boolean next()
and
public Object getFieldValue(JRField field)
The next()
implementation is very simple: it
just moves the current pointer to the next object in the list:
1public boolean next() throws JRException { 2
currentValue = iterator.hasNext() ? iterator.next() : null; 3
return (currentValue != null); 4
}
getFieldValue
method should return the value
for the specified field. The field is defined in *.jrxml
file and is passed to the JRDataSource
as a JRField
.
In the case of an object list datasource the objective is to correspond field
names to the object field values. One of the ways to do this is to correspond
the name of the field in the report to the name of the getter method in the
object class. For example:
<field
name="Name" class="java.lang.String"/>
class Pilot
{
...
public
String getName(){
return
name;
}
}
The method name is "get" + JRField#getName() or "get" + "Name". Knowing the method name, we can invoke it using reflection and obtain the value of the object field:
01public Object getFieldValue(JRField field) throws JRException { 02
Object value = null; 03
try { 04
// getter method signature is assembled from "get" + field name 05
// as specified in the report 06
Method fieldAccessor = currentValue.getClass().getMethod("get" + field.getName(), null); 07
value = fieldAccessor.invoke(currentValue, null); 08
} catch (IllegalAccessException iae) { 09
iae.printStackTrace(); 10
} catch (InvocationTargetException ite) { 11
ite.printStackTrace(); 12
} catch (NoSuchMethodException nsme) { 13
nsme.printStackTrace(); 14
} 15
return value; 16
}