Quick Start
Introductionβ
A lightweight Maven library for integrating AG Grid Server-Side Mode with backend applications using JPA. This solution simplifies querying mapped entities for AG Grid and supports advanced server-side operations, including sorting, filtering, pagination, row grouping, and pivoting.
This project is under active development. Breaking changes may occur between versions.
Installationβ
Available via maven dependency
<dependency>
<groupId>io.github.smolcan</groupId>
<artifactId>ag-grid-jpa-adapter</artifactId>
<version>${ag-grid-jpa-adapter.version}</version>
</dependency>
Requirements π οΈ
- Java: Version 11 or higher.
- JPA: Version 3.1.0.
- JPA static metamodel: an annotation processor that generates the
*_metamodel classes (e.g.hibernate-jpamodelgen) β see step 2 below.
Using AG Grid JPA Adapterβ
When enabling 'serverSide' row model type in your AG Grid, you must provide datasource, which is used to fetch rows for the grid, such as:
const createDatasource = server => {
return {
// called by the grid when more rows are required
getRows: params => {
// get data for request from server
const response = server.getData(params.request);
if (response.success) {
// supply rows for requested block to grid
params.success({
rowData: response.rows
});
} else {
// inform grid request failed
params.fail();
}
}
};
}
AG Grid JPA Adapter can process the AG Gridβs request and return corresponding data using JPA abstraction, which avoids the use of native queries, ensures compatibility with multiple databases, and promotes maintainable and scalable code.
The only entrypoint you interact with is QueryBuilder, and its method getRows, which processes a ServerSideGetRowsRequest object, builds the query using JPA Criteria API, executes it and returns a LoadSuccessParams object which you can return directly to the grid.
Complete Exampleβ
1. Your JPA entity:
@Entity
@Table(name = "trade")
public class Trade {
@Id
private Long id;
private String product;
private String portfolio;
private BigDecimal currentValue;
// getters / setters
}
2. Generate the JPA static metamodel:
Columns are declared with the generated JPA static metamodel attributes (Trade_.product),
so you need a metamodel generator on your build β for example hibernate-jpamodelgen:
<annotationProcessorPaths>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
</path>
</annotationProcessorPaths>
3. Build a QueryBuilder once (e.g. in a Spring @Service):
@Service
public class TradeService {
// type parameters are <entity, id type, master-detail detail type>;
// use Void for the detail type when not using master-detail
private final QueryBuilder<Trade, Long, Void> queryBuilder;
public TradeService(@Autowired EntityManager entityManager) {
// pass the entity's @Id attribute as the second argument
this.queryBuilder = QueryBuilder.builder(Trade.class, Trade_.id, entityManager)
.colDefs(
ColDef.builder(Trade_.id).sortable(true).build(),
ColDef.builder(Trade_.product).filter(new AgTextColumnFilter()).build(),
ColDef.builder(Trade_.portfolio).filter(AgSetColumnFilter.forString()).build(),
ColDef.builder(Trade_.currentValue)
.filter(new AgNumberColumnFilter<BigDecimal>())
.enableValue(true)
// row grouping needs a converter from the string group key to the column type
.enableRowGroup(true, BigDecimal::new)
.build()
)
.build();
}
public LoadSuccessParams getRows(ServerSideGetRowsRequest request) {
return this.queryBuilder.getRows(request);
}
}
To map a column onto a related entity, build the path with FieldPath instead of a single
attribute:
ColDef.builder(FieldPath.of(Trade_.submitter).to(Submitter_.id))
.filter(new AgNumberColumnFilter<Long>())
.build()
4. Expose an endpoint:
@RestController
@RequestMapping("/api/trades")
public class TradeController {
private final TradeService tradeService;
@PostMapping("/getRows")
public LoadSuccessParams getRows(@RequestBody ServerSideGetRowsRequest request) {
return tradeService.getRows(request);
}
}
5. Point AG Grid at your endpoint:
const datasource = {
getRows: (params) => {
fetch('/api/trades/getRows', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(params.request),
})
.then(res => res.json())
.then(data => params.success({ rowData: data.rowData, rowCount: data.rowCount }))
.catch(() => params.fail());
}
};
gridApi.setGridOption('serverSideDatasource', datasource);