The Jakarta EE ecosystem offers specifications for building database backend applications using relational and/or NoSQL databases. The Jakarta Persistence specification, with a rich history dating back almost 20 years, has been a staple in the Java community for writing relational database applications. The Jakarta NoSQL specification, with a short history dating back to 2020, provides comprehensive support for all four types of NoSQL databases.
The Jakarta EE ecosystem offers specifications for building database backend applications using relational and/or NoSQL databases. The Jakarta Persistence specification, with a rich history dating back almost 20 years, has been a staple in the Java community for writing relational database applications. The Jakarta NoSQL specification, with a short history dating back to 2020, provides comprehensive support for all four types of NoSQL databases.
Along with an overview of each specification, this guide provides an example application, the required dependencies and configuration, an explanation of the most frequently used annotations for connecting to a relational or NoSQL database, its current status, and compatible implementations.
The Jakarta EE Adopt-a-Spec initiative encourages Java User Groups (JUGs) and their members to get involved by adopting a Jakarta EE specification. The objective is to increase developer-level participation in the evolution of a Jakarta EE specification. There are currently eight Java User Groups that have adopted various Jakarta EE specifications. The JUGs that have adopted Jakarta NoSQL and Jakarta Persistence will be listed here as well.
For both Jakarta Persistence and Jakarta NoSQL, we will use a model of a
carsdb
MySQL and MongoDB databases, with tables/collections named cars
and
dealers
, that store information about various cars and dealerships that sell
them.
Listing 1 is a Plain Old Java Object (POJO) that models the cars
table/collection in the Car
class, decorated with annotations.
@Entity
public class Car {
@Id
private int id;
@Column
private String make;
@Column
private String model;
@Column
dealerId;
//The usual constructors and getters/setters are defined here
}
Listing 1: The Car
class using the Jakarta Persistence and Jakarta NoSQL
annotations.
Similarly, Listing 2 is a POJO that models the dealers
table/collection in
the Dealers
class, decorated with annotations.
@Entity
public class Dealer {
@Id
private int id;
@Column
private String name;
@Column;
private String city;
@Column
private String state;
//The usual constructors and getter/setters are defined here
}
Listing 2: The Dealer
class using the Jakarta Persistence and Jakarta NoSQL
annotations.
We will examine these annotations in the overview section of both specifications.
Each of these database technologies requires a minimal set of dependencies that
are available by default if you specify the full
Jakarta EE Platform or the Jakarta EE Web Profile
in your pom.xml
or build.gradle
file. At this time, this is only true with
Jakarta Persistence.
However, you can individually specify the dependencies for a particular specification, especially if it hasn’t yet been included in one of the Jakarta EE profiles. Such is the case with Jakarta NoSQL.
Let’s examine the required dependencies for each specification.
If Maven is your preferred build tool, use this artifact, as shown in Listing
3, in your pom.xml
file:
<dependency>
<groupId>jakarta.persistence</groupId>
<artifactId>jakarta.persistence-api</artifactId>
<version>3.2.0</version>
</dependency>
Listing 3: The Jakarta Persistence dependency defined in Maven.
If Gradle is your preferred build tool, use this artifact, as shown in Listing
4, in your build.gradle
file:
implementation group: 'jakarta.persistence', name: 'jakarta.persistence-api', version: '3.2.0'
Listing 4: The Jakarta Persistence dependency defined in Gradle
If Maven is your preferred build tool, use this artifact, as shown in Listing
5, in your pom.xml
file:
<dependency>
<groupId>jakarta.nosql</groupId>
<artifactId>jakarta.nosql-api</artifactId>
<version>1.0.0</version>
</dependency>
Listing 5: The Jakarta NoSQL dependency defined in Maven.
If Gradle is your preferred build tool, use this artifact, as shown in Listing
6, in your build.gradle
file:
implementation group: 'jakarta.nosql', name: 'jakarta.nosql-api', version: '1.0.0'
Listing 6: The Jakarta NoSQL dependency defined in Gradle.
Now that we have covered the application and dependencies, let’s review the individual specifications.
For both Jakarta Persistence and Jakarta NoSQL, annotations that represent a
database entity, a primary key and database columns, share the same names.
These are @Entity
, @Id
and @Column
, respectively. While similar in
design, there are notable differences that will be discussed in this document.
The Jakarta Persistence specification, currently at version 3.2 for Jakarta EE 11, defines a standard for management of persistence and object/relational mapping in Java environments.
Having evolved from JSR 338, Java Persistence 2.2, as one of the specifications supporting Java EE 8, Jakarta Persistence has a rich history dating back to May 2006, as it was initially developed by the Enterprise JavaBeans 3.0 expert group (JSR 220) with the release of Java EE 5. Delivered in December 2009, Java EE 6 included JSR 317, Java Persistence 2.0, the first independent persistence specification.
After the release of Java EE 8 in August 2017, Oracle donated Java EE to the
Eclipse Foundation. Due to trademark laws, the Eclipse Foundation was required
to change the Java EE name and the javax.*
namespace to what ultimately
became Jakarta EE and jakarta.*
, respectively.
You have two choices for specifying database connection configuration: a
persistence.xml
file or the PersistenceConfiguration
class in your application.
The persistence.xml
file, usually located under the resources/META-INF
directory of your project, registers your database with your application.
Listing 7 demonstrates how to connect to the carsdb
MySQL database using the
standard JDBC driver, com.mysql.cj.jdbc.Driver
; the database URL,
jdbc:mysql://localhost:3306/carsdb
; the database user, root
; and an empty value
for the database password. The persistence unit name, mysql-persistence-unit
.
<?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_2.xsd"
version="3.2">
<persistence-unit name="mysql-persistence-unit">
<properties>
<property name="jakarta.persistence.jdbc.driver" value="com.mysql.cj.jdbc.Driver" />
<property name="jakarta.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/carsdb" />
<property name="jakarta.persistence.jdbc.user" value="root" />
<property name="jakarta.persistence.jdbc.password" value="" />
</properties>
</persistence-unit>
</persistence>
Listing 7: Establishing a connection to a MySQL database using the
persistence.xml
file.
The PersistenceConfiguration
class, new for Jakarta Persistence 3.2,
represents a configuration of a persistence unit that allows you to
programmatically create an instance of EntityManagerFactory
, an interface
designed to work with the PersistenceConfiguration
class, that will
ultimately create an instance of the EntityManager
interface.
Listing 8 demonstrates how to connect to the carsdb
MySQL database using: the
standard JDBC driver, com.mysql.cj.jdbc.Driver
; the database URL,
jdbc:mysql://localhost:3306/carsdb
; the database user, root
; and an empty
value for the database password. The persistence unit name,
mysql-persistence-unit
.
@Produces @ApplicationScoped @Documents
EntityManagerFactory configure() {
return new PersistenceConfiguration()
.name("mysql-persistence-unit")
.managedClass(Car.class)
.property(persistenceConfiguration.JDBC_DRIVER,"com.mysql.cj.jdbc.Driver")
.property(PersistenceConfiguration.JDBC_URL,"jdbc:mysql://localhost:3306/carsdb")
.property(PersistenceConfiguration.JDBC_USER,"root")
.property(PersistenceConfiguration.JDBC_PASSWORD,"")
.createEntityManagerFactory();
}
Listing 8: Establishing a connection to a MySQL database using the
PersistenceConfiguration
class.
The annotations shown in the example application shown in Listings 1 and 2, are
defined under the jakarta.persistence
package.
The @Entity
annotation declares that the annotated class is an entity. Specific rules for
using this annotation include:
non-final
top-level class or static inner classpublic
or protected
constructor with no parametersfinal
methods or persistent instance variablesIt is also important to note that an enum
, record
, or interface
may not
be designated as an entity.
A notable difference from Jakarta NoSQL is that a record
may be designated as
an entity.
The @Id
annotation identifies the primary key of the specified entity. The field or
property to which the @Id
annotation is applied should have one of the
following Java types:
String
UUID
java.util.Date
java.sql.Date
BigDecimal
BigInteger
A notable difference from Jakarta NoSQL is that java.util.Date
and
java.sql.Date
are allowed Java types.
The @Column
annotation specifies the database column mapped by the annotated persistent
property or field.
There are 14 optional parameters for this annotation (as opposed to two in Jakarta NoSQL) that include:
If a @Column annotation is not explicitly specified, the default values will apply.
The name parameter is useful in a situation where the database contains a foreign key from another table using snake case, but the variable in the corresponding POJO is in camel case as shown in Listing 9.
@Column("dealer_id")
private int dealerId;
Listing 9: Demonstrating how to use the @Column
annotation.
You also have the ability to do this in Jakarta NoSQL, however, the notable
difference is that the name of the method is value()
as opposed to name()
.
The current version of Jakarta Persistence is 3.2 and has been included in the Jakarta EE 11 Platform and Web Profile.
Two of the compatible implementations for Jakarta Persistence 3.2 are EclipseLink 5.x and Hibernate 7.x.
Jakarta Persistence has been adopted by SouJava.
The Jakarta NoSQL specification, currently at version 1.0 supporting Jakarta EE 11, defines a set of APIs and provides a standard implementation for most NoSQL databases and streamlining the integration of Java applications with those databases.
The journey to Jakarta NoSQL started out with the development of its ultimate implementation, Eclipse JNoSQL, before the specification was even a concept. Introduced to the Java community in March 2017, Eclipse JNoSQL was originally planned to be a community project led by Otávio Santana under the auspices of the Java Community Process.
The plan to develop Jakarta NoSQL was approved in October 2020, and choosing Eclipse JNoSQL as its implementation was a natural fit.
There are four types of NoSQL databases:
Let’s quickly review all four of these.
Key-Value NoSQL databases store data in a simple key-value format. Each data item is stored as a key-value pair, where the key is unique and used to access its corresponding value. These databases are highly scalable and provide fast access to data, making them suitable for use cases that require high throughput and low-latency data retrieval.
Example databases include: Redis, MemcacheDB and Riak.
Column Family databases store data in a tabular format with columns and rows. Unlike traditional relational databases, these databases allow a flexible schema design that can handle vast amounts of structured and semi-structured data. Column Family databases are suitable for use cases that require high scalability, fault-tolerance, and efficient querying.
Example databases include: Apache Cassandra and Apache Hadoop Hbase.
Document NoSQL databases store data in a semi-structured document format such as JSON or Binary JSON (BSON). Each document can have its own structure and fields, providing flexibility in data modeling. These databases are suitable for handling complex and evolving data structures, and support powerful querying and indexing capabilities.
Example databases include: MongoDB and Apache CouchDB.
Graph NoSQL databases store data in a graph structure consisting of nodes (vertices) and relationships (edges). Each node represents an entity, and edges represent relationships and connections between these entities. These databases are ideal for handling highly connected data and performing complex graph-based queries.
Example databases include: Neo4J, ArangoDB and OrientDB.
Jakarta NoSQL supports many of today’s common NoSQL databases, as shown in Figure 1.
Figure 1: The list of supported NoSQL databases in Jakarta NoSQL.
As defined in the Configuration and Credentials section of the Jakarta NoSQL specification document:
Configuration and credentials for NoSQL databases are not standardized within the Jakarta NoSQL specification. Each Jakarta NoSQL provider is responsible for providing its own configuration mechanism, allowing developers to configure the connection to the NoSQL database according to their specific requirements.
So, for our example application, we will connect to a NoSQL database via a
properties file such as microprofile-config.properties
. In Listing 10, we
want to use the carsdb
MongoDB database and connect via localhost
on
the standard 27017
MongoDB port.
jnosql.document.database=carsdb
jnosql.mongodb.host=localhost:27017
Listing 10: Establishing a connection to a MongoDB database.
The annotations shown in the example application shown in Listings 1 and 2, are
defined under the jakarta.nosql
package.
The @Entity
annotation declares that the annotated class is an entity.
Specific rules for using this annotation include:
@Id
or @Column
.@Id
or @Column
).It is also important to note that an enum
or interface
may not be designated as
an entity. However, a record
may be designated as an entity.
A notable difference from Jakarta Persistence is that an enum
, record
, or
interface
may not be designated as an entity.
The @Id
annotation identifies the primary key of the specified entity. The
field or property to which the @Id
annotation is applied should have one of
the following Java types:
int
, double
, byte
, etc.)Integer
, Double
, Byte
, etc.)String
UUID
BigDecimal
BigInteger
The mapped column for the primary key of the entity is assumed to be the primary key of the database table.
A notable difference from Jakarta Persistence is that java.util.Date
and
java.sql.Date
are Java types that are not allowed. They are marked as
deprecated in Jakarta Persistence 3.2, so use of the java.time
API is
encouraged there as well.
The @Column
annotation specifies the database column mapped by the annotated persistent
property or field. If a @Column
annotation is not explicitly specified, the
field will be ignored.
There are two optional parameters for this annotation:
The value parameter is useful in a situation where the database contains a foreign key from another collection defined using snake case, but the variable in the corresponding POJO is in camel case, as shown in Listing 11.
@Column("brewer_id")
private int brewerId;
Listing 11: Demonstrating how to use the @Column
annotation.
You also have the ability to do this in Jakarta Persistence, however, the
notable difference is that the name of the method is name()
as opposed to
valuename()
.
The current version of Jakarta NoSQL is 1.0.0, and is not part of the Jakarta EE 11 Platform. It is a candidate for inclusion in Jakarta EE 12.
One of the compatible implementations for Jakarta NoSQL is Eclipse JNoSQL 1.x.
Jakarta NoSQL has been adopted by the Garden State JUG and SouJava.
The Jakarta NoSQL and Jakarta Persistence specifications allow you to build robust backend database applications.
While there are obvious differences in these specifications, the use of the
@Entity
, @Id
, and @Column
annotations is very similar. This makes it easier for
developers to move from NoSQL to relational database applications or vice
versa.
The Jakarta Data specification, introduced in the summer of 2022, is included in the Jakarta EE 11 Platform and Web Profile. This new specification aims to be a top-level specification supporting both Jakarta NoSQL and Jakarta Persistence.
Looking ahead to Jakarta EE 12, the Jakarta NoSQL committers will be working towards having this specification included in the Jakarta EE 12, scheduled for release in 2026. In the meantime, however, you can still build your NoSQL applications with Jakarta NoSQL.
This GitHub repository contains examples on how to use some of the Jakarta EE specifications. Please note that there are some parts of this repository that are a work in progress. Feedback would indeed be appreciated!