The imminent release of Jakarta EE 11 is an exciting development for the Java community. Numerous and substantial updates will make the platform work better and easier to use, emphasising the overall themes of performance and developer productivity.
While much of the release constitutes updates to existing specifications to either improve their performance or help make developers more productive, the Jakarta Data Specification is wholly new to Jakarta EE, and is on the cusp of its 1.0 release.
In this article, we’ll explain how the Jakarta Data Specification works and how it aligns with the two primary themes of the Jakarta EE 11 release.
Familiar and Consistent Access to Jakarta Data
The Jakarta Data Specification provides a familiar and consistent programming model for accessing data based on Jakarta EE, while also allowing developers to preserve the unique characteristics and strengths of the underlying data store.
The specification offers an API that makes accessing various types of databases, including relational and NoSQL databases, easier. Java developers can access these repositories in multiple ways by creating custom query methods on a Repository interface.
The goal is not to use SQL as a NoSQL database or vice versa but to have an API that abstracts the behaviour that both use within the persistence layer.
Eliminating Boilerplate Code for Data Access Layers
The first version of the specification addresses the repository pattern that provides repository abstractions. It is designed to streamline the development of data access layers for various persistent stores, eliminating the need for extensive boilerplate code.
We won’t cover modifications of this pattern in this article, but if you want to learn more, please check out Eric Evans’ book, Domain-Driven Design: Tackling Complexity in the Heart of Software.
Repository Abstractions Can Be Built-In or Custom
The Jakarta Data Specification broadly classifies repository abstractions in two categories: built-in repository interfaces and custom repository interfaces.
Built-in repository interfaces include several specialised interfaces like CrudRepository
and BasicRepository
. 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);
}
However, developers also have the option to create their own interface and define vocabulary and terminology. This can be done to make the interface domain-centric or can be used to explore more ubiquitous language.
My favourite example is a repository to handle cars, where we can have a Garage and define methods to insert a Car into the database.
@Repository
public interface Garage {
@Insert
Car park(Car car);
}
Access Database Via Querying, Inserting, Updating, and Deleting
The repository also offers several ways to explore and interact with the database, including querying, inserting, updating, and deleting. These operations happen through various annotations, including action annotations, method-by-query, and Jakarta Data Query Language (JDQL).
Four main action annotations allow users to define specific actions: @Insert
, @Delete
, @Update
, and @Find
.
@Insert
Car park(Car car);
Method-by-query annotations allow users to use standard terminology to perform queries:
List<Product> findByType(ProductType type);
JDQL is a streamlined query language designed to specify the semantics of query methods within Jakarta Data repositories. Using the @Query annotation, JDQL allows developers to define queries in a straightforward and robust way:
@Query("where author.name = :author order by title")
List<Book> findByAuthorSortedByTitle(String author);
Specification Supports Both Offset and Cursor Pagination
Also worth noting is that the Jakarta Data Specification supports both offset and cursor pagination. As such, whether you’re working on a simpler, smaller dataset or a larger, more complex one, you can use the pagination method best suited to the task at hand.
Jakarta Data Supports But Doesn’t Unify SQL and NoSQL
Of note, however, is that the Jakarta Data specification does not unify the SQL and NoSQL database types. There are a few reasons for this, not least of which are that there are already existing specifications that tackle this challenge, such as Jakarta Persistence and Jakarta NoSQL. And because unifying these types of databases does represent a significant challenge, it is beyond the scope of what we’re trying to accomplish with this specification.
Our goal is to instead focus on enhancing and exploring the persistence layer by covering both database types, leveraging their unique strengths, and providing a consistent and familiar programming model for data access.
We hope you found this overview of the Jakarta Data Specification useful and helpful. You can find more information about it, including a comprehensive breakdown of the specification, here.