Evaluate structured code in JasperReports

JasperReports is a library which can be used to fill reports from Java applications or just create simple PDFs. It allows you to not only use static output strings but also Groovy expressions. Sadly, this is restricted to simple expressions that result in a value and don't generate multiple class files at compile time.

For example, you could use the following expression to print different values depending if your document has more or less than 10 pages:

$V{PAGE_COUNT} < 10 ? "foo" : "bar"

But when you have to loop over values you'll face a problem as you have no possibility to define own methods. Even the usage of closures (Groovy) or anonymous inner classes (Java) is prohibited as Jasper expects every expression to result in one single class file.

Of course you could extend the class path or use Scriptlets for this, but this requires you to ship the compiled class together with the report library.

Using the power of groovy there is a way to work around this: compile your expression at runtime! The following code will calculate the faculty of the number of pages:

  1. new GroovyClassLoader().parseClass('''
  2. def static fac(x) {
  3. def res = 1;
  4. 1.upto(x) {
  5. res *= it
  6. }
  7. return res
  8. }
  9. ''').fac($V{PAGE_COUNT})

The first line creates a new instance of the GroovyClassLoader, parses the code given in the following multiline string expression and executes the method "fac(x)" defined statically before.

To prove the power of this method the following code will embed a recursive listing of your home directory in your report:

  1. new GroovyClassLoader().parseClass('''
  2. def static list(path, prefix) {
  3. String result = ""
  4. path.listFiles().each() {
  5. result += prefix + it.name + "\\n"
  6. result += list(it, prefix + " ")
  7. }
  8. return result
  9. }
  10. ''').list(new File(System.getProperty("user.home")), "")

Remember that you have to double-escape backslashes as the first escape will be handles by the Jasper compiler.

Another possibility (and the reason why I researched at this topic) is that this method allows you to generate images at runtime and use the full power of the JFreeChart library used by Jasper itself.

Comments

Hi.

The Groovy evaluation works very well.
How can i do the same with javascript and beanshell?
When i switch the language to Java and try the following expression,
an error apears.

new Object(){
public String test(){
return "Hallo Jasper";
}
}.test()

ERROR:
java.lang.NoClassDefFoundError: Blank_A4_1382728693175_542805 (wrong name: Blank_A4_1382728693175_542805$3)

Any idea?

Add new comment