Jakarta NoSQL 1.1: Advancing Polyglot Persistence for Jakarta EE 12
Jakarta NoSQL 1.1 brings Jakarta Query integration, projections, fluent updates, and automatic converters, strengthening polyglot persistence in Jakarta EE 12.
Join the DZone community and get the full member experience.
Join For FreeModern applications rarely rely on a single data model. Relational databases remain essential for transactional consistency and structured business data. However, document, key-value, column-oriented, graph, and vector databases are now critical for workloads that require flexible schemas, horizontal scalability, low-latency access, or specialized queries. As a result, polyglot persistence — selecting the most appropriate database model for each use case — has become a standard architectural strategy rather than an exception.
The rise of artificial intelligence further supports this trend. Retrieval-augmented generation (RAG), semantic search, recommendation systems, and autonomous agents often rely on embeddings and vector similarity searches to access contextual information. As a result, vector databases and multimodel NoSQL platforms are becoming integral to the modern enterprise data landscape.
In this context, Jakarta NoSQL offers Jakarta EE developers a standardized and extensible programming model for working with various NoSQL technologies, while minimizing direct dependence on specific database vendors.
From Jakarta NoSQL to Polyglot Persistence
Jakarta NoSQL is the first specification developed within the Jakarta EE ecosystem, rather than inherited from Java EE. It addresses the need for enterprise applications to use NoSQL databases and supports polyglot persistence. Its goal is to offer a simple, vendor-neutral programming model for document, key-value, column, and graph databases, so developers do not need to learn a separate API for each provider.
This work influenced the development of Jakarta Data, which introduced a repository-oriented model independent of database technology, and Jakarta Query, which aims to provide a unified query language across persistence specifications. Collectively, these specifications advance Jakarta EE toward a broader and more consistent data-access strategy.
Entity mapping is the initial step in Jakarta NoSQL. Its annotations use terminology familiar from Jakarta Persistence, formerly JPA. Developers use @Entity to define persistent types, @Id for keys, and @Column for attributes. This consistency lowers the learning curve for Java developers experienced with Jakarta Persistence.
For example, an investment can be modeled as follows:
ackage expert.os.videos.nosql;
import jakarta.nosql.Column;
import jakarta.nosql.Entity;
import jakarta.nosql.Id;
import java.math.BigDecimal;
import java.util.UUID;
@Entity
public class Investment {
@Id
private UUID id;
@Column
private String name;
@Column
private InvestmentType type;
@Column
private BigDecimal amount;
public Investment(
UUID id,
String name,
InvestmentType type,
BigDecimal amount) {
this.id = id;
this.name = name;
this.type = type;
this.amount = amount;
}
Investment() {
}
@Override
public String toString() {
return "Investment{" +
"id=" + id +
", name='" + name + '\'' +
", type=" + type +
", amount=" + amount +
'}';
}
}
ublic enum InvestmentType {
STOCK,
BOND,
FUND,
CRYPTO,
REAL_ESTATE
}
Jakarta NoSQL supports Java records, enabling entities to be defined in a more concise and immutable format:
@Entity
public record Investment(
@Id UUID id,
@Column String name,
@Column InvestmentType type,
@Column BigDecimal amount) {
}
A key difference from Jakarta Persistence is that persistent attributes must be explicitly marked with @Id or @Column. Fields lacking these annotations are ignored, making the persistence model clearer and preventing accidental storage of attributes.
After mapping the entity, it can be inserted, retrieved, and queried using the template API:
UUID id = UUID.randomUUID();
Investment investment = new Investment(
id,
"Java Growth Fund",
InvestmentType.FUND,
new BigDecimal("1500.00")
);
template.insert(investment);
template.find(Investment.class, id)
.ifPresent(System.out::println);
template.select(Investment.class)
.where("amount")
.gt(new BigDecimal("1000"))
.result()
.forEach(System.out::println);
The fluent query API makes operations easy to discover and keeps queries aligned with the domain model. In this example, the application uses Oracle NoSQL, but the same mapping and structure can be reused with providers like MongoDB or ArangoDB by updating dependencies and connection settings. The common API reduces vendor coupling, though database-specific features such as transactions, consistency, indexing, and advanced queries may still require provider-specific solutions.
Jakarta NoSQL 1.1
Jakarta NoSQL 1.1 advances data access in Jakarta EE by improving compatibility with other specifications. With Jakarta EE 12, enterprise Java enters a new data era, highlighted by Jakarta NoSQL’s integration with Jakarta Query.
Jakarta Query provides a unified query model for Java applications and diverse data sources. Its core language defines essential query concepts such as entities, attributes, comparisons, filtering, and parameters. It also offers the Jakarta Persistence Query Language, previously known as JPQL, enabling its familiar syntax and concepts to be used by other specifications and persistence technologies.
With the Investment entity, applications can execute string-based queries directly using the template API:
template.query("FROM Investment WHERE amount > 1000")
.result()
.forEach(System.out::println);
Queries can use named parameters to separate values from the query expression:
template.query("FROM Investment WHERE amount > :amount")
.bind("amount", new BigDecimal("1000"))
.result()
.forEach(System.out::println);
Jakarta NoSQL 1.1 supports projections, enabling queries to return only the information needed for a specific use case rather than loading the entire entity. Projections can be represented as Java records and declared with the @Projection annotation:
@Projection
public record InvestmentProjector(
String name,
BigDecimal amount) {
}
The projection can then serve as the result type for a typed query:
template.typedQuery(
"FROM Investment WHERE amount > 1000",
InvestmentProjector.class)
.result()
.forEach(System.out::println);
In this example, the query returns only the investment name and amount. This approach is useful for reports, dashboards, API responses, and other read-oriented scenarios where retrieving the full entity is unnecessary. Records are well-suited for projections because they offer a compact and immutable representation of selected data.
Jakarta NoSQL 1.1 expands the fluent API. Previous versions supported select and delete operations:
template.select(Investment.class)
.where("amount")
.gt(new BigDecimal("1000"))
.result()
.forEach(System.out::println);
template.delete(Investment.class)
.where("amount")
.gt(new BigDecimal("1000"))
.execute();
Version 1.1 adds fluent update operations, completing the main set of data manipulation capabilities:
template.update(Investment.class)
.set("amount")
.to(new BigDecimal("2000.00"))
.where("id")
.eq(id)
.execute();
This operation updates matching entities directly, eliminating the need to retrieve and modify them in memory first.
Another enhancement is the autoApply attribute for the @Converter annotation. When enabled, the converter is automatically applied to every mapped attribute of the supported Java type, removing the need to declare it on each field. This reduces repetitive configuration and ensures consistent custom type conversion across the domain model.
Together, Jakarta Query integration, projections, fluent update operations, and automatic converters make Jakarta NoSQL 1.1 more expressive and better aligned with the broader Jakarta EE data ecosystem.
Opinions expressed by DZone contributors are their own.
Comments