JasperReports Ultimate Guide - Samples - Schema - Configuration - Functions - FAQ - API (Javadoc)

JasperReports - Subreport Sample (version 6.21.0)


Shows how subreport could be used to create complex document layouts.

Download All Sample Source Files
Browse Sample Source Files on Git


Main Features in This Sample

Subreports

Exporting to JSON Format Using Report Metadata


top

SubreportsDocumented by Luke Shannon


Description / Goal
How to use the built-in subreport element to create nested content.

Since
0.3.0

Other Samples
/demo/samples/xmldatasource


What is a Subreport
A Subreport is a JasperReports Template thats embedded within another JasperReports template (which we will refer to as the Master report).
As the Master report executes, each time the Subreport element is reached it is executed and its content seamlessly embedded into the output of the Master report.
The end result is a single output containing the blended contents of the Master report and each subreport execution.
Subreports can be nested.

When to Use Subreports
There are several situations when you wish to embed one report into other. Examples of such situations are:
  • Isolating a common layout that is used in a series of reports
  • Processing records from a query different from the Master report's query
This current example demonstrates the latter case.

Running the Sample
Prerequisites
Ant is required. By running 'ant --version' you will be able to check if ant is set up on your system (at least version 1.5 is required):
    
    C:\>ant -version Apache Ant version 1.8.0 compiled on February 1 2010
	
	
You can obtain ant from http://ant.apache.org/, instructions for installation can be found there as well.

Starting the Data Source
In a command prompt/terminal window browse to the demo/hsqldb folder of the JasperReports source and run the command 'ant runServer'.
Leave window/terminal running (see below for sample output).
    
    C:\js-workspace\jasperreports\demo\hsqldb>ant runServer
	Buildfile: C:\js-workspace\jasperreports\demo\hsqldb\build.xml

	runServer:
     [java] [Server@83cc67]: [Thread[main,5,main]]: checkRunning(false) entered
     [java] [Server@83cc67]: [Thread[main,5,main]]: checkRunning(false) exited
     [java] [Server@83cc67]: Startup sequence initiated from main() method
     [java] [Server@83cc67]: Loaded properties from [C:\js-workspace\jasperreports\demo\hsqldb\server.properties]
     [java] [Server@83cc67]: Initiating startup sequence...
     [java] [Server@83cc67]: Server socket opened successfully in 19 ms.
     [java] [Server@83cc67]: Database [index=0, id=0, db=file:test, alias=] opened sucessfully in 1104 ms.
     [java] [Server@83cc67]: Startup sequence completed in 1125 ms.
     [java] [Server@83cc67]: 2010-03-10 11:32:30.423 HSQLDB server 1.8.0 is online
     [java] [Server@83cc67]: To close normally, connect and execute SHUTDOWN SQL
     [java] [Server@83cc67]: From command line, use [Ctrl]+[C] to abort abruptly
    
	
Generating the Report
Open up a separate command prompt/terminal window and browse to the root directory of the sample.
By running 'ant -p' you will be presented with a list of options available. Of interest in this list is all the exporters available for testing.
Each export type will generate a output type in the build/report folder.
By running the command 'ant' the following actions will be performed:
  • All java code will be compiled to produce class files.
  • JRXML fills will be compiled by JasperReports to produce a .jasper file (this is a serialized version of a JasperReports object).
  • The report will be filled with data and the resulting object, JasperPrint, will be serialized to the file system as a .jrprint.
  • All the exporters the sample is configured to test will run.

You can now run 'ant view' to see a version of the report in the JasperViewer (a Swing report viewer contained in the JasperReports package which can be used to view a .jrprint object).
Each of the these task can be ran separately as well:
  • ant clean - removes all generated files.
  • ant javac - compiles all java code, this should be done before running further tasks.
  • ant compile - compiles the JRXML generating a .jasper file.
  • ant fill - fills the report with data, some reports use the empty data source, others use the HSQL DB and other an inline data source. A .jrprint object is generated in this step.
  • ant view - opens the report in the JasperViewer
  • ant pdf - generates a PDF (other exporters are available run 'ant -p' for a full list)
Note: All generated files can be found in build/reports.
You now have a working version of the report you can review.

Configuring a Subreport
The first thing to note is any JasperReport can be used as a Subreport. However, once a report has embedded into another as a Subreport, the Master report is now responsible for:
  • Supplying the Subreport with a JRDataSource
  • Specifying an expression to locate the report design
  • Passing Parameters into the Subreport
The Subreport can return data to the main report using variables.
In this example the Master Report contains the Address and Product reports embedded as Subreport elements.
Lets begin by review the configuration of the Subreport element for the Products Subreport.
	
<subreport>
	<reportElement isPrintRepeatedValues="false" x="5" y="25" width="325" height="20" isRemoveLineWhenBlank="true" backcolor="#ffcc99"/>
	<subreportParameter name="City">
		<subreportParameterExpression><![ CDATA[$F{City} ]] ></subreportParameterExpression>
	</subreportParameter>
	<connectionExpression><![ CDATA[$P{REPORT_CONNECTION}]] ></connectionExpression>
	<returnValue subreportVariable="PriceSum" toVariable="ProductTotalPrice" calculation="Sum"/>
	<subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![ CDATA[$P{ProductsSubreport}]] ></subreportExpression>
</subreport>
	
This element is in the Detail band of the Master report. This means this Subreport will be executed with each record in the Master report's Result Set.

subreportParameter
This tag indicates a Parameter in the Product report is being filled by the Master report. In this case, its the City field in the Master report
filling the City Parameter of the Product report.
If we look at the query of the Product report we see that the value of the City parameter is injected into the Query to constrain the Results:
 	
SELECT Product.ID AS ID, Product.Name AS Name, 
Positions.Quantity AS Quantity, Positions.Price AS Price
FROM Positions, Product, Document, Address
WHERE Positions.DocumentID = Document.ID AND
Document.AddressID = Address.ID AND
Positions.ProductID = Product.ID AND
Address.City = $P{City}
ORDER BY Product.ID
 	
 
What this means is the Product report executes for each row in the Master report's ResultSet and displays results related to the city field in that row
(Remember: Fields map to the data source, in this case to columns returned in the Result Set).
For more information on modifying report queries please view the Query Sample.

connectionExpression
This tag specifies the JRDataSource to be used to fill the subreport. In this case the built in parameter $P{REPORT_CONNECTION} is used.
This parameter contains a reference to JDBC Connection that was used to fill the Master Report. This is best practice when working with Subreports
which need to be filled with the same JDBC Connection as the Master report.
In situations where your Subreport doesn't use a data source (the report may just contain some text and/or images) a reference to the
JREmptyDataSource can be passed in here:
	
<dataSourceExpression><![ CDATA[new net.sf.jasperreports.engine.JREmptyDataSource()]] ></dataSourceExpression>
	

returnValue
This tag indicates the value passed from the subreport to the Master report. The calulcation indicates if the value should be accumlated or just passed directly up.
In this case the calculation is Sum, meaning the PriceSum variable in the Subreport is going to be accumlated for each Subreport execution and stored in the
ProductTotalPrice variable of the master report. If the desired effect is to just pass a variable from the Subreport to the Master, then a calculation type of
None should be used.

subreport Expression
This tag indicates where the design of the Subreport can be located. Note the class. In this example the expression is returning a JasperReports object.
The subreport expression represents a very powerful place for extensions/integratoins. Ternary operators can be used here to load different Subreports based on different
conditions in the report. Also external Java classes can be called in this expression, provided they return a JasperReport reference, the subreport design can be obtained
or created using Java. In the SubreportApp.java the JasperReport reference is obtained by loading a .jasper (serialized JasperReport object) file from the file system.
 
 JasperReport subreport = (JasperReport)JRLoader.loadObjectFromFile("build/reports/ProductReport.jasper");
 
 
Lets review the Address Report configuration.
 	
<subreport>
	 <reportElement positionType="Float" x="335" y="25" width="175" height="20" isRemoveLineWhenBlank="true" backcolor="#99ccff"/>
	 <subreportParameter name="City">
	   <subreportParameterExpression><![ CDATA[$F{City}]] ></subreportParameterExpression>
	 </subreportParameter>
	 <connectionExpression><![ CDATA[$P{REPORT_CONNECTION}]] ></connectionExpression>
	 <returnValue subreportVariable="REPORT_COUNT" toVariable="CityAddressCount"/>
	 <subreportExpression class="java.lang.String"><![CDATA["AddressReport.jasper"]] ></subreportExpression>
</subreport>
	
 
The main differences are here:
  1. returnValue: No calculation is set. The default is None, which means the variable REPORT_COUNT variable in the subreport will be passed directly to the Master.
  2. subreportExpression: In this case the expression class is a String and the expression is the location on the file system for the compiled version of the JRXML.


Is there performance concerns with Subreports?
The answer to this depends on your system, data source and your report design. A few points to note on Subreports:
  • Each subreport execution may spawn a new thread (see below).
  • As the subreport executes more objects will be created in Heap Memory.
On the subject of threads. Support for Java continuations has been added as an alternative to threads. This was done using the Jakarta Commons Javaflow library.
The JasperReports property: net.sf.jasperreports.subreport.runner.factory can be used with the following two settings:
  • net.sf.jasperreports.engine.fill.JRContinuationSubreportRunnerFactory
  • net.sf.jasperreports.engine.fill.JRThreadSubreportRunnerFactory
By default net.sf.jasperreports.engine.fill.JRThreadSubreportRunnerFactory is used, however if net.sf.jasperreports.engine.fill.JRContinuationSubreportRunnerFactory
is set, then a Javaflow approach will be used to fill the reports rather than threads. If this option is chosen, then the Jakarta Commons Javaflow jar must be
included in the application classpath. This jar can be found in the lib directory of the JasperReport reports project distribution package.
Other alternatives for processing different queries in the same report are usage of the List element and Sub Datasets.

top

Exporting to JSON Format Using Report MetadataDocumented by Sanda Zaharia


Description / Goal
Shows how to export the report to JSON format using metadata associated with report elements at design time, to mark JSON tree nodes.

Since
6.0.0

Other Samples
/demo/samples/jasper


Pixel-Perfect Requirement and JSON Output Format

JasperPrint objects are ready to be printed out in a pixel-perfect representation. This means that they are very appropriate for visual representations of data, since objects' dimensions, their absolute and relative positions within the document are completely preserved. The pixel-perfect representation suits very well the read-only or layout-oriented output formats, such as PDF or Graphics2D, but it may generate some inconvenients for data-oriented output formats like CSV, Excel or JSON. In this case more important than the pixel-perfectness of the document is to allow the generated data in the report to be properly stored, transmitted or manipulated by specific engines. To successfully handle a set of data ideally is to know:
  • how to navigate through the data structure in order to retrieve the data;
  • the field name the data is associated with;
  • the correct data type (text, numeric, date, etc);
  • the data value
Document pagination and visual layout are not important in this case:
  • no page margins and other padding settings;
  • no page numbers;
  • no repetition of page headers;
  • etc.
The JSON output format organizes data hierachically in a tree structure, written in accordance with the JSON syntax:
  • arrays are enclosed in square brackets
  • objects in arrays are comma-separated
  • objects are enclosed in curly braces
  • object members come in name:value pairs, separated by commas
The JSON Metadata Exporter

Extracting relevant data from a pixel-perfect JasperPrint object, in order to generate a data-oriented output, may be done by customizing the export process. Some properties are needed to tell the JR engine which elements should be exported and where should they be placed within the JSON tree object. The JsonMetadataExporter is designed to handle such kind of metadata information and to generate consistent data structures.
Before starting its export work, the JSON metadata exporter looks for the presence of an existing JSON schema by calling the getJsonSchemaResource() exporter configuration setting. This can be configured either directly, using the APIs, or by reading the value from the net.sf.jasperreports.export.json.schema report property. If present, this setting provides the path to a JSON schema file that will be used to generate the JSON structure at export time. Nodes in a given schema may provide:
  • the _type property (mandatory), which can be an object or an array.
  • the _children property (mandatory for array-type nodes), which defines the type of the objects in the array.
  • other properties that describe the object.
An example of JSON schema can be found in demo/samples/subreport/reports/MasterReport.schema.json file in the subreport sample directory:
{
  _type: 'array',
  _children: {
    _type: 'object',
    City: 'value',
    products: {
      _type: 'array',
      _children: {
        _type: 'object',
        Id: 'value',
        Name: 'value',
        Quantity: 'value',
        Price: 'value'
      }
    },
    customers: {
      _type: 'array',
      _children: {
        _type: 'object',
        Name: 'value',
        Street: 'value'
      }
    }  
  }
}
The above schema instructs the engine to export data into an array of objects, each of them containing a City, an array of products and an array of customers. A product is defined by its Id, Name, Quantity and Price properties, while a customer is characterized by a Name and a Street
If no schema is provided at export time, then the output structure will be deduced from the elements marked for JSON export, in accordance with net.sf.jasperreports.export.json.path and/or net.sf.jasperreports.export.json.{type}.{arbitrary_path} metadata properties.
Following are the metadata properties defined at element level, that are taken into account by the JSON metadata exporter:
  • net.sf.jasperreports.export.json.path - this property uses the period notation to specify a given path within the JSON tree, where the current element will be exported. If the net.sf.jasperreports.export.json.schema property is not present in the report, this property can be used to determine a rule in the JSON schema as well. If the JSON schema is provided, then the path specified by net.sf.jasperreports.export.json.path must follow the rules in that schema. The current element will be placed in a node according to this path.
  • net.sf.jasperreports.export.json.{type}.{path} - properties with this prefix specify both the type and a given path within the JSON tree, where the current element will be exported. The exported value is the value of the property. If the net.sf.jasperreports.export.json.schema property is not present in the report, these properties can be used to determine rules in the JSON schema as well. If the JSON schema is provided, then the path specified by the {path} suffix must follow a rule in that schema. The current exported value will be placed in a node according to this path.
    When working with such properties, numbers have to be written with no thousand separators and using a period as decimal. For instance, 1,000,000 should be written as "1000000" and 2,000.45 should be written as "2000.45". Dates must be written according to ISO 8601 standard: "yyyy-MM-dd'T'HH:mm:ss".
  • net.sf.jasperreports.export.json.repeat.value - an element-level flag property indicating whether the value associated to that exported element should be repeated or not when it is missing.
  • net.sf.jasperreports.export.json.repeat.{path} - an element-level flag property indicating whether the value associated to that JSON path should be repeated or not when it is missing. Usually this property works in conjunction with one of the net.sf.jasperreports.export.json.{type}.{path} properties.
  • net.sf.jasperreports.export.json.data - element-level property containing the exported value for that element. By default is considered the value of the report element itself.
    When working with this property, numbers have to be written with no thousand separators and using a period as decimal. For instance, 1,000,000 should be written as "1000000" and 2,000.45 should be written as "2000.45". Dates must be written according to ISO 8601 standard: "yyyy-MM-dd'T'HH:mm:ss".
To control the appearance of the name of the member properties in an object, the metadata exporter looks for a report-level property called net.sf.jasperreports.export.json.escape.members. If this flag is set to true (as it is, by default), then member names will be surrounded by double quotes.
In this sample the JSON schema is referenced in MasterReport.jrxml. For each City given in the master report, a list of products is retrieved based on the ProductReport.jrxml subreport, and a list of customers is collected based on the AddressRport.jrxml subreport. Below are some coding fragments that show the use of properties discussed above:
In MasterReport.jrxml:
<jasperReport ...>
  <property name="net.sf.jasperreports.export.json.schema" value="reports/MasterReport.schema.json"/>
  ...
  <detail>
    <band height="50">
      <textField>
        <reportElement style="Sans_Bold" x="5" y="5" width="100" height="15" isPrintWhenDetailOverflows="true" uuid="2c343d22-1686-4fe6-be91-a83597306aeb">
          <property name="net.sf.jasperreports.export.json.path" value="City"/>
        </reportElement>
        <textFieldExpression><![CDATA[$F{City}]] ></textFieldExpression>
      </textField>
      ...
    </band>
  </detail>
  ...
</jasperReport>
In ProductReport.jrxml:
<jasperReport ...>
  ...
  <group name="ProductGroup">
    <groupExpression><![CDATA[$F{Id}]] ></groupExpression>
    <groupHeader>
      <band height="14">
        <textField>
          <reportElement x="0" y="2" width="15" height="10" uuid="fc2ad1b0-4874-4765-baf8-b17a2490185a">
            <property name="net.sf.jasperreports.export.json.path" value="products.Id"/>
          </reportElement>
          <textElement textAlignment="Right"/>
          <textFieldExpression><![CDATA[$F{Id}]] ></textFieldExpression>
        </textField>
        <textField textAdjust="StretchHeight">
          <reportElement positionType="Float" x="20" y="2" width="80" height="10" uuid="f53978bd-fc13-4359-b82d-2142640c6696">
            <property name="net.sf.jasperreports.export.json.path" value="products.Name"/>
          </reportElement>
          <textFieldExpression><![CDATA[$F{Name}]] ></textFieldExpression>
        </textField>
        <textField textAdjust="StretchHeight" evaluationTime="Group" evaluationGroup="ProductGroup" pattern="#0">
          <reportElement positionType="Float" x="105" y="2" width="20" height="10" uuid="aec3706b-5a2e-455a-aec0-245ada2a8830">
            <property name="net.sf.jasperreports.export.json.path" value="products.Quantity"/>
          </reportElement>
          <textElement textAlignment="Right"/>
          <textFieldExpression><![CDATA[$V{QuantityProductSum}]] ></textFieldExpression>
        </textField>
        <textField textAdjust="StretchHeight" evaluationTime="Group" evaluationGroup="ProductGroup" pattern="#0.00">
          <reportElement positionType="Float" x="130" y="2" width="30" height="10" uuid="38a1047a-67fe-4c37-ac55-1252bcb7f9db">
            <property name="net.sf.jasperreports.export.json.path" value="products.Price"/>
          </reportElement>
          <textElement textAlignment="Right"/>
          <textFieldExpression><![CDATA[$V{PriceProductSum}]] ></textFieldExpression>
        </textField>
      </band>
    </groupHeader>
    <groupFooter>
      <band/>
    </groupFooter>
  </group>
  ...
</jasperReport>
In AddressReport.jrxml:
<jasperReport ...>
  ...
  <detail>
    <band height="14">
      <textField>
        <reportElement x="0" y="2" width="15" height="10" uuid="e9328667-edce-49cd-a5a4-504884a5094f"/>
        <textElement textAlignment="Right"/>
        <textFieldExpression><![CDATA[$F{Id}]] ></textFieldExpression>
      </textField>
      <textField textAdjust="StretchHeight">
        <reportElement positionType="Float" x="20" y="2" width="80" height="10" uuid="1c766997-5272-480b-935f-cf519342a2a1">
          <property name="net.sf.jasperreports.export.json.path" value="customers.Name"/>
        </reportElement>
        <textFieldExpression><![CDATA[$F{FirstName} + " " + $F{LastName}]] ></textFieldExpression>
      </textField>
      <textField textAdjust="StretchHeight">
        <reportElement positionType="Float" x="105" y="2" width="70" height="10" uuid="919d119f-31d8-4631-b19c-555f21ef3e5e">
          <property name="net.sf.jasperreports.export.json.path" value="customers.Street"/>
        </reportElement>
        <textFieldExpression><![CDATA[$F{Street}]] ></textFieldExpression>
      </textField>
    </band>
  </detail>
  ...
</jasperReport>
After running the >ant test view command, the pure data exported with the JSON metadata exporter will be available in the demo/samples/subreport/build/reports directory as MasterReport.json.



© 2001- Cloud Software Group, Inc. www.jaspersoft.com