Getting Started with Jakarta Data API

Jakarta Data API is a powerful specification that simplifies data access across a variety of database types, including relational and NoSQL databases. In this article you will learn how to leverage this programming model which will be part of Jakarta 11 bundle.

Overview of Jakarta Data API

Jakarta.Data API: Offers a higher-level abstraction for data access across various persistence mechanisms, including relational databases (handled by Jakarta.Persistence) and NoSQL databases (potentially using Jakarta.NoSQL underneath). It aims to simplify data access by providing a consistent API regardless of the underlying data store.

For example, here is the traditional way to mapping a Database Table with Jakarta Persistence API:

import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;

@Entity
public class Car {

    @Id
    @GeneratedValue
    private int id;
    private Integer power;
    private String model;
 
}

On the other hand, you can also map a NoSQL structure (such as a MongoDB Collection with jakarta.nosql.Entity:

import jakarta.nosql.Column;
import jakarta.nosql.Entity;
import jakarta.nosql.Id;

@Entity
public class Product {

    @Id
    private String id;

    @Column
    private String name;
}

A Java developer can now use both Entity objects with Jakarta.Data offers a broader scope, handling both relational and NoSQL databases with a unified API. You can do so by including a Repository interface which acts as a layer of abstraction between your application logic and the underlying persistence mechanism

Understanding the Repository Interface

A repository is an interface annotated with the Repository annotation. A Repository derives from the DataRepository interface, which includes several specialized interfaces like CrudRepository, BasicRepository, and more. For example, the following ProductRepository Class extends jakarta.data.repository.CrudRepository:

import jakarta.data.repository.CrudRepository;
import jakarta.data.repository.Repository;

import java.util.List;

@Repository
public interface ProductRepository extends CrudRepository<Product, String> {

}

You can then inject the Repository interface in your applications via the jakarta.inject.Inject annotation. For example:

 @Inject
 ProductRepository repository;

 ...
 @POST
 public void insert(Product product) {
     repository.save(product);
 }
 @GET
 public List<Product> getProducts() {
     repository.findAll().toList();
 }

Defining Custom repository Interfaces

Besides extending the built-in repository interfaces, Jakarta Data lets you define custom repository interfaces. These custom interfaces can map the standard Data operations with annotations like Insert, Update, Delete, and Save. For example:

@Repository
public interface CustomProductRepository {

    @Insert
    Product add(Product product);

    @Find
    Optional<Product> get(String productNum);

    @Update
    Product modify(Product product);

    @Delete
    boolean remove(Product product);

    @Save
    void save(Product product);

}

The above CustomProductRepository shows an example on how top map the commin @Insert @Find @Update @Delete and @Save Operations with a custom Repository interface.

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.

For example:

@Repository
public interface ProductRepository extends BasicRepository<Product, String> {

  // Find products with names matching a specific pattern (like with wildcards)
  @Query("where name like :namePattern")
  List<Product> findProductsByName(String namePattern);

  // Find products by category and sort them by name (ascending)
  @Query("where description like :category order by name asc")
  List<Product> findByCategorySortedByName(String category);
}

This example demonstrates how you can use JDQL with the ProductRepository interface:

  • The first query (findProductsByName) retrieves a list of products where the name matches the namePattern (using the like operator for pattern matching).
  • The second query (findByCategorySortedByName) finds products based on their description containing the provided category and sorts the results by name in ascending order (asc).

Building and deploying Jakarta Data in your applications

In order to build an application which uses Jakarta Data API you need to include the following Maven dependency:

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

Please note that Jakarta Data is part of Jakarta EE 11 which is not yet available in the GA release. However, you can still have a preview of it in some application server such as OpenLiberty. Moreover, some features of Jakarta EE 11 will be available in WildFly 32 so stay tuned as we will soon provide a quickstart for it!

Conclusion

Jakarta Data API in Jakarta EE 11 offers a powerful and versatile approach to data access across various persistence mechanisms. It streamlines data access by providing a consistent API regardless of the underlying data store (relational databases, NoSQL databases, etc.). Remember, Jakarta Data API is an evolving technology, so stay tuned for future enhancements and embrace its potential to simplify and empower your data access strategies in Jakarta EE 11 applications.