Skip to main content

Abstract

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.

Introduction

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.

Example Application

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.

Dependencies

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.

Jakarta Persistence

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

Jakarta NoSQL

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.

Common Annotations

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.

Jakarta Persistence Overview

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.

Background

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.

Configuration

You have two choices for specifying database connection configuration: a
persistence.xml file or the PersistenceConfiguration
class in your application.

persistence.xml File

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.

PersistenceConfiguration Class

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.

Annotations

The annotations shown in the example application shown in Listings 1 and 2, are
defined under the jakarta.persistence package.

@Entity

The @Entity
annotation declares that the annotated class is an entity. Specific rules for
using this annotation include:

  • Must be a non-final top-level class or static inner class
  • Must have a public or protected constructor with no parameters
  • Must have no final methods or persistent instance variables

It 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.

@Id

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:

  • any Java primitive type (int, double, byte, etc.)
  • any Java primitive wrapper type (Integer, Double, Byte, etc.)
  • 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.

@Column

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:

  • name: a string that allows you to wire together the name of the column
    and the name of its corresponding attribute in the application, should they
    be different.
  • table: a string that defines the name of the table that contains the
    column
  • insertable: a boolean for whether the column should be included in
    SQL INSERT statements generated by the persistence provider
  • updatable: a boolean for whether the column should be included in SQL
    UPDATE statements generated by the persistence provider.

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().

Current Status

The current version of Jakarta Persistence is 3.2 and has been included in the
Jakarta EE 11 Platform and Web Profile.

Compatible Implementations

Two of the compatible implementations for Jakarta Persistence 3.2 are
EclipseLink 5.x
and Hibernate 7.x.

Specification Adopters

Jakarta Persistence has been adopted by SouJava.

Jakarta NoSQL Overview

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.

Background

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.

NoSQL Database Types

There are four types of NoSQL databases:

  • Key-Value
  • Column Family
  • Document
  • Graph

Let’s quickly review all four of these.

Key-Value

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

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

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

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.

Supported NoSQL Databases

Jakarta NoSQL supports many of today’s common NoSQL databases, as shown in
Figure 1.

List of supported NoSQL databases in Jakarta NoSQL: ArangoDB; Apache TinkerPop; biazegraph; basho; Tom Sawyer Software; Cassandra; Couchbase; IBM Graph; CouchDB redux; Infinispan; Elastic; Grakn.ai; hazelcast; Apache HBASE; Azure Cosmos DB; Stardog; Titan; JanusGraph; KeyLines Network Insight; Linkurious; M; mongoDB; Solr; Scylla; neo4j; Oracle NoSQL Database; Orient DB; redis; riak; and RavenDB.

Figure 1: The list of supported NoSQL databases in Jakarta NoSQL.

Configuration

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.

Annotations

The annotations shown in the example application shown in Listings 1 and 2, are
defined under the jakarta.nosql
package.

@Entity

The @Entity annotation declares that the annotated class is an entity.
Specific rules for using this annotation include:

  • At least one field must be annotated with @Id or @Column.
  • Must have a public or protected constructor with no parameters (or with
    parameters annotated with @Id or @Column).
  • Constructor parameters without annotations will be ignored, and instead
    utilize a non-argument constructor.

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.

@Id

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:

  • any Java primitive type (int, double, byte, etc.)
  • any Java primitive wrapper type (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.

@Column

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:

  • udt: a string that defines the user-defined type for this column.
  • value: a string that defines the name of the column.

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().

Current Status

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.

Compatible Implementations

One of the compatible implementations for Jakarta NoSQL is Eclipse JNoSQL
1.x.

Specification Adopters

Jakarta NoSQL has been adopted by the
Garden State JUG and SouJava.

Conclusion

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!