back to all blogsSee all blog posts

Preview of Jakarta Data Milestone 1 in Open Liberty

image of author
Laura Cowen on Nov 28, 2023
Post available in languages:

Open Liberty contains a preview of the new Jakarta Data specification for Jakarta EE, as it currently stands at Milestone 1. Milestone 1 provides the capability to annotate lifecycle methods such as Insert, Delete, and more. You can try it out and give feedback on the specification so far.

Also in this beta, you can configure the quiesce stage when the Liberty runtime shuts down to be longer than the default 30 seconds. This update is useful for services that need more time to finish processing requests.

The Open Liberty includes the following beta features (along with all GA features):

Preview of Jakarta Data (Milestone 1)

Jakarta Data is a new Jakarta EE specification being developed in the open that aims to standardize the popular data repository pattern across a variety of providers. Open Liberty includes the Jakarta Data 1.0 Milestone 1 release, which adds the ability to annotatively compose custom lifecycle methods, covering Insert, Update, Save, and Delete operations. The Open Liberty beta includes a test implementation of Jakarta Data that we are using to experiment with proposed specification features so that developers can try out these features and provide feedback to influence the Jakarta Data 1.0 specification as it continues to be developed after Milestone 1. The test implementation currently works with relational databases and operates by redirecting repository operations to the built-in Jakarta Persistence provider.

Jakarta Data 1.0 Milestone 1 introduces the concept of annotated lifecycle methods. To use these methods, you need an entity and a repository.

Start by defining an entity class that corresponds to your data. With relational databases, the entity class corresponds to a database table and the entity properties (public methods and fields of the entity class) generally correspond to the columns of the table. An entity class can be:

  • annotated with jakarta.persistence.Entity and related annotations from Jakarta Persistence

  • a Java class without entity annotations, in which case the primary key is inferred from an entity property named id or ending with Id and an entity property named version designates an automatically incremented version column.

You define one or more repository interfaces for an entity, annotate those interfaces as @Repository and inject them into components via @Inject. The Jakarta Data provider supplies the implementation of the repository interface for you.

The following example shows a simple entity:

public class Product {
    public long id;

    public String name;

    public float price;

    public long version;

The following example shows a repository that defines operations that relate to the entity. Your repository interface can inherit from built-in interfaces, such as BasicRepository and CrudRepository, to gain a variety of general purpose repository methods for inserting, updating, deleting, and querying for entities. However, in this case, we will define all of the methods ourselves by using the new lifecycle annotations:

@Repository(dataStore = "java:app/jdbc/my-example-data")
public interface Products {
    Product add(Product newProduct);

    boolean modify(Product product);

    boolean remove(Product product);

    // parameter based query that requires compilation with -parameters to preserve parameter names
    Optional<Product> find(long id);

    // query-by-method name pattern:
    Page<Product> findByNameIgnoreCaseContains(String searchFor, Pageable pageRequest);

    // query via JPQL:
    @Query("UPDATE Product o SET o.price = o.price - (?2 * o.price) WHERE = ?1")
    boolean discount(long productId, float discountRate);

The following example shows the repository being used:

@DataSourceDefinition(name = "java:app/jdbc/my-example-data",
                      className = "org.postgresql.xa.PGXADataSource",
                      databaseName = "ExampleDB",
                      serverName = "localhost",
                      portNumber = 5432,
                      user = "${example.database.user}",
                      password = "${example.database.password}")
public class MyServlet extends HttpServlet {
    Products products;

    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // Insert:
        Product prod = ...
        prod = products.add(prod);

        // Update:
        prod.price = prod.price + 1.00;
        if (products.update(prod))
            System.out.println("Successfully increased the price.");
        else {
            // someone else either removed the product or updated its version before we could
            prod = products.find(productId).orElseThrow();

        // Request only the first 20 results on a page, ordered by price, then name, then id:
        Pageable pageRequest = Pageable.size(20).sortBy(Sort.desc("price"), Sort.asc("name"), Sort.asc("id"));
        Page<Product> page1 = products.findByNameIgnoreCaseContains(searchFor, pageRequest);

Configurable quiesce timeout for the Liberty runtime

Liberty has a quiesce stage when shutting down the Liberty runtime, which prevents services from accepting new requests and allows time for services to process existing requests. The quiesce stage has always been a fixed 30 seconds time period. This quiesce time period is now configurable.

Previously, in some cases, the 30-seconds quiesce period was not long enough time for services to finish processing existing requests. So you can now increase the quiesce timeout if necessary.

To configure the quiesce timeout, add the new quiesceTimeout attribute to the executor element in the server.xml file:

<executor quiesceTimeout=1m30s/>

The timeout value is a positive integer followed by a unit of time, which can be hours (h), minutes (m), or seconds (s). For example, specify 30 seconds as 30s. You can include multiple units in a single entry. For example, 1m30s is equivalent to 90 seconds. The minimum quiesceTimeout value is 30 seconds. If you specify a shorter length of time, the value 30s is used.

Try it now

To try out these features, update your build tools to pull the Open Liberty All Beta Features package instead of the main release. The beta works with Java SE 21, Java SE 17, Java SE 11, and Java SE 8.

If you’re using Maven, you can install the All Beta Features package using:


You must also add dependencies to your pom.xml file for the beta version of the APIs that are associated with the beta features that you want to try. For example, for Jakarta EE 10 and MicroProfile 6, you would include:


Or for Gradle:

buildscript {
    repositories {
    dependencies {
        classpath ''
apply plugin: 'liberty'
dependencies {
    libertyRuntime group: 'io.openliberty.beta', name: 'openliberty-runtime', version: '[,)'

Or if you’re using container images:


Or take a look at our Downloads page.

If you’re using IntelliJ IDEA, Visual Studio Code or Eclipse IDE, you can also take advantage of our open source Liberty developer tools to enable effective development, testing, debugging and application management all from within your IDE.

For more information on using a beta release, refer to the Installing Open Liberty beta releases documentation.

We welcome your feedback

Let us know what you think on our mailing list. If you hit a problem, post a question on StackOverflow. If you hit a bug, please raise an issue.