Jump to content
We've recently updated our Privacy Statement, available here ×

Howto: Subreport using custom datasource


Recommended Posts

By: Gauauu - gauauu

Howto: Subreport using custom datasource

2006-07-13 07:49

Subreport with custom datasource. (JRDatasource)

 

I see a lot of questions on here about how to make this happen. And very few answers.

Hopefully this will help. I'm not convinced this is anywhere near the BEST way to make this work, but it worked for me.

 

Prereqs: If you don't have any idea how to deal with subreports, first, watch the video tutorial about subreports from the iReport page for an understanding of how to build and nest subreports (http://ireport.sourceforge.net/swf/Subreport_viewlet_swf.htm)

 

General Picture:

 

1. You will have a JRDatasource for your main report, and one for your subreport.

 

2. Since your custom JRDatasource can't read the parameters passed to it from the main report, it has to be smart enough to know the data arrangement of the master report. It can't ask the main report, "what master record are we on?" So when you build the master and sub report data, build them at the same time, so when you setup the first master record, setup the subreport's datasource so it knows to put the detail records for THAT master record first.

 

3. You use a parameter to pass the JRDataSource of the subreport to the main report.

 

4. In your report designer, you should put that same parameter as the datasource expression for the subreport.

 

 

Lost? Ok, let's go through it with an overly simple example.

 

Our master datasource will be similar to the custom datasource example from jasper reports:

 

 

public class CustomDataSource implements JRDataSource

{

 

 

/**

*

*/

private Object[][] data =

{

{"Berne", new Integer(22), "Bill Ott", "250 - 20th Ave."},

{"Boston", new Integer(32), "Michael Ott", "339 College Av."},

};

 

private int index = -1;

 

 

/**

*

*/

public CustomDataSource()

{

}

 

 

/**

*

*/

public boolean next() throws JRException

{

index++;

 

return (index < data.length);

}

 

 

/**

*

*/

public Object getFieldValue(JRField field) throws JRException

{

Object value = null;

 

String fieldName = field.getName();

 

else if ("Name".equals(fieldName))

{

value = data[index][2];

}

else if ("Street".equals(fieldName))

{

value = data[index][3];

}

 

return value;

}

 

 

}

 

 

 

Now we will define the datasource for our subreport detail record. In it, we must know the arrangement of records in our master data, so that we can arrange the detail groups to match.

 

When the subreport datasource's next() method returns false, Jasper knows that this is the end of that particular set of data. But it continues to use the same datasource object for the other detail lines. So you have to manually group the detail objects by returning a false value from next() when you have used all the detail objects for the current master object. Again, we can't figure out the master value from here, so we need to set it up ahead of time to match the master data source order.

 

 

public class SubCustomDataSource implements JRDataSource

{

 

 

/**

* our data is arranged to match the master data source, and

* the null records in the middle are to divide it into detail groups

*/

private Object[][] data =

{

{"Berne", new Integer(22), "Bill Ott's customer 1", "2501 - 20th Ave."},

{"Berne", new Integer(9), "Bill Ott's customer 2", "2771 Seventh Av."},

{null, 0, null, null},

{"Boston", new Integer(32), "Michael Ott's customer 1", "123 College Av."},

{"Boston", new Integer(32), "Michael Ott's customer 2", "234 College Av."},

};

 

private int index = -1;

 

 

/**

*

*/

public SubCustomDataSource()

{

}

 

 

/**

*

*/

public boolean next() throws JRException

{

index++;

 

//if we hit the null record, return false to indicate the end of this

//detail section

 

if (data[index][0] == null) {

return false;

}

 

return (index < data.length);

}

 

 

/**

*

*/

public Object getFieldValue(JRField field) throws JRException

{

Object value = null;

 

String fieldName = field.getName();

 

else if ("Name".equals(fieldName))

{

value = data[index][2];

}

else if ("Street".equals(fieldName))

{

value = data[index][3];

}

 

return value;

}

 

 

}

 

 

 

Now, our code to run the report should use a parameter to pass the subreport's datasource to the subreport.

 

To do this, you need to pick a parameter name for the subreport's datasource. We'll set up how the reports know which parameter to use when we talk about the report setup.

 

Here, I'm filling the compiled report directly. You can really do it however you like, the important part is setting the parameter:

 

Map customParameters = new HashMap();

customParameters.put("SubDataSource", new SubCustomDataSource());

 

JasperPrint filledReport = JasperFillManager.fillReport(getReportFileName(), customParameters, new CustomDataSource());

 

 

Now, we just need to define the reports so that they know what to do with this parameter.

 

If you are using iReport (I'm referring to version 1.2.4), in the master report, click the View menu, then parameters. Use "new" to add a new parameter. Call it whatever you picked for your subreport datasource parameter name (SubDataSource in the above example). Give it a class type of java.lang.Object.

 

Now, when you've added your subreport to the page, right click it, go to properties, and in the Subreport tab, set it to "Use Datasource Expression" and specify a datasource based on your parameter, like: $P{SubDataSource} (The $P just means to use that parameter).

 

On the Subreport (Other) tab, make sure the Subreport Expression points to your subreport file.

 

Then you are good to go, run your report and see the subreports work!

 

For reference, here are the jrxml files for my master (testReport) and subreport (subreport).

 

TestReport.jrxml:

 

<?xml version="1.0" encoding="UTF-8" ?>

<!-- Created with iReport - A designer for JasperReports -->

<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<jasperReport

name="Untitled_report_1"

columnCount="1"

printOrder="Vertical"

orientation="Portrait"

pageWidth="595"

pageHeight="842"

columnWidth="535"

columnSpacing="0"

leftMargin="30"

rightMargin="30"

topMargin="20"

bottomMargin="20"

whenNoDataType="NoPages"

isTitleNewPage="false"

isSummaryNewPage="false">

<property name="ireport.scriptlethandling" value="0" />

<property name="ireport.encoding" value="UTF-8" />

<import value="java.util.*" />

<import value="net.sf.jasperreports.engine.*" />

<import value="net.sf.jasperreports.engine.data.*" />

 

<parameter name="SUBREPORT_DIR" isForPrompting="true" class="java.lang.String">

<defaultValueExpression ><![CDATA[".\"]]></defaultValueExpression>

</parameter>

<parameter name="SubDataSource" isForPrompting="false" class="java.lang.Object"/>

 

<field name="Name" class="java.lang.String"/>

<field name="Street" class="java.lang.String"/>

 

<background>

<band height="0" isSplitAllowed="true" >

</band>

</background>

<title>

<band height="50" isSplitAllowed="true" >

<staticText>

<reportElement

x="24"

y="9"

width="462"

height="37"

key="staticText-3"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<text><![CDATA[static text]]></text>

</staticText>

</band>

</title>

<pageHeader>

<band height="50" isSplitAllowed="true" >

</band>

</pageHeader>

<columnHeader>

<band height="30" isSplitAllowed="true" >

<staticText>

<reportElement

x="17"

y="4"

width="132"

height="20"

key="staticText-1"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<text><![CDATA[Header 1]]></text>

</staticText>

<staticText>

<reportElement

x="194"

y="4"

width="147"

height="20"

key="staticText-2"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<text><![CDATA[Header 2]]></text>

</staticText>

</band>

</columnHeader>

<detail>

<band height="113" isSplitAllowed="true" >

<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None" hyperlinkTarget="Self" >

<reportElement

x="16"

y="6"

width="138"

height="27"

key="textField-1"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<textFieldExpression class="java.lang.String"><![CDATA[$F{Name}]]></textFieldExpression>

</textField>

<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None" hyperlinkTarget="Self" >

<reportElement

x="200"

y="6"

width="137"

height="27"

key="textField-2"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<textFieldExpression class="java.lang.String"><![CDATA[$F{Street}]]></textFieldExpression>

</textField>

<subreport isUsingCache="true">

<reportElement

x="79"

y="54"

width="385"

height="55"

key="subreport-1"/>

<dataSourceExpression><![CDATA[$P{SubDataSource}]]></dataSourceExpression>

<subreportExpression class="java.lang.String"><![CDATA["d:/temp/subreport.jasper"]]></subreportExpression>

</subreport>

</band>

</detail>

<columnFooter>

<band height="30" isSplitAllowed="true" >

</band>

</columnFooter>

<pageFooter>

<band height="50" isSplitAllowed="true" >

</band>

</pageFooter>

<lastPageFooter>

<band height="50" isSplitAllowed="true" >

</band>

</lastPageFooter>

<summary>

<band height="90" isSplitAllowed="true" >

</band>

</summary>

</jasperReport>

 

 

 

And my subreport.jrxml:

 

<?xml version="1.0" encoding="UTF-8" ?>

<!-- Created with iReport - A designer for JasperReports -->

<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN" "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<jasperReport

name="Untitled_report_2"

columnCount="1"

printOrder="Vertical"

orientation="Portrait"

pageWidth="595"

pageHeight="842"

columnWidth="535"

columnSpacing="0"

leftMargin="30"

rightMargin="30"

topMargin="20"

bottomMargin="20"

whenNoDataType="NoPages"

isTitleNewPage="false"

isSummaryNewPage="false">

<property name="ireport.scriptlethandling" value="0" />

<property name="ireport.encoding" value="UTF-8" />

<import value="java.util.*" />

<import value="net.sf.jasperreports.engine.*" />

<import value="net.sf.jasperreports.engine.data.*" />

 

 

<field name="Name" class="java.lang.String"/>

<field name="Street" class="java.lang.String"/>

 

<background>

<band height="0" isSplitAllowed="true" >

</band>

</background>

<title>

<band height="0" isSplitAllowed="true" >

</band>

</title>

<pageHeader>

<band height="0" isSplitAllowed="true" >

</band>

</pageHeader>

<columnHeader>

<band height="0" isSplitAllowed="true" >

</band>

</columnHeader>

<detail>

<band height="40" isSplitAllowed="true" >

<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None" hyperlinkTarget="Self" >

<reportElement

x="171"

y="9"

width="138"

height="27"

key="textField-1"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<textFieldExpression class="java.lang.String"><![CDATA[$F{Name}]]></textFieldExpression>

</textField>

<textField isStretchWithOverflow="false" isBlankWhenNull="false" evaluationTime="Now" hyperlinkType="None" hyperlinkTarget="Self" >

<reportElement

x="355"

y="9"

width="137"

height="27"

key="textField-2"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<textFieldExpression class="java.lang.String"><![CDATA[$F{Street}]]></textFieldExpression>

</textField>

<staticText>

<reportElement

x="14"

y="12"

width="130"

height="25"

key="staticText-1"/>

<box topBorder="None" topBorderColor="#000000" leftBorder="None" leftBorderColor="#000000" rightBorder="None" rightBorderColor="#000000" bottomBorder="None" bottomBorderColor="#000000"/>

<textElement>

<font/>

</textElement>

<text><![CDATA[subreport:]]></text>

</staticText>

</band>

</detail>

<columnFooter>

<band height="0" isSplitAllowed="true" >

</band>

</columnFooter>

<pageFooter>

<band height="0" isSplitAllowed="true" >

</band>

</pageFooter>

<summary>

<band height="0" isSplitAllowed="true" >

</band>

</summary>

</jasperReport>

Link to comment
Share on other sites

  • Replies 0
  • Created
  • Last Reply

Top Posters In This Topic

Popular Days

Top Posters In This Topic

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×
×
  • Create New...