Plugin for grails available: see DJ Grails plugin
The purpose of this paper is to explain how DynamicJasper and Grails could be integrated. We are currently making so much progress, and plan to continue doing so, but our main interest is to share it, get feedback and go forward.
Why using DynamicJasper for grails reporting? They share a common philosophy: making development easier by using conventions, allowing the most common cases to be developed fast and easily.
This example is a favorite books database, with basic data such as: isbn, title, author, country, and a score based on my personal opinion.
class Book {
String name
String ISBN
Date dateWritten
String author
String country
Integer score
}
Once you have configured the project and are working on a relatively simple data model, your first report would be quite straightforward, within the Book controller:
def report = {
FastReportBuilder drb = new FastReportBuilder();
DynamicReport dr = drb.addColumn("Name", "name",
String.class.getName(),30).addColumn("ISBN", "ISBN",
String.class.getName(),30).addColumn("Author","author",
String.class.getName(), 100).
setTitle("My Favorite Books").
setUseFullPageWidth(true).
build();
JRDataSource ds = new JRBeanCollectionDataSource(Book.list());
JasperPrint jp = DynamicJasperHelper.generateJasperPrint(dr, new
ClassicLayoutManager(), ds);
JasperViewer.viewReport(jp);
}
This way, you have defined a new action report:

Which take us right to a JasperView with the data:

So far we have demonstrated basic reporting capabilities, in order to show you how quickly the report could be made! We only needed to define a DynamicReport which finally turns into a JasperPrint with our favorite books list.
DynamicReport: is a domain model entity which models a report, including attributes such as title, subtitle, and footer, and many other common ones, such as columns, groups, repeating groups and so on. As we are going to see, pretty soon, each of these elements can be modified.
JasperPrint: Is the Jasper file compiled and filled, can be shown in different formats (PDF, HTML, XLS, etc).
Honestly, the last list doesn?t really represent my preferences: The Being and the Nothing was really good, but A Clockwork Orange should not be in second place.
This is not related with DynamicJasper, but with the list created. Hence, I am going to define an ordered list:
def list = Book.list()
def scoreComparator = [
compare: {
a,b -> a.score > b.score ? -1: 1
}] as Comparator
JRDataSource ds = new JRBeanCollectionDataSource(list.sort(scoreComparator));
And as ISBN is not crucial, I will replace it with Country and Score:

These are my favorites, and the report makes more sense now. However, I would like to know which author prevails on my library.
In order to do so, let?s define the columns individually:
SimpleColumn columnName = ColumnBuilder.getNew().
setColumnProperty("name", String.class.getName()).
setTitle("Name").build()
SimpleColumn columnAuthor = ColumnBuilder.getNew().
setColumnProperty("author", String.class.getName()).
setTitle("Author").build()
SimpleColumn columnCountry = ColumnBuilder.getNew().
setColumnProperty("country", String.class.getName()).
setTitle("Country").build()
SimpleColumn columnScore = ColumnBuilder.getNew().
setColumnProperty("score", Integer.class.getName()).
setTitle("Score").build()
SimpleColumn : Is the entity which models a column in the report. Is one of the children of AbstractColumn, among others, such as PropertyColumn or ExpressionColumn (which allows to use averages or percentages).
As group without ordering is not always the best way to present data, we are going to show them ordered by author and score:
def authorComparator = [
compare: {
a,b -> if (a.author.equals(b.author)) {
return a.score > b.score ? -1 : 1
} else {
return a.author > b.author ? 1 : -1
}
}] as Comparator
FInally, we define the group and a variable to sum how many elements match the criteria set before.
GroupBuilder gb1 = new GroupBuilder()
gb1.setCriteriaColumn(columnAuthor)
gb1.addFooterVariable(columnAuthor, DJCalculation.COUNT)
DJGroup g1 = gb1.build();
As you can see, we have a new report grouped by author, and counting the number of books of every author.

The concept of group is pretty intuitive and useful. Looking at the report I would say that the Author column, which is the one used to group, should be first. This could be easily solved by changing the order when adding the columns to the report.
This is pretty interesting when working with agile methodologies, where change is always embraced and an xml template could be disturbing compared to this approach.
Let?s do the same, but ordering by Country and including a Pie Chart:
def countryComparator = [compare: {
a,b -> a.country > b.country? 1 : -1
}
] as Comparator
First I order by Country, to define the group and the chart after:
DJChartBuilder chartBuilder = new DJChartBuilder()
chartBuilder.addType(DJChart.PIE_CHART)
chartBuilder.addOperation(DJChart.CALCULATION_COUNT)
chartBuilder.addColumnsGroup(g1)
chartBuilder.addColumn(columnScore)
drb.addChart(chartBuilder.build())
Now we have made, pretty quickly, a report ordered by Country and including a Pie Chart. As you can see Argentina Authors has the higher percentage in my library, followed by USA authors.

Before moving on, I will do some refactoring!
SimpleColumn columnName = ColumnBuilder.getNew().
setColumnProperty("name", String.class.getName()).setTitle("Name").build()
SimpleColumn columnAuthor = ColumnBuilder.getNew().
setColumnProperty("author", String.class.getName()).setTitle("Author").build()
SimpleColumn columnCountry = ColumnBuilder.getNew().
setColumnProperty("country", String.class.getName()).setTitle("Country").build()
SimpleColumn columnScore = ColumnBuilder.getNew().
setColumnProperty("score", Integer.class.getName()).setTitle("Score").build()
GroupBuilder gbCountry = new GroupBuilder()
gbCountry.with {
setCriteriaColumn(columnCountry)
addFooterVariable(columnCountry, DJCalculation.COUNT)
}
DJGroup groupCountry = gbCountry.build();
GroupBuilder gbAuthor = new GroupBuilder()
gbAuthor.with {
setCriteriaColumn(columnAuthor)
addFooterVariable(columnAuthor, DJCalculation.COUNT)
}
DJGroup groupAuthor = gbAuthor.build();
DJChartBuilder chartBuilder = new DJChartBuilder()
chartBuilder.with {
addType(DJChart.PIE_CHART)
setPosition(DJChartOptions.POSITION_FOOTER)
addOperation(DJChart.CALCULATION_COUNT)
addColumnsGroup(groupAuthor)
addColumn(columnScore)
}
FastReportBuilder drb = new FastReportBuilder();
drb.with {
setTitle("My Favorite Books by Country and Author ")
setUseFullPageWidth(true)
addColumn(columnCountry)
addColumn(columnAuthor)
addColumn(columnName)
addColumn(columnScore)
addGroup(groupCountry)
addGroup(groupAuthor)
addChart(chartBuilder.build())
}
DynamicReport dr = drb.build();
def list = Book.list()
def countryComparator = [
compare: {
a,b -> a.country > b.country? 1 : -1
}
] as Comparator
JRDataSource ds = new JRBeanCollectionDataSource(list.sort(countryComparator));
JasperPrint jp = DynamicJasperHelper.generateJasperPrint(dr, new ClassicLayoutManager(), ds);
ReportWriter reportWriter = ReportWriterFactory.getInstance().getReportWriter(jp, 'PDF', [:]);
reportWriter.writeTo(response);
}
Finally, we only added some Groovy notation and a last line, where we set to export to PDF, instead of using JasperView.
There are many other options, all described on DynamicJasper?s Web Page
It is important to note that we could still define a template using Jasper, and then to integrate it. Also, defining a wide number of styles, charts, crosstabs, subreports, and so on.
What should be noticed is that DynamisJasper makes it really easy and fast to build reports with Grails, something we think was necessary to keep agility and productivity under this platform.
I would really appreciate your feedback, regarding next steps to make, as there are many possibilities to enhance this integration:
Please, for any comments or suggestions, write to me to mariano.stampella [at] fdvsolutions.com so we can make developments on these alternatives or others you may suggest.
The code has been uploaded to DynamicJaspers web. Below you have the final version of the report:

Change it, rewrite it, enhance it, but please write to me so we could all make this product grow.
Thanks in Advance,
Marian.