Package net.sf.jasperreports.engine.data
Data Sources
When filling the report, the JasperReports engine iterates through the records of the supplied data source object and generates every section according to the template defined in the report design.
Normally, the engine expects to receive a
JRDataSource
object as the data source of the
report that it has to fill. But another feature lets users supply a JDBC
connection object instead of the usual data source object when the report data is found in
a relational database.
The JRDataSource
interface is very simple. It
exposes only two methods:
public boolean next() throws JRException; public Object getFieldValue(JRField jrField) throws JRException;The
next()
method is called on the data source object by the reporting engine when
iterating through the data at report-filling time. The second method provides the value
for each report field in the current data source record.
It is very important to know that the only way to retrieve data from the data source is by using the report fields. A data source object is more like a table with columns and rows containing data in the table cells. The rows of this table are the records through which the reporting engine iterates when filling the report and each column should be mapped to a report field, so that we can make use of the data source content in the report expressions.
There are several default implementations of the
JRDataSource
interface.
JDBC Data Sources
TheJRResultSetDataSource
is a very useful
implementation of the JRDataSource
interface
because it wraps a java.sql.ResultSet
object. Since most reports are generated using
data in relational databases, this is probably the most commonly used implementation for
the data source interface.
Interestingly, you might end up using this implementation even if you do not instantiate
this class yourself when filling your reports. This is what happens: if you specify the
SQL query in your report template, the reporting engine executes the specified SQL
query and wraps the returned java.sql.ResultSet
object in a
JRResultSetDataSource
instance. The only thing
the engine needs to execute the query is a java.sql.Connection
object.This connection object
may be supplied instead of supplying the usual data source object.
In many other cases the SQL query is executed in the parent application, outside
JasperReports. In such a situation, one could manually wrap the
java.sql.ResultSet
obtained using an instance of this data source class before calling
the report-filling process.
The most important thing to know when using this type of data source is that one must
declare a report field for each column in the result set. The name of the report field must
be the same as the name of the column it maps, as well as the data type.
If this is not possible for some reason, the data source also allows users to retrieve data
from a particular column in the java.sql.ResultSet
by index. The report field that
maps the specified column can be named COLUMN_x
, where x is the one-based index of
the result set column.
For maximum portability, as stated in the JDBC documentation, the values from a
java.sql.ResultSet
object should be retrieved from left to right and only once. To
ensure that they work this way, consider declaring the report fields in the same order as
they appear in the SQL query.
JavaBeans Data Sources
The library provides two data source implementations that can wrap collections or arrays of JavaBean objects. Both implementations rely on Java reflection to retrieve report field data from the JavaBean objects wrapped inside the data sources. These data sources can be used to generate reports using data already available in-memory in the form of EJBs, Hibernate, JDO objects, or even POJOs.
The JRBeanArrayDataSource
is for
wrapping an array of JavaBean objects to use for filling a report with data, and the
JRBeanCollectionDataSource
is for
wrapping a collection of JavaBeans. Each object inside the array or the collection will be
seen as one record in this type of data source.
The mapping between a particular JavaBean property and the corresponding report field is made by naming conventions. The name of the report field must be the same as the name of the JavaBean property as specified by the JavaBeans specifications.
For instance, to retrieve the value of a report field named productDescription
, the
program will try to call through reflection a method called getProductDescription()
on the current JavaBean object.
The JavaBeans data source implementation contain few methods that are useful in certain cases:
getData()
- returns the underlying bean collection or array used by the data source.getRecordCount()
- returns the total number of beans contained in the collection or array used by the data source.cloneDataSource()
- returns a copy of data source by creating a fresh data source that uses the same underlying JavaBeans collection or array. This method can be used when a master report contains a subreport that needs to iterate on the same JavaBeans collection as the master.
Map-Based Data Sources
JasperReports library comes with two data source implementations that can wrap arrays or collections ofjava.util.Map
objects.
The JRMapArrayDataSource
wraps an array
of java.util.Map
objects, and
JRMapCollectionDataSource
can be used
to wrap a java.util.Collection
of Map
objects.
These implementations are useful if the parent application already stores the reporting
data available in-memory as java.util.Map
objects. Each Map
object in the wrapped array or
collection is considered a virtual record in the data source, and the value of each report
field is extracted from the map using the report field name as the key.
Map-based data source implementations contain the same set of utility methods as JavaBeans data sources:
getData()
to access the underlying map collection or arraygetRecordCount()
to return the total number of maps/recordscloneDataSource()
- to create a fresh copy of the data source
TableModel Data Sources
In some Swing-based desktop client applications, the reporting data might already be available in the form of ajavax.swing.table.TableModel
implementation used for
rendering javax.swing.JTable
components on various forms. JasperReports can
generate reports using this kind of data if a given javax.swing.table.TableModel
object is wrapped in a
JRTableModelDataSource
instance before
being passed as the data source for the report-filling process.
There are two ways to use this type of data source. Normally, to retrieve data from it,
one must declare a report field for each column in the
javax.swing.table.TableModel
object bearing the same name as the column it
maps. Sometimes it is not possible or desirable to use the column name, however,
because the report field name and columns could still be bound to report fields using
their zero-based index instead of their names.
For instance, if you know that a particular column is the third column in the table model
object (index=2), then you could name the corresponding field "COLUMN_2" and use the
column data without problems.
XML Data Sources
XML documents can be used as report data sources by means of a data source implementation. JasperReports features a built-in XML data source implementation (JRXmlDataSource
) that is based on DOM
and uses XPath expressions to select data from the XML document.
An XML data source instantiation involves the following inputs:
- An XML document. The parsed document, its location, or its source is provided as an argument to the data source constructor.
- An XPath expression to select the node set that corresponds to the data source record list. The expression is passed to the data source as a constructor argument. The default XPath expression selects the document node itself; in this case the data source would produce a single record. The XPath expression is executed when the data source is instantiated; each item in the resulting node set will generate a record/row in the data source.
- For every field in the report/data set, an XPath expression to select the field value
for each record is needed. The field's XPath expression is provided by the
AbstractXmlDataSource.PROPERTY_FIELD_EXPRESSION
custom field property. The use of thefield description
to specify the XPath expression is still supported, but is now discouraged, the above mentioned custom property taking precedence over the field description. The field's XPath expression is executed for each record using as a context node the current node from the main node set.
- A sub-data source can be created for a new document that uses the current node as
a root node. An XPath expression can additionally be specified to select the list of
nodes for the sub-data source. The
subDataSource()
andsubDataSource(String selectExpression)
methods should be used to create sub-data sources in this scenario. - The same document can be reused for a new sub-data source, which would specify
a different XPath expression for the main node set. This can be accomplished via
dataSource()
anddataSource(String selectExpression)
methods calls.
In order to parse these text values into java.lang.Number
or java.util.Date
values
according to the declared report field type in the report template, the program needs to
know which pattern and locale to use. For date/time report fields, if the text value inside
the XML representing time is rendered in a specific time zone, then this time zone needs
to be provided to the data source so that it is taken into account when parsing.
There are four setter methods in the JRXmlDataSource class for specifying:
setNumberPattern(java.lang.String)
- to use for parsing all text values corresponding to report fields of typejava.lang.Number
or any subclass of itsetDatePattern(java.lang.String)
- to use for parsing all date/time values corresponding to report fields of typejava.util.Date
or any subclass of itsetLocale(java.util.Locale)
- to use for getting localized number and date parserssetTimeZone(java.util.TimeZone)
- to use for properly translating time values when they are not expressed in GMT
java.text.DecimalFormat
and
java.text.SimpleDateFormat
pattern syntax. If specific patterns are not supplied, the defaults for
these two format classes apply.
XML data sources work by interpreting XPath expressions and selecting nodes and
values from the XML document based on these expressions. This functionality related to
XPath processing has been extracted into a generic service interface called
JRXPathExecuter
.
The XPath executer implementation used by XML data sources can be configured via a
JasperReports property named net.sf.jasperreports.xpath.executer.factory
.
This property gives the name of a XPath executer factory class, which has to implement
the JRXPathExecuterFactory
.
JasperReports has two XPath executer implementations, one based on
Apache Xalan (http://xml.apache.org/xalan-j/), now moved into a separate jasperreports-xalan artifact,
and the second based on Jaxen (http://www.cafeconleche.org/jaxen/), now used by default.
In many cases, the Jaxen XPath executor provides better performance than the
executor that uses Xalan. But if backward compatibility is required, for switching to the Xalan XPath executer, one needs to set the
net.sf.jasperreports.xpath.executer.factory
property to
the net.sf.jasperreports.xalan.util.XalanXPathExecuterFactory class, which
is usually done by including the following line in the jasperreports.properties
configuration file:
net.sf.jasperreports.xpath.executer.factory=net.sf.jasperreports.xalan.util.XalanXPathExecuterFactoryand make sure the optional jasperreports-xalan-x.x.x.jar is in the classpath of the application. To switch back to Jaxen, one would comment or remove the property line, or explicitly set the property to
JaxenXPathExecuterFactory
.
CSV Data Sources
Sometimes data that users need to fill the report with is found in plain text files, in a certain format, such as the popular CSV (comma-separated value).
JasperReports provides an implementation for such a data source, by wrapping the CSV
data from a text file into a JRCsvDataSource
.
The CSV data source usually needs to read a file from disk, or at least from an input
stream. Thus, the JRCsvDataSource
can be initialized in three ways, depending on
where it gets the data:
- a file -
new JRCsvDataSource(File)
- an input stream -
new JRCsvDataSource(InputStream)
- a reader -
new JRCsvDataSource(Reader)
The default values in JasperReports (and also the most common for CSV files) are a
comma for field delimiter and a newline (\n
) for record delimiter. Users can override
these default values by calling setFieldDelimiter(char)
and
setRecordDelimiter(String)
. For example, on some systems, users may need to
replace the default \n
delimiter with \r\n
.
Since CSV does not specify column names, the default convention is to name report
fields COLUMN_x
and map each column with the field found at index x in each row (these
indices start with 0). To avoid this situation, users have two possible solutions:
- using the
setUseFirstRowAsHeader(true)
method to force the program to read the column name from the first line of the CSV file. - Providing an array of column names using the
setColumnNames(String[])
method.
Handling data types for fields in CSV data sources is special since the CSV file format
does not provide such information. This matter is solved by trying to match each field in
the data source to its corresponding report field type. For number and date/time fields,
converting text values to java.lang.Number
and java.util.Date
values respectively
requires parsing using format objects. This is controlled by specifying the date and
number format objects to be used with the
JRCsvDataSource
instance by calling its
setDateFormat(DateFormat)
and setNumberFormat(NumberFormat)
methods
before passing it to the report-filling process.
The CSV data source implementation also has a JRCsvDataSourceProvider class, useful for design tools creators.
Excel Data Sources
When reporting data is in Microsoft Excel files (XLS or XLSX), theExcelDataSource
data source
implementation can be used to read it and feed it into the report.
The XLS data source uses the Apache POI library to load the Excel workbook and read from it. Instances of this data source can be created by supplying either an in-memory workbook object, a file, or an input stream to read the data from.
Report-field mapping for this data source implementation is very similar to the CSV data source field-mapping explained in the previous section. It works on the assumption that the workbook contains data in a tabular form (rows are records and columns contain report-field values).
Empty Data Sources
TheJREmptyDataSource
class is a very simple
data source implementation that simulates a data source with a given number of virtual
records inside. It is called "empty data source" because even though it has one or more
records inside, all the report fields are null for all the virtual records of the data source.
Such a simple data source implementation is used by the UI tools to offer basic report preview functionality, or in special report templates, or for testing and debugging purposes.
Rewindable Data Sources
TheJRRewindableDataSource
is an extension of
the basic JRDataSource
interface, to which it adds
the possibility of moving the record pointer back before the first virtual record. It adds
only one method, called moveFirst()
, to the interface.
Rewindable data sources are useful when working with subreports. If a subreport is placed inside a band that is not allowed to split due to the isSplitAllowed="false" setting and there is not enough space on the current page for the subreport to be rendered, then the engine has to give up rendering the current band, introduce a page break, and restart the band and the subreport on the next page. But since the subreport has already consumed some of the supplied data source records when trying to render the band on the previous page, it needs to move the record pointer of the data source back before the first data source for the subreport to restart properly.
All built-in data source implementations are rewindable except for the
JRResultSetDataSource
, which does not support
moving the record pointer back. This is a problem only if this data source is used to
manually wrap a java.sql.ResultSet
before passing it to the subreport. It is not a
problem if the SQL query resides in the subreport template because the engine will reexecute
it when restarting the subreport on the next page.
Data Source Provider
To simplify integration with the GUI tools for creating and previewing report templates, the JasperReports library has published an interface that allows those tools to create and dispose of data source objects. This is the standard way to plug custom data sources into a design tool.
This is very useful when the developer wants to preview the reports with the design tool
and use the actual data that the target application will supply at runtime. In order to
achieve this, simply create a custom implementation of the
JRDataSourceProvider
interface and make it
available to the design tool to create the required data sources to use during report preview.
The data source provider interface has only a few methods that allow creating and disposing of data source objects and also methods for listing the available report fields inside the data source if possible. Knowing which fields will be found in the created data sources helps you to create report field wizards inside the design tools to simplify report creation.
The library also comes with an abstract implementation of the
JRDataSourceProvider
interface that can be used as the base class for creating data source provider
implementations that produce JavaBean-based data sources.
The JRAbstractBeanDataSourceProvider
uses Java reflection to provide available report fields names for a given JavaBean class.
Related Documentation
JasperReports Tutorial-
Interface Summary Interface Description DataAdapterServiceConstants DataSourceProvider<D extends JRDataSource> HierarchicalDataSource<T extends JRDataSource> IndexedDataSource JRDataSource
extension that can provide the record index at the current position.JRAbstractBeanDataSource.PropertyNameProvider JsonData<T extends JsonData<T>> RandomAccessDataSource RewindableDataSourceProvider<D extends JRRewindableDataSource> XlsxDataSourceFactory -
Class Summary Class Description AbstractXlsDataSource This data source implementation reads an XLSX or XLS stream.AbstractXmlDataSource<T extends AbstractXmlDataSource<?>> Abstract XML data source implementation that allows to access the data from a xml document using XPath expressions.ConsumedFirstRecordDataSource DataSourceCollection<D extends JRDataSource,P extends DataSourceProvider<D>> JRAbstractBeanDataSource JRAbstractBeanDataSource.DefaultPropertyNameProvider JRAbstractBeanDataSourceProvider The base implementation for JRBeanXXXDataSource providers.JRAbstractTextDataSource Abstract text data source, containing methods used to parse text data into numerical or date values.JRBeanArrayDataSource A data source implementation that wraps an array of JavaBean objects.JRBeanCollectionDataSource A data source implementation that wraps a collection of JavaBean objects.JRCsvDataSource This datasource implementation reads a CSV stream.JRCsvDataSourceProvider JRMapArrayDataSource JRMapCollectionDataSource JRTableModelDataSource JRXmlDataSource XML data source implementation that allows to access the data from a xml document using XPath expressions.JsonDataCollection<D extends JsonData<D>> ListOfArrayDataSource RewindableDataSourceCollection<D extends JRRewindableDataSource> TextDataSourceAttributes -
Exception Summary Exception Description NoRecordAtIndexException