BeanReports - 2 minutes guide
What is it for:
Build a set of jasper report templates (.jrxml) directly from java beans. It can handle an arbitary number of nested beans and collections.
This follows the idea of separating the logic and presentation layers:
The data of the report is produced completely in java, thus it is easier to develop and test.
The reports are then used only for the presentation.
The examples in this page can be run by calling the test target of the ant build file, available with the
current release.
Example Beans
Typically the beans from which the report templates are produced would be a mixure of Data Objects and Model Objects.
As an example, imagine you have Customer, Order and OrderItems
public class Order {
@ReflectionHelperInfo(fieldOrder=1.1)
@ReportInfo(showShortInReport=false)
Customer customer;
@ReflectionHelperInfo(fieldOrder=1.1)
@ReportInfo(showShortInReport=false)
@StructureInfo(childClass=OrderLine.class)
List orderLines;
// ... getter,setters and toString....
}
public class Customer {
@ReflectionHelperInfo(fieldOrder=1.1)
String name;
@ReflectionHelperInfo(fieldOrder=1.2)
String phone;
// ... getter and setters and toString....
}
public class Orderline {
String itemDesc;
double price;
double margin;
// ... getter and setters and toString....
}
As you can see several annotations are used:
-
@ReflectionHelperInfo(fieldOrder=1): Specify where this property should appear in the report.
The properties with smaller fieldOrder go first.
This is required otherwise the properties would appear in any order,
as the JVM does not know about the order of declaration in the source files.
- @ReportInfo(showShortInReport=false) : Indicates that we want the template
to show what is inside the property .
When set to true (the default) a call to toString() is instead issued.
-
@StructureInfo(childClass=OrderLine.class): Used for the collections to indicate what
is the class of the elements in the collection. This is required since the generics information
is not available at runtime.
All the annotations are in the net.sf.beanreports.annotation package
Building the report templates
Now let's run the report template generation for the Order class:
import net.sf.beanreports.jasper.*;
...
JasperGenerator jasperGenerator=new JasperGenerator(new JasperGeneratorConfig("tmp"));
jasperGenerator.generateReport(Order.class);
This will produce a set of jrxml files in the tmp/Order directory:
- Order.jrxml: this will be the main report
- OrderLine.jrxml: will be used as a subreport
The jrxml reports can then be parsed and populated as normal jasper reports.
See net.sf.beanreports.jasper.IntegrationTest in the test folder for an example of how to do that.
Replacing toString()
You will probably want to use another method than toString() for the properties marked as
showShortInReport. For this override the JasperGeneratorConfig.getShortStringFor(...) method.
Another kind of list
Removing the annotation @ReportInfo(showShortInReport=false) from the orderLine property
will produce a template with another kind of list that displays only one line per Orderline,
instead of displaying all properties.
Each line will be show what is returned by the toString() method, or whatever
is defined in JasperGeneratorConfig.getShortStringFor(...).
Reusing beans for different reports
Putting annotations in the Model for the report is not usually a good thing to do.
In addition to having people saying bad things about you at the coffee machine,
you will run into troubles when reusing the classes for another report.
Fortunately Beanreports comes with a mechanism to allow for overriding the annotations
(but not for the bad tongues).
Consider that now we realize the need for another version of the order report,
where the margin should not be shown. This can be achieved with:
// 1) create the equivalent of a @ReportInfo annotation,
//with the information we want
ReportInfoProxy generatorInfoAdapter=new ReportInfoProxy();
generatorInfoAdapter.showInReport=false;
// 2) specify the path on which this ReportInfoProxy is to be used
ContextualAnnotationManager.getInstance().addOverride("orderLines.margin",generatorInfoAdapter);
Now the report will be generated has if the margin property of the orderLines property of
the top level beans would have a annotation @ReportInfo(showInReport=false)
Disclaimer
This is a very early release, the API will probably change. And yes I know the reports look ugly :)