Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Issue_668] Jakarta Data blog post #670

Merged
merged 1 commit into from
Oct 11, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 227 additions & 0 deletions _posts/2024-10-10-jakarta-data.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
---
layout: post
title: "Introducing Jakarta Data in WildFly Preview"
date: 2024-10-10
tags: wildfly jakarta hibernate
author: bstansberry
description: Learn about the support for Jakarta Data in WildFly Preview 34
---

= Introducing Jakarta Data in WildFly Preview

I'm excited that in the 34 Beta release we were able to introduce support for link:https://jakarta.ee/specifications/data/1.0/[Jakarta Data, window=_blank] into WildFly Preview. It was a bit of an unexpected last minute thing that we were able to do this, which left us without time to much in the way of documentation. We'll correct that for WildFly 35, but in the meantime I'll use this blog post as a way to introduce the basics.

NOTE: In the 34 release, Jakarta Data is only available in WildFly Preview, and not in standard WildFly. It is provided at the link:https://docs.wildfly.org/33/Admin_Guide.html#Feature_stability_levels[`preview` stability level, window=_blank], which is enabled out-of-the-box in WildFly Preview.

== Jakarta Data Overview

My purpose in this post isn't to dive much into the details of Jakarta Data itself; there are other resources that do a good job of covering that. I want to focus here on how the WildFly Preview and Hibernate ORM integration of Jakarta Data works, so users can get going with using Jakarta Data in a WildFly server. So this next bit is very brief and high level.

Jakarta Data brings the repository pattern to the Jakarta ecosystem. As explained in the link:https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0#architecture[Jakarta Data 1.0 Specification, window=_blank]

[quote]
____
a repository is a mediator between an application’s domain logic and the underlying data storage, be it a relational database, NoSQL database, or any other data source.

In Jakarta Data, a Repository provides a structured and organized way to interact with data. It abstracts data storage and retrieval complexities, allowing you to work with domain-specific objects and perform common operations on data without writing low-level database queries.
____

An application developer defines a repository by providing an interface annotated with the Jakarta Data `@Repository` annotation. The repository interface declares methods used for data retrieval and modification of a particular link:https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0#_entity_classes[entity type, window=_blank]. A repositoy interface can include different methods that deal with different entity types, giving application authors flexibility to define repositories that fit the needs of their application domain.

Following is an example repository:

[source,java]
----
@Repository
interface Publishing {
@Find
Book book(String isbn);

@Find
Author author(String ssn);

@Insert
void publish(Book book);

@Insert
void create(Author author);

// query methods
...
}
----

`Book` and `Author` are typical entity classes.

The repository interface methods are annotated with various Jakarta Data annotations (`@Insert`, `@Find`, etc) that define the expected persistence behavior of the method.

There's much more to the Jakarta Data programming model than this; for all the details see:

* The link:https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0[Jakarta Data 1.0 specification, window=_blank]
* The link:https://docs.jboss.org/hibernate/orm/6.6/repositories/html_single/Hibernate_Data_Repositories.html[Hibernate Data Repositories documentation, window=_blank]
* Gavin King's excellent link:https://in.relation.to/2024/04/01/jakarta-data-1/[blog posts, window=_blank] on Jakarta Data


A Jakarta Data implementation like WildFly Preview can support one or more Jakarta Data link:https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0#_jakarta_data_providers[providers, window=_blank]. A provider understands one or more Java annotation types that are used to define entities, and it understands how to interact with a particular type of back end datastore.

WildFly Preview's Jakarta Data implementation supports the link:https://docs.jboss.org/hibernate/orm/6.6/repositories/html_single/Hibernate_Data_Repositories.html[Hibernate Data Repositories, window=_blank] provider, which uses Hibernate ORM to interact with a variety of different relational databases. Hibernate Data Repositories supports the `jakarta.persistence.Entity` annotation as the mechanism for application authors to define entities.

== Using Hibernate Data Repositories in Your Application

There are two key things to understand in order to use WildFly Preview's Hibernate Data Repositories provider:

* How to configure build time generation of the implementation of your `@Repository` interfaces.
* How to configure the runtime behavior of the Hibernate ORM instance that will interact with the database.


=== Build-time Generation of Repository Implementations

An application author using Jakarta Data simply writes an interface for their repository, but of course for that to work at runtime there must be an actual implementation of that interface. It's the responsibility of the Jakarta Data provider to provide that implementation. Hibernate Data Repositories does this by generating the implementation classes as part of the build of your application.

So, _to use Jakarta Data with WildFly Preview you need to configure the generation of those classes as part of your application build_. In a Maven build this is done by configuring the Maven compiler plugin to use the `org.hibernate.orm:hibernate-jpamodelgen` artifact as an annotation processor:

[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 3.12 or later is necessary for proper dependency management in annotationProcessorPaths -->
<version>3.12.1</version>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
----

Note that there is no version element in the `org.hibernate.orm:hibernate-jpamodelgen` declaration above. You could provide one, but best practice is to control the version in your pom's `dependencyManagement`. Importing the `org.wildfly.bom:wildfly-ee-preview-with-tools` BOM lets you align the version of Hibernate artifacts with what's used in your target WildFly Preview runtime:

[source,xml]
----
<dependencyManagement>
<dependencies>
<!-- importing the ee-with-tools BOM adds specs and other useful artifacts as managed dependencies -->
<dependency>
<groupId>org.wildfly.bom</groupId>
<artifactId>wildfly-ee-preview-with-tools</artifactId>
<version>34.0.0.Beta1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
----

WARNING: Some users may have learned to configure Hibernate annotation processing by declaring `org.hibernate.orm:hibernate-jpamodelgen` as a `provided` dependency in their pom. With the Hibernate version used with WildFly, link:https://docs.jboss.org/hibernate/orm/6.3/migration-guide/migration-guide.html#metamodel-generation[this will likely fail, window=_blank]. Use the `maven-compiler-plugin` configuration approach described above.

If you're using Gradle, you'll need to use `annotationProcessor`:

[source,groovy]
----
annotationProcessor 'org.hibernate.orm:hibernate-jpamodelgen:6.6.1'
----

The generated repository implementation classes internally use various Hibernate ORM classes, so to compile the generated code you'll need to add a dependency on Hibernate:

[source,xml]
----
<dependencies>
<dependency>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-core</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
----

=== Configuring Hibernate ORM

Under the covers, your repository implementation will use Hibernate ORM to interact with the database. You configure ORM by providing a `META-INF/persistence.xml` file, the same as you would with a Jakarta Persistence application:

[source,xml]
----
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">

<persistence-unit name="Publisher">

<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<properties>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.show_sql" value="false"/>
</properties>

</persistence-unit>

</persistence>
----

The `jta-data-source` value should match the value of the `jndi-name` attribute in a datasource you've declared in the WildFly Preview `datasources` or `datasources-agroal` subsystem configuration.


== Configuring WildFly Preview to Support Jakarta Data

Jakarta Data in WildFly Preview is configured using the new `jakarta-data` subsystem. This subsystem isn't included in any of WildFly Preview's out-of-the-box configuration files, so to use it you'll need to add it to your configuration.

If you're using a complete WildFly Preview installation, like the ones available from the https://wildfly.org/downloads[WildFly downloads page, window=_blank], then you can use the JBoss CLI to add the Jakarta Data extension and subsystem to your configuration:

[source]
----
$ /extension=org.wildfly.extension.jakarta.data:add
$ /subsystem=jakarta-data:add
----

If you're using Galleon to provision a slimmed WildFly Preview installation, you'll need to specify the `jakarta-data` Galleon layer. For example if you are using the WildFly Maven Plugin to provision a server that supports a Jakarta REST application interacting with a Postgresql database, the configuration in your application's pom.xml might look like this:

[source,xml]
----
<build>
<plugins>
<plugin>
<groupId>org.wildfly.plugins</groupId>
<artifactId>wildfly-maven-plugin</artifactId>
<configuration>
<feature-packs>
<feature-pack>
<location>wildfly-preview@maven(org.jboss.universe:community-universe)</location>
</feature-pack>
<feature-pack>
<groupId>org.wildfly</groupId>
<artifactId>wildfly-datasources-preview-galleon-pack</artifactId>
<version>8.0.1.Final</version>
</feature-pack>
</feature-packs>
<layers>
<layer>jaxrs-server</layer>
<layer>jakarta-data</layer>
<layer>postgresql-datasource</layer>
</layers>
</configuration>
<executions>
<execution>
<goals>
<goal>package</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
----

The subsystem itself is very simple and doesn't expose any configuration attributes.

Note that for the `jakarta-data` subsystem to work, the `jpa` subsystem must be present in your configuration. It's present in our out-of-the-box configurations and will be included if you provision a server using the `jakarta-data` Galleon layer.


Please try out Jakarta Data in WildFly Preview and give us your feedback! We'll continue to work on the integration, with a goal of including it in standard WildFly in one of the next couple of releases.