ProjectionQuery builds dynamic Jakarta Persistence queries and maps selected fields to Java records or DTOs. Use it directly with an EntityManager or through Spring Boot auto-configuration.
The core requires Java 17+ and a configured JPA/Hibernate environment. It does not require Spring. Result types use Java generics, while property paths are strings resolved at runtime.
The project is split into multiple modules:
Project Repository: https://github.com/juliocmbueno/jb-projects-projection-query
These examples use version 3.6.0, as declared in this repository. Configure your entity mappings, database connection, and JDBC driver before executing queries. The Spring dependency includes the core module transitively.
<dependency>
<groupId>io.github.juliocmbueno</groupId>
<artifactId>projection-core</artifactId>
<version>3.6.0</version>
</dependency>
<dependency>
<groupId>io.github.juliocmbueno</groupId>
<artifactId>projection-spring-data</artifactId>
<version>3.6.0</version>
</dependency>
First, define the result shape for an existing Customer entity.
@Projection(of = Customer.class)
public record CustomerBasicData(
@ProjectionField Long id,
@ProjectionField String name,
@ProjectionField("address.city.name") String city,
@ProjectionField("address.city.state.name") String state
) { }
In the following examples, we assume a JPA context in which the
ProjectionProcessorreceives anEntityManagerinstance, responsible for executing the queries.
1. Example using a projection class:
ProjectionProcessor processor = new ProjectionProcessor(entityManager);
List<CustomerBasicData> customers = processor.execute(CustomerBasicData.class);
2. Example using a fully configured ProjectionQuery:
ProjectionProcessor processor = new ProjectionProcessor(entityManager);
ProjectionQuery<Customer, CustomerBasicData> query = ProjectionQuery
.fromTo(Customer.class, CustomerBasicData.class)
.filter("address.city.name", ProjectionFilterOperator.EQUAL, "São Paulo")
.order("name", OrderDirection.ASC)
.paging(0, 20)
.distinct();
List<CustomerBasicData> customers = processor.execute(query);
3. Example using ProjectionPage result:
ProjectionProcessor processor = new ProjectionProcessor(entityManager);
ProjectionQuery<Customer, CustomerBasicData> query = ProjectionQuery
.fromTo(Customer.class, CustomerBasicData.class)
.paging(0, 20);
ProjectionPage<CustomerBasicData> page = processor.executePageable(query);
This is a basic introduction. More advanced topics such as specifications, complex filters, sorting, pagination, and integration with Spring Data JPA are covered in the next sections.