back to all blogsSee all blog posts

Support for Java 22 and an updated preview of Jakarta Data in 24.0.0.4-beta

image of author
David Mueller on Apr 9, 2024
Post available in languages:

The 24.0.0.4-beta release introduces support for Java SE 22 and updates for the Jakarta Data 1.0 preview, including improvements for type safety and a new @Find annotation to define repository find methods.

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

Run your Open Liberty apps with Java 22

Java 22 is the latest release of Java, released in March 2024. It contains new features and enhancements over previous versions of Java. However, Java 22 is not a long-term support (LTS) release and support for it will be dropped when the next version of Java is supported. It offers some new functions and changes that you are going to want to check out for yourself.

Check out the following feature changes in Java 22:

Take advantage of the new changes in Java 22 in Open Liberty now and get more time to review your applications, microservices, and runtime environments on your favorite server runtime!

To use Java 22 with Open Liberty, just download the latest release of Java 22 and install the 24.0.0.4-beta version of Open Liberty. Then, edit your Liberty server.env file to point the JAVA_HOME environment variable to your Java 22 installation and start testing today. The 24.0.0.4-beta release introduces beta support for Java 22. As we work toward full Java 22 support, please bear with any of our implementations of these functions that might not be ready yet.

For more information about Java 22, see the following resources:

Try out new functions for Jakarta Data 1.0 at milestone 3

Jakarta Data is a new Jakarta EE open source specification that standardizes the popular Data Repository pattern across various providers. Open Liberty 24.0.0.4-beta includes the Jakarta Data 1.0 Milestone 3 release, which introduces the static metamodel and the ability to annotatively compose Find methods.

The Open Liberty beta includes a test implementation of Jakarta Data that we are using to experiment with proposed specification features. You can try out these features and provide feedback to influence the Jakarta Data 1.0 specification as it continues to be developed. 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 3 introduces the concept of a static metamodel, which allows for more type-safe usage, and the ability to define repository find methods with the @Find annotation. To use these capabilities, 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 that is named id or ending with Id and an entity property that is 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 by using @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 boolean isDiscounted;

    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 various general-purpose repository methods for inserting, updating, deleting, and querying for entities. However, in this case, we define all of the methods ourselves by using the new life-cycle annotations.

@Repository(dataStore = "java:app/jdbc/my-example-data")
public interface Products extends BasicRepository<Product, Long> {
    @Insert
    Product add(Product newProduct);

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

    // parameter based query that does not require -parameters because it explicitly specifies the name
    @Find
    Page<Product> find(@By("isDiscounted") boolean onSale,
                       PageRequest<Product> pageRequest);

    // query-by-method name pattern:
    List<Product> findByNameIgnoreCaseContains(String searchFor, Order<Product> orderBy);

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

Observe that the repository interface includes type parameters in PageRequest<Product> and Order<Product>. These parameters help ensure that the page request and sort criteria are for a Product entity, rather than some other entity. To enable this function, you can optionally define a static metamodel class for the entity (or various IDEs might generate one for you after the 1.0 specification is released). The following example shows that you can use with the Product entity,

@StaticMetamodel(Product.class)
public class _Product {
    public static volatile SortableAttribute<Product> id;
    public static volatile SortableAttribute<Product> isDiscounted;
    public static volatile TextAttribute<Product> name;
    public static volatile SortableAttribute<Product> price;
    public static volatile SortableAttribute<Product> version;

    // The static metamodel can also have String constants for attribute names,
    // but those are omitted from this example
}

The following example shows the repository and static metamodel 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);

        // Find one entity:
        prod = products.find(productId).orElseThrow();

        // Find all, sorted:
        List<Product> all = products.findByNameIgnoreCaseContains(searchFor, Order.by(
                                     _Product.price.desc(),
                                     _Product.name.asc(),
                                     _Product.id.asc()));

        // Find the first 20 most expensive products on sale:
        Page<Product> page1 = products.find(onSale, Order.by(_Product.price.desc(),
                                                             _Product.name.asc(),
                                                             _Product.id.asc())
                                                         .pageSize(20));
        ...
    }
}

To enable the new beta feature in your app, add it to your server.xml file:

<server>
  <featureManager>
    <feature>data-1.0</feature>
    ...
  </featureManager>
  ...
<server>

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 22, 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 by using:

<plugin>
    <groupId>io.openliberty.tools</groupId>
    <artifactId>liberty-maven-plugin</artifactId>
    <version>3.10.2</version>
    <configuration>
        <runtimeArtifact>
          <groupId>io.openliberty.beta</groupId>
          <artifactId>openliberty-runtime</artifactId>
          <version>24.0.0.4-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, the following block adds dependencies for two example beta APIs:

<dependency>
    <groupId>org.example.spec</groupId>
    <artifactId>exampleApi</artifactId>
    <version>7.0</version>
    <type>pom</type>
    <scope>provided</scope>
</dependency>
<dependency>
    <groupId>example.platform</groupId>
    <artifactId>example.example-api</artifactId>
    <version>11.0.0</version>
    <scope>provided</scope>
</dependency>

Or for Gradle:

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath 'io.openliberty.tools:liberty-gradle-plugin:3.8.2'
    }
}
apply plugin: 'liberty'
dependencies {
    libertyRuntime group: 'io.openliberty.beta', name: 'openliberty-runtime', version: '[24.0.0.4-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.