Skip to content

jakartaee/data

Jakarta Data

Introduction

The Jakarta Data specification provides an API for easier data access to various database types, such as relational and NoSQL. A Java developer can access those repositories in several ways, including composing custom query methods on a Repository interface.

Jakarta Data’s goal is to provide a familiar and consistent, Jakarta-based programming model for data access while still retaining the particular traits and strengths of the underlying data store.

Repository

Jakarta Data provides repository abstractions designed to streamline the development of data access layers for various persistent stores, eliminating the need for extensive boilerplate code. These repository abstractions are broadly classified into two categories:

  • Built-in Repository Interfaces: Jakarta Data offers a hierarchy of built-in repository interfaces. The root of this hierarchy is the DataRepository interface, which includes several specialized interfaces like CrudRepository, BasicRepository, and more. These interfaces are designed to handle common data access operations and provide an extensible foundation for your data layer.

@Repository
public interface CarRepository extends BasicRepository<Car, Long> {

  List<Car> findByType(CarType type);

  Optional<Car> findByName(String name);

}
@Inject
CarRepository repository;
...
Car ferrari = Car.id(10L).name("Ferrari").type(CarType.SPORT);
repository.save(ferrari);
  • Custom Repository Interfaces: Besides the built-in repository interfaces, Jakarta Data enables you to create custom repository interfaces tailored to your domain requirements. These custom interfaces serve as a bridge between your domain’s semantics and the underlying database operations. With annotations like Insert, Update, Delete, and Save, you can define expressive and domain-specific repository methods that align seamlessly with your application’s needs.

@Repository
public interface Garage {

  @Insert
  Car park(Car car);

}
@Inject
Garage garage;
...
Car ferrari = Car.id(10L).name("Ferrari").type(CarType.SPORT);
repository.park(ferrari);

Whether you use built-in repository interfaces or create custom repositories, Jakarta Data empowers you to write more concise and expressive data access layers while reducing the need for boilerplate code.

Pagination

Jakarta Data supports two types of Pagination: offset and cursor-based Pagination.

  • Offset Pagination: Offset-based pagination computes pages relative to a positional offset from the beginning of the dataset given the requested page number and page size.

  • Cursor-based Pagination: Cursor-based Pagination aims to reduce missed and duplicate results across pages by querying relative to the observed values of entity properties that constitute the sorting criteria. This method uses a cursor, a pointer to a specific position in the dataset, to navigate the dataset.

Example code using both pagination methods:

@Repository
public interface CarRepository extends BasicRepository<Car, Long> {

 Page<Car> findByTypeOrderByName(CarType type, PageRequest pageRequest);

 @Find
 @OrderBy(_Car.NAME)
 @OrderBy(_Car.VIN)
 CursoredPage<Car> type(CarType type, PageRequest pageRequest);

}

Type-safe Access to Entity Attributes

Jakarta Data provides a static metamodel for type-safe access to entity attributes by applications. Given this entity class:

@Entity
public class Product {
  public long id;
  public String name;
  public float price;
}

You can leverage Jakarta Data’s static metamodel to access entity attributes in a type-safe manner, offering several advantages:

  • Compile-time Safety: By accessing entity attributes through the static metamodel (_Product), you gain compile-time safety. Any errors or mismatches in attribute names or types are detected at compile time, reducing the likelihood of runtime errors and enhancing code reliability.

  • Refactoring Support: Type-safe access to entity attributes facilitates seamless refactoring. When renaming or changing attributes in entity classes, the static metamodel ensures that all references to these attributes in your codebase are updated automatically, minimizing the risk of introducing bugs during refactoring.

  • Reduced Magic Strings: Accessing entity attributes via the static metamodel eliminates the need for using magic strings (e.g., "price", "name") directly in your code. Instead, you reference attributes using generated constants (e.g., _Product.price, _Product.name), making your code more readable, maintainable, and less error-prone.

  • Enhanced Documentation: Type-safe access to entity attributes enhances code documentation and self-documenting code practices. When reviewing code, developers can easily understand which attributes are accessed and manipulated, promoting better code understanding and collaboration.

By embracing type-safe access to entity attributes with Jakarta Data’s static metamodel, developers can write more robust, maintainable, and error-resistant code, leading to improved software quality and developer productivity.

List<Product> found = products.findByNameLike(searchPattern, Order.by(
                                              _Product.price.desc(),
                                              _Product.name.asc(),
                                              _Product.id.asc()));

Jakarta Data Query Language (JDQL)

Jakarta Data introduces the Jakarta Data Query Language (JDQL), a streamlined query language designed to specify the semantics of query methods within Jakarta Data repositories. Utilizing the @Query annotation, JDQL allows developers to define queries straightforwardly and robustly.

JDQL is conceptualized as a subset of the Jakarta Persistence Query Language (JPQL). It inherits its syntax and functionality while being specifically tailored to accommodate the broad spectrum of data storage technologies supported by Jakarta Data. This design approach ensures that JDQL remains compatible with JPQL yet simplifies its implementation across diverse data stores.

@Repository
public interface BookRepository extends BasicRepository<Book, UUID> {

  // Find books with titles matching a specific pattern
  @Query("where title like :titlePattern")
  List<Book> booksMatchingTitle(String titlePattern);

  // Select books by a specific author and sort them by title
  @Query("where author.name = :author order by title")
  List<Book> findByAuthorSortedByTitle(String author);
}

JDQL supports three primary types of statements, reflecting the core operations typically required for data manipulation and retrieval in applications:

  • Select Statements: Facilitate data retrieval from a data store, allowing for the specification of criteria to filter results.

  • Update Statements: This option enables the modification of existing records in the data store based on specified criteria.

  • Delete Statements: Allow for removing records from the data store that meet certain conditions.

This streamlined query language empowers developers to efficiently perform data access operations with minimal complexity, aligning with Jakarta Data’s objective of simplifying data access across various storage technologies.

Maven

To start to use Jakarta Data, add the API as a Maven dependency:

<dependency>
    <groupId>jakarta.data</groupId>
    <artifactId>jakarta.data-api</artifactId>
    <version>1.0.1</version>
</dependency>

Testing Guideline

This project has a testing guideline that will help you understand Jakarta Data’s testing practices. Please take a look at the TESTING-GUIDELINE file.

Code of Conduct

This project is governed by the Eclipse Foundation Community Code of Conduct. By participating, you are expected to uphold this code of conduct. Please report unacceptable behavior to [email protected].

Getting Help

Having trouble with Jakarta Data? We’d love to help!

Report Jakarta Data bugs at https://github.com/jakartaee/data/issues.

Building from Source

You don’t need to build from source to use the project, but you can do so with Maven and Java 17 or higher.

mvn package

Meetings