Preview of Jakarta Data Milestone 1 in Open Liberty 23.0.0.12-beta
Open Liberty 23.0.0.12-beta 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 23.0.0.12-beta includes the following beta features (along with all GA features):
See also previous Open Liberty beta blog posts.
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 withId
and an entity property namedversion
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:
@Entity
public class Product {
@Id
public long id;
public String name;
public float price;
@Version
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 {
@Insert
Product add(Product newProduct);
@Update
boolean modify(Product product);
@Delete
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 o.id = ?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 {
@Inject
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:
<plugin>
<groupId>io.openliberty.tools</groupId>
<artifactId>liberty-maven-plugin</artifactId>
<version>3.9</version>
<configuration>
<runtimeArtifact>
<groupId>io.openliberty.beta</groupId>
<artifactId>openliberty-runtime</artifactId>
<version>23.0.0.12-beta</version>
<type>zip</type>
</runtimeArtifact>
</configuration>
</plugin>
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:
<dependency>
<groupId>org.eclipse.microprofile</groupId>
<artifactId>microprofile</artifactId>
<version>6.0-RC3</version>
<type>pom</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jakarta.platform</groupId>
<artifactId>jakarta.jakartaee-api</artifactId>
<version>10.0.0</version>
<scope>provided</scope>
</dependency>
Or for Gradle:
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'io.openliberty.tools:liberty-gradle-plugin:3.7'
}
}
apply plugin: 'liberty'
dependencies {
libertyRuntime group: 'io.openliberty.beta', name: 'openliberty-runtime', version: '[23.0.0.12-beta,)'
}
Or if you’re using container images:
FROM icr.io/appcafe/open-liberty:beta
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.