Back to Home

Modular library jasper-modular for JasperReports

jasper-modular library simplifies working with subreports in JasperReports through typed Java classes and annotations. Automatic JRXML and parameter generation eliminates manual data drilling. Supports nesting and collections for complex reports.

jasper-modular: modular reports in JasperReports without pain
Advertisement 728x90

Modular Library for JasperReports: Simplifying Subreports and Data

Working with large reports in JasperReports often leads to monolithic JRXML files. Design, data logic, and business rules get mixed together, making maintenance difficult. Subreports address modularity, but passing data into them introduces complexities.

Typical data approaches:

  • Single JSON: JsonDataSource with paths in XML. Path errors aren't caught at compile time, and REPORT_DATA_SOURCE is passed implicitly.
  • SQL in templates: REPORT_CONNECTION for queries. Logic resides outside Java, with no type checks.
  • Passing REPORT_DATA_SOURCE: Consumable data sources are exhausted after the first subreport.
  • Manual parameters: Dozens of <subreportParameter> and params.put() in Java, requiring synchronization.

The jasper-modular principle

The library passes two parameters into each subreport:

Google AdInline article slot
  • <prefix>Report — the compiled JasperReport.
  • <prefix>MapParameter — a Map<String, Object> containing data.

The map is unpacked via REPORT_PARAMETERS_MAP: keys become $P{key} without <subreportParameter>. An annotation processor generates parameters and JRXML during compilation. The renderer recursively populates subreports using reflection.

Adding dependencies

For JasperReports 7.x:

<dependency>
    <groupId>io.github.hhdevr</groupId>
    <artifactId>jasper-modular-starter-jr7</artifactId>
    <version>1.0.0</version>
</dependency>

For 6.x:

Google AdInline article slot
<dependency>
    <groupId>io.github.hhdevr</groupId>
    <artifactId>jasper-modular-starter-jr6</artifactId>
    <version>1.0.0</version>
</dependency>

Annotation processor in maven-compiler-plugin:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <configuration>
        <annotationProcessorPaths>
            <path>
                <groupId>io.github.hhdevr</groupId>
                <artifactId>jasper-modular-processor-jr7</artifactId>
                <version>1.0.0</version>
            </path>
        </annotationProcessorPaths>
    </configuration>
</plugin>

Report class structure

Root report:

@Getter
@Setter
@JasperModularReport(templatePath = "/reports/company_report.jrxml")
public class CompanyReport extends ModularReport {
    private TitleSubModule titleSubModule;
    private FinancialSubModule financialSubModule;
}

Subreport:

Google AdInline article slot
@Getter
@Setter
@JasperSubreport(templatePath = "/reports/sub_title_report.jrxml", prefix = "Title")
public class TitleSubModule extends SubreportModule {
    private CompanyDetails companyDetails;
    private String period;
    private String currency;

    @Override
    public boolean isEmpty() {
        return companyDetails == null;
    }
}

Nesting: FinancialSubModule contains RevenueSubModule, ExpenseSubModule, ProfitSubModule. Each module checks isEmpty() for conditional rendering.

Collections:

@JasperCollection(columnWidth = 150)
private List<RevenueItem> items;

Excluding fields:

@JasperIgnore
private transient String internalCache;

JRXML generation modes

The annotation processor updates templates in target/generated-sources/:

  • CREATE: Generates a full JRXML with parameters, datasets, collection components, and subreport bands.
  • INJECT (default): Adds missing elements while preserving existing design.
  • NONE: No changes.

After generation, templates can be refined in Jaspersoft Studio.

Sample project tree:

  • CompanyReport

- TitleSubModule (CompanyDetails, period, currency)

- FinancialSubModule

- RevenueSubModule (totalRevenue, growthPercent, List<RevenueItem>)

- ExpenseSubModule (totalExpenses, growthPercent, List<ExpenseItem>)

- ProfitSubModule (grossProfit, operatingProfit, netProfit, margin, List<ProfitBreakdown>)

Key takeaways

  • Modularity via Java classes: subreports as fields, with typed data.
  • Automatic parameter and JRXML generation by the annotation processor.
  • Recursive rendering without manual data passing.
  • Support for collections with @JasperCollection and unlimited nesting depth.
  • Compatibility with JasperReports 6.x/7.x and Spring Boot 3.x/4.x.

— Editorial Team

Advertisement 728x90

Read Next