Data Adapter
Create a data adapter file, for example adapter.xml
, through the user interface. The contents might resemble:
<?xml version="1.0" encoding="UTF-8" ?>
<beanDataAdapter class="net.sf.jasperreports.data.bean.BeanDataAdapterImpl">
<name>YourClass</name>
<factoryClass>com.yourcompany.jasper.JRDataSourceFactory</factoryClass>
<methodName>createCollection</methodName>
<useFieldDescription>false</useFieldDescription>
</beanDataAdapter>
Data Class
Create a class that has a createCollection
method, as per the data adapter definition above:
package com.compay.jasper;
public class JRDataSourceFactory {
/**
* @return A collection of data for the report.
*/
public static Collection<YourClass> createCollection() {
return Arrays.asList( new YourClass() );
}
}
Set Report Properties
Ensure that the report has the following property (links the report to the custom data adapter):
<property name="com.jaspersoft.studio.data.defaultdataadapter" value="adapter.xml"/>
Set Report Fields
The report fields should now be able to reference the bean properties:
<field name="yourObject.property" class="java.lang.String">
<fieldDescription><![CDATA[yourObject.property]]></fieldDescription>
</field>
It's important that the fieldDescription
element contain a value that reflects the bean property (i.e., the Java code you would normally call to retrieve the value from the bean on an instance of that bean).
Application
The JRDataSourceFactory
class stands alone -- it's used by the data adapter to create a collection of bean instances. The static
method (createCollection
) does the work here and does not, indeed cannot, use inheritance.
Example
If possible, borrow the field names for the report from the bean's attributes. The code as written in the question makes it difficult to discern where the value for KN_Id
comes from.
The following example links the data adapter to the field names in the report.
Bean Class
A bean exposes some properties:
package com.company.domain;
public final class Student extends Entity {
private String firstName;
private String lastName;
public String getFirstName() {
return this.firstName;
}
public String getLastName() {
return this.lastName;
}
}
Data Adapter
The data adapter looks like:
<?xml version="1.0" encoding="UTF-8" ?>
<beanDataAdapter class="net.sf.jasperreports.data.bean.BeanDataAdapterImpl">
<name>Student</name>
<factoryClass>com.company.jasper.JRDataSourceFactory</factoryClass>
<methodName>createCollection</methodName>
<useFieldDescription>false</useFieldDescription>
</beanDataAdapter>
Data Class
The data class creates instances of the bean:
package com.compay.jasper;
import com.company.domain.Student;
public class JRDataSourceFactory {
public static Collection<Student> createCollection() {
return Arrays.asList( new Student() );
}
}
Report Fields
The report fields reflect the bean fields:
<field name="firstName" class="java.lang.String">
<fieldDescription><![CDATA[firstName]]></fieldDescription>
</field>
<field name="lastName" class="java.lang.String">
<fieldDescription><![CDATA[lastName]]></fieldDescription>
</field>
A collection of "student" instances is passed into the report. In this example, the collection contains a single instance. In your example, the collection could contain many instances. As the report library iterates over the collection, different values of firstName
and lastName
will be made available.
The mechanics for how the Student
instance data is initially populated is outside the scope of this answer. As far as the reporting tool is concerned, it simply uses pre-populated instances of Student
. If FillTable
populates TableCells
, that's not a concern for the reporting tool.