Straightforward Data Access with Jakarta Data and the Oracle Database

Juarez Junior
Oracle Developers
Published in
8 min readOct 7, 2024

by Juarez Junior

Introduction

A previous blog post explained how to connect to an Oracle Database instance from a Spring Data JDBC application. This blog post will further explore this topic by combining Jakarta Data with JDBC.

As you may know, Jakarta Data is a specification under the Jakarta EE umbrella that aims to simplify the development of data-driven applications. One of the main benefits of using Jakarta Data is that it offers a high-level abstraction to support working with relational databases, simplifying data access, and reducing boilerplate code through a standardized, consistent Java API.

Besides, it follows the same design patterns used in other ORM / data access frameworks, such as supporting the Repository pattern, which allows developers to leverage code implemented automatically by the underlying framework. Last but not least, it’s interesting to mention that it’s also fully extensible and provides easy interplay with other specifications belonging to the Jakarta EE ecosystems.

This blog post will explore a scenario using Jakarta Data and the Oracle Database. So, without further ado, let’s get started!

Prerequisites

Run an Oracle Database 23ai Free instance on Docker

Assuming that you already know how to run an Oracle Database 23ai Free instance on Docker as explained in a previous blog post, run the command below from the Windows Command Prompt (cmd):

docker run -d -p 1521:1521 -e ORACLE_PASSWORD=<your password> -v oracle-volume:/opt/oracle/oradata gvenzl/oracle-free

Replace <your password> above with your chosen password as required.

Note that you also have to prepare a directory called oradata to persist data with the oracle-volume as shown above.

If everything goes well, you can run the command docker ps -al to confirm that your Docker container is up and running with the Oracle Database 23ai Free instance as expected.

Oracle Database 23ai Free — up and running

Connect to Oracle Database 23ai Free

The next step is to connect to Oracle Database 23ai to run the required DDL script. Please follow the instructions in this blog post, which covers how to do so with the IntelliJ IDEA tool.

Alternatively, you can also use Oracle SQL Developer, a free tool that simplifies the development and management of Oracle Databases in traditional and cloud deployments, or any other tool you might prefer.

Connect to your DB 23ai Free instance and run the DDL script

Now, you must connect to the DB 23ai Free database instance and execute the DDL script —jakarta-data-oracle.sql — to create the tables for our sample Jakarta Data application.

Open the Oracle SQL Developer tool as explained previously, copy the DDL script from the Gist below — and execute it as required by clicking the Run Statement button.

OpenLiberty’s server.xml file

Now, you must adjust the connection details to the DB 23ai Free database instance. The target file is server.xml under /src/main/liberty/config, and it has the Oracle Database connection details. Adjust the values accordingly, according to your environment.

Oracle DB connection details — server.xml file

You must adjust your Oracle Datasource configuration with your own database/JDB connection details as expected. If you prefer, you can set those as environment variables under Windows or Linux, for example.

Note that the password is highlighted. Make sure the password for the Oracle DB follows Oracle’s requirements for DB passwords.

The Jakarta Data with Oracle Database app

It’s beyond the scope of this blog post to teach you about Jakarta Data 1.0, which is part of Jakarta EE 11. If you want to explore Jakarta Data, I advise you to follow my friend and fellow Brazilian Otavio Santana, who’s leading the Jakarta Data efforts.

This blog post's goal is to show you how to easily connect your Jakarta Data project to an Oracle Database 23ai Free instance.

This provides an overview of the code sample’s main components so you can understand what to expect it to do.

Below, we have listed the project components, which are also highlighted in the screenshot that follows.

Code sample — application components

The main application components and architecture are quite simple. First, it has a usual entry point (main) class, which extends Jakarta.ws.rs.core. The application, as expected, is MartialArtApplication.java. Note that it also sets the application’s path to /ww.

package com.oracle.dev.jdbc;

import jakarta.ws.rs.ApplicationPath;
import jakarta.ws.rs.core.Application;

@ApplicationPath("/ww")
public class MartialArtApplication extends Application {
}

Next, a couple of classes to declare both a REST endpoint (Resource with MartialArtResource.java).

package com.oracle.dev.jdbc;

import java.util.List;

import jakarta.inject.Inject;
import jakarta.ws.rs.Consumes;
import jakarta.ws.rs.DELETE;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;

@Path("/martialarts")
public class MartialArtResource {

@Inject
private MartialArtRepository martialArtRepository;

@POST
@Consumes(MediaType.APPLICATION_JSON)
public Response addMartialArt(MartialArt martialArt) {
return Response.ok(
"Added martial art: " + martialArtRepository.save(martialArt).getId())
.build();
}

@DELETE
@Path("/{id}")
@Produces(MediaType.TEXT_PLAIN)
public Response deleteById(@PathParam("id") Long id) {
martialArtRepository.deleteById(id);
return Response.ok("Deleted martial art with ID: " + id).build();
}

@GET
@Path("/{name}")
@Produces(MediaType.TEXT_PLAIN)
public String findOne(@PathParam("name") String name) {
return martialArtRepository.findByNameIgnoreCase(name)
.map(MartialArt::getCountry).orElse(name + " not found");
}

@GET
@Produces(MediaType.APPLICATION_JSON)
public List<MartialArt> findAll() {
return martialArtRepository.findAll().toList();
}

}

And a Java Persistence (Repository with MartialArtRepository.java) component, so again no tricks here. Note how simple and straightforward it is to use the Repository pattern with Jakarta Data by simply creating an interface that extends the jakarta.data.repository.CrudRepository OOTB interface.

package com.oracle.dev.jdbc;

import java.util.Optional;

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

@Repository
public interface MartialArtRepository extends CrudRepository<MartialArt, Long> {
Optional<MartialArt> findByNameIgnoreCase(String name);
void deleteById(Long id);
}

Last, we have our target entity class, which is tagged with the Entity annotation (Jakarta.persistence.Entity) as usual. The entity class is MartialArt.java.

package com.oracle.dev.jdbc;

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

@Entity
public class MartialArt {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String country;

public MartialArt() {
}

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

}

Java Persistence Unit configuration with persistence.xml

One last important file to mention is persistence.xml under /src/main/resources/META-INF

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<persistence xmlns="https://jakarta.ee/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/persistence https://jakarta.ee/xml/ns/persistence/persistence_3_0.xsd"
version="3.0">
<persistence-unit name="OraclePu"
transaction-type="JTA">
<jta-data-source>OracleDataSource</jta-data-source>
</persistence-unit>
</persistence>

It has the Java Persistence Unit declaration, with its defined name as OraclePu, and the associated JTA Data Source child element (OracleDataSource), which points to the declared data source configured with server.xml (OracleDataSource), as explained above.

Run the Jakarta EE / Data application locally

Change to the root directory of your project, and run the Maven command below as usual. Run the commands below.

cd C:\java-projects\jakarta-data-oracle-db
mvn clean package

cd C:\java-projects\jakarta-data-oracle-db
mvn liberty:run

You will see some messages logged by Jakarta EE confirming that your server is up and running and awaiting to server HTTP requests. Take note of your specific HTTP port and adjust the URLs accordingly if needed.

Jakarta Data app started with OpenLiberty

Test the Jakarta Data app from a browser

Provided that your application has started successfully, you can now test it. First, let’s add some records to the database table. Run the HTTP POST requests below with curl.

curl -X POST -H "Content-Type: application/json" http://localhost:9082/jakarta-data-oracle-db/ww/martialarts -d '{"country":"China", "name":"KungFu"}'
curl -X POST -H "Content-Type: application/json" http://localhost:9082/jakarta-data-oracle-db/ww/martialarts -d '{"country":"Brazil", "name":"BJJ"}'
curl -X POST -H "Content-Type: application/json" http://localhost:9082/jakarta-data-oracle-db/ww/martialarts -d '{"country":"Brazil", "name":"Capoeira"}'

If everything is working properly, the records will be inserted with no errors as expected, and you will see the respective IDs of each entity returned as part of the related HTTP responses.

Entities persisted — returned entity IDs

So, you can now perform the HTTP GET request below to retrieve your persisted data. For your convenience, you can also run the HTTP requests from a web browser such as http://localhost:9082/jakarta-data-oracle-db/ww/martialarts/, and you will see the database records returned as JSON, as below.

HTTP response — persisted entities

Of course, you can also get the record of a specific entity only, examples are listed below:

http://localhost:9082/jakarta-data-oracle-db/ww/martialarts/kungfu
http://localhost:9082/jakarta-data-oracle-db/ww/martialarts/bjj
http://localhost:9082/jakarta-data-oracle-db/ww/martialarts/capoeira

Last but not least, you can also delete a given entity. Here's another example with curl to finalize it all.

curl -X DELETE http://localhost:9082/jakarta-data-oracle-db/ww/martialarts/3

Wrapping it up

That’s it! You learned how to use Java Persistence with Jakarta EE 1 and Jakarta Data 1.0, along with the specific Oracle Datasource configurations, the Oracle JDBC Driver, and the Java project t implementation with all its main basic components.

As we focused on Jakarta Data, persistence was at the core of this example implementation. It provided an easy implementation of the Repository pattern as supported by Jakarta Data connected to an Oracle Database 23ai instance. I hope you enjoyed this blog post, so stay tuned!

References

Jakarta EE

Jakarta EE 11 API — Javadocs

Jakarta Persistence 3.1

MicroProfile 6.1

OpenLiberty.io

Oracle Database 23ai

Oracle Database Free Release 23ai — Container Image

Oracle® Database JDBC Java API Reference, Release 23ai

Oracle JDBC Driver 23ai (23.4.0.24.05) — Maven Central

Developers Guide For Oracle JDBC on Maven Central

Oracle UCP (Universal Connection Pool) — Developer’s Guide

Develop Java applications with Oracle Database

Oracle Developers and Oracle OCI Free Tier

Join our Oracle Developers channel on Slack to discuss Java, JDK, JDBC, GraalVM, Microservices with Spring Boot, Helidon, Quarkus, Micronaut, Reactive Streams, Cloud, DevOps, IaC, and other topics!

Build, test, and deploy your applications on Oracle Cloud — for free! Get access to OCI Cloud Free Tier!

--

--

Oracle Developers
Oracle Developers

Published in Oracle Developers

Aggregation of articles from Oracle engineers, Groundbreaker Ambassadors, Oracle ACEs, and Java Champions on all things Oracle technology. The views expressed are those of the authors and not necessarily of Oracle.

No responses yet