Exploring the New Eclipse JNoSQL Version 1.1.0: A Dive Into Oracle NoSQL
Eclipse JNoSQL 1.1.0 simplifies Java's NoSQL database integration with Jakarta Data annotations and custom repositories for easier and more business-centric code.
Join the DZone community and get the full member experience.
Join For FreeIn the ever-evolving world of software development, staying up-to-date with the latest tools and frameworks is crucial. One such framework that has been making waves in NoSQL databases is Eclipse JNoSQL. This article will deeply dive into the latest release, version 1.1.0, and explore its compatibility with Oracle NoSQL.
Understanding Eclipse JNoSQL
Eclipse JNoSQL is a Java-based framework that facilitates seamless integration between Java applications and NoSQL databases. It leverages Java enterprise standards, specifically Jakarta NoSQL and Jakarta Data, to simplify working with NoSQL databases. The primary objective of this framework is to reduce the cognitive load associated with using NoSQL databases while harnessing the full power of Jakarta EE and Eclipse MicroProfile.
With Eclipse JNoSQL, developers can easily integrate NoSQL databases into their projects using Widfly, Payara, Quarkus, or other Java platforms. This framework bridges the Java application layer and various NoSQL databases, making it easier to work with these databases without diving deep into their intricacies.
What’s New in Eclipse JNoSQL Version 1.1.0
The latest version of Eclipse JNoSQL, 1.1.0, comes with several enhancements and upgrades to make working with NoSQL databases smoother. Let’s explore some of the notable changes:
Jakarta Data Version Upgrade
In this release, one of the significant updates in Eclipse JNoSQL version 1.1.0 is upgrading the Jakarta Data version to M2. To better understand the importance of this upgrade, let’s delve into what Jakarta Data is and how it plays a crucial role in simplifying data access across various database types.
Jakarta Data
Jakarta Data is a specification that provides a unified API for simplified data access across different types of databases, including both relational and NoSQL databases. This specification is part of the broader Jakarta EE ecosystem, which aims to offer a standardized and consistent programming model for enterprise Java applications.
Jakarta Data empowers Java developers to access diverse data repositories straightforwardly and consistently. It achieves this by introducing concepts like Repositories and custom query methods, making data retrieval and manipulation more intuitive and developer-friendly.
One of the key features of Jakarta Data is its flexibility in allowing developers to compose custom query methods on Repository interfaces. This flexibility means that developers can craft specific queries tailored to their application’s needs without manually writing complex SQL or NoSQL queries. This abstraction simplifies the interaction with databases, reducing the development effort required to access and manipulate data.
The Goal of Jakarta Data
The primary goal of Jakarta Data is to provide a familiar and consistent programming model for data access while preserving the unique characteristics and strengths of the underlying data stores. In other words, Jakarta Data aims to abstract away the intricacies of interacting with different types of databases, allowing developers to focus on their application logic rather than the specifics of each database system.
By upgrading Eclipse JNoSQL to use Jakarta Data version M2, the framework aligns itself with the latest Jakarta EE standards and leverages the newest features and improvements introduced by Jakarta Data. It ensures that developers using Eclipse JNoSQL can benefit from the enhanced capabilities and ease of data access that Jakarta Data brings.
Enhanced Support for Inheritance
One of the standout features of Eclipse JNoSQL is its support for Object-Document Mapping (ODM). It allows developers to work with NoSQL databases in an object-oriented manner, similar to how they work with traditional relational databases. In version 1.1.0, the framework has enhanced its support for inheritance, making it even more versatile when dealing with complex data models.
Oracle NoSQL Database: A Brief Overview
Before we conclude, let’s take a moment to understand the database we’ll work with – Oracle NoSQL Database.
Oracle NoSQL Database is a distributed key-value and document database developed by Oracle Corporation. It offers robust transactional capabilities for data manipulation, horizontal scalability to handle large workloads, and simplified administration and monitoring. It is particularly well-suited for applications that require low-latency access to data, flexible data models, and elastic scaling to accommodate dynamic workloads.
The Oracle NoSQL Database Cloud Service provides a managed cloud platform for deploying applications that require the capabilities of Oracle NoSQL Database, making it even more accessible and convenient for developers.
Show Me the Code
We’ll create a simple demo application to showcase the new features of Eclipse JNoSQL 1.1.0 and its compatibility with Oracle NoSQL. This demo will help you understand how to set up the environment, configure dependencies, and interact with Oracle NoSQL using Eclipse JNoSQL.
Prerequisites
Before we begin, ensure you have an Oracle NoSQL instance running. You can use either the “primes” or “cloud” flavor. For local development, you can run Oracle NoSQL in a Docker container with the following command:
docker run -d --name oracle-instance -p 8080:8080 ghcr.io/oracle/nosql:latest-ce
Setting up the Project
We’ll create a Java SE project using the Maven Quickstart Archetype to keep things simple. It will give us a basic project structure to work with.
Project Dependencies
For Eclipse JNoSQL to work with Oracle NoSQL, we must include specific dependencies. Additionally, we’ll need Jakarta CDI, Eclipse MicroProfile, Jakarta JSONP, and the Eclipse JNoSQL driver for Oracle NoSQL. We’ll also include “datafaker” for generating sample data. Here are the project dependencies:
<dependencies>
<dependency>
<groupId>org.eclipse.jnosql.databases</groupId>
<artifactId>jnosql-oracle-nosql</artifactId>
<version>1.1.0</version>
</dependency>
<dependency>
<groupId>net.datafaker</groupId>
<artifactId>datafaker</artifactId>
<version>2.0.2</version>
</dependency>
</dependencies>
Configuration
Eclipse JNoSQL relies on configuration properties to establish a connection to the database. This is where the flexibility of Eclipse MicroProfile Config shines. You can conveniently define these properties in your application.properties or application.yml file, allowing for easy customization of your database settings. Remarkably, Eclipse JNoSQL caters to key-value and document databases, a testament to its adaptability. Despite Oracle NoSQL's support for both data models, the seamless integration and configuration options provided by Eclipse JNoSQL ensure a smooth experience, empowering developers to effortlessly switch between these database paradigms to meet their specific application needs.
# Oracle NoSQL Configuration
jnosql.keyvalue.database=cars
jnosql.document.database=cars
jnosql.oracle.nosql.host=http://localhost:8080
Creating a Model for Car Data in Eclipse JNoSQL
After setting up the database configuration, the next step is to define the data model to be stored in it. The process of defining a model is consistent across all databases in Eclipse JNoSQL. For instance, in this example, we will form a data model for cars using a basic Car
class.
@Entity
public class Car {
@Id
private String id;
@Column
private String vin;
@Column
private String model;
@Column
private String make;
@Column
private String transmission;
// Constructors, getters, and setters
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Car car = (Car) o;
return Objects.equals(id, car.id);
}
@Override
public int hashCode() {
return Objects.hashCode(id);
}
@Override
public String toString() {
return "Car{" +
"id='" + id + '\'' +
", vin='" + vin + '\'' +
", model='" + model + '\'' +
", make='" + make + '\'' +
", transmission='" + transmission + '\'' +
'}';
}
// Factory method to create a Car instance
public static Car of(Faker faker) {
Vehicle vehicle = faker.vehicle();
Car car = new Car();
car.id = UUID.randomUUID().toString();
car.vin = vehicle.vin();
car.model = vehicle.model();
car.make = vehicle.make();
car.transmission = vehicle.transmission();
return car;
}
}
In the Car
class, we use annotations to define how the class and its fields should be persisted in the database:
@Entity
: This annotation marks the class as an entity to be stored in the database.@Id:
Indicates that the id field will serve as the unique identifier for each Car entity.@Column
: Annotations like @Column specify that a field should be persisted as a column in the database. In this case, we annotate each field we want to store in the database.
Additionally, we provide methods for getters, setters, equals, hashCode, and toString for better encapsulation and compatibility with database operations. We also include a factory method Car.of(Faker faker)
, to generate random car data using the “datafaker” library.
This data model encapsulates the structure of a car entity, making it easy to persist and retrieve car-related information in your Oracle NoSQL database using Eclipse JNoSQL.
Simplifying Database Operations With Jakarta Data Annotations
In Eclipse JNoSQL’s latest version, 1.1.0, developers can harness the power of Jakarta Data annotations to streamline and clarify database operations. These annotations allow you to express your intentions in a more business-centric way, making your code more expressive and closely aligned with the actions you want to perform on the database.
Here are some of the Jakarta Data annotations introduced in this version:
@Insert: Effortless Data Insertion
The @Insert
annotation signifies the intent to perform an insertion operation in the database. When applied to a method, it indicates that it aims to insert data into the database. This annotation provides clarity and conciseness, making it evident that the method is responsible for adding new records.
@Update: Seamless Data Update
The @Update
annotation is used to signify an update operation. It is beneficial when you want to modify existing records in the database. Eclipse JNoSQL will check if the information to be updated is already present and proceed accordingly. This annotation simplifies the code by explicitly stating its purpose.
@Delete: Hassle-Free Data Removal
When you want to delete data from the database, the @Delete
annotation comes into play. It communicates that the method’s primary function is to remove information. Like the other annotations, it enhances code readability by conveying the intended action.
@Save: Combining Insert and Update
The @Save
annotation serves a dual purpose. It behaves like the save method in BasicRepository but with added intelligence. It checks if the information is already in the database, and if so, it updates it; otherwise, it inserts new data. This annotation provides a convenient way to handle insertion and updating without needing separate methods.
With these Jakarta Data annotations, you can express database operations in a more intuitive and business-centric language. In the context of a car-centric application, such as managing a garage or car collection, you can utilize these annotations to define operations like parking a car and unparking it:
@Repository
public interface Garage extends DataRepository<Car, String> {
@Save
Car parking(Car car);
@Delete
void unpark(Car car);
Page<Car> findByTransmission(String transmission, Pageable page);
}
In this example, the @Save
annotation is used for parking a car, indicating that this method handles both inserting new cars into the “garage” and updating existing ones. The @Delete
annotation is employed for unparking, making it clear that this method is responsible for removing cars from the “garage.”
These annotations simplify database operations and enhance code clarity and maintainability by aligning your code with your business terminology and intentions.
Executing Database Operations With Oracle NoSQL
Now that our entity and repository are set up let’s create classes to execute the application. These classes will initialize a CDI container to inject the necessary template classes for interacting with the Oracle NoSQL database.
Interacting With Document Database
As a first step, we’ll interact with the document database. We’ll inject the DocumentTemplate
interface to perform various operations:
public static void main(String[] args) {
Faker faker = new Faker();
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
DocumentTemplate template = container.select(DocumentTemplate.class).get();
// Insert 10 random cars into the database
for (int index = 0; index < 10; index++) {
Car car = Car.of(faker);
template.insert(car);
}
// Retrieve and print all cars
template.select(Car.class).stream().toList().forEach(System.out::println);
// Retrieve and print cars with Automatic transmission, ordered by model (descending)
template.select(Car.class).where("transmission").eq("Automatic").orderBy("model").desc()
.stream().forEach(System.out::println);
// Retrieve and print cars with CVT transmission, ordered by make (descending)
template.select(Car.class).where("transmission").eq("CVT").orderBy("make").desc()
.stream().forEach(System.out::println);
}
System.exit(0);
}
In this code, we use the DocumentTemplate
to insert random cars into the document database, retrieve and print all cars, and execute specific queries based on transmission type and ordering.
Interacting With Key-Value Database
Oracle NoSQL also supports a key-value database, and we can interact with it as follows:
public static void main(String[] args) {
Faker faker = new Faker();
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
KeyValueTemplate template = container.select(KeyValueTemplate.class).get();
// Create a random car and put it in the key-value database
Car car = Car.of(faker);
template.put(car);
// Retrieve and print the car based on its unique ID
System.out.println("The query result: " + template.get(car.id(), Car.class));
// Delete the car from the key-value database
template.delete(car.id());
// Attempt to retrieve the deleted car (will return null)
System.out.println("The query result: " + template.get(car.id(), Car.class));
}
System.exit(0);
}
In this code, we utilize the KeyValueTemplate
to put a randomly generated car into the key-value database, retrieve it by its unique ID, delete it, and attempt to retrieve it again (resulting in null since it’s been deleted).
These examples demonstrate how to execute database operations seamlessly with Oracle NoSQL, whether you’re working with a document-oriented or key-value database model, using Eclipse JNoSQL’s template classes.
In this final sampling execution, we will demonstrate how to interact with the repository using our custom repository interface. This approach simplifies database operations and makes them more intuitive, allowing you to work with your custom-defined terminology and actions.
public static void main(String[] args) {
Faker faker = new Faker();
try (SeContainer container = SeContainerInitializer.newInstance().initialize()) {
Garage repository = container.select(Garage.class, DatabaseQualifier.ofDocument()).get();
// Parking 10 random cars in the repository
for (int index = 0; index < 10; index++) {
Car car = Car.of(faker);
repository.parking(car);
}
// Park a car and then unpark it
Car car = Car.of(faker);
repository.parking(car);
repository.unpark(car);
// Retrieve the first page of cars with CVT transmission, ordered by model (descending)
Pageable page = Pageable.ofPage(1).size(3).sortBy(Sort.desc("model"));
Page<Car> page1 = repository.findByTransmission("CVT", page);
System.out.println("The first page");
page1.forEach(System.out::println);
// Retrieve the second page of cars with CVT transmission
System.out.println("The second page");
Pageable secondPage = page.next();
Page<Car> page2 = repository.findByTransmission("CVT", secondPage);
page2.forEach(System.out::println);
System.out.println("The query result: ");
}
System.exit(0);
}
We create a Garage instance through the custom repository interface in this code. We then demonstrate various operations such as parking and unparking cars and querying for cars with specific transmission types, sorted by model and paginated.
You can express database operations in a business-centric language by utilizing the repository interface with custom annotations like @Save and @Delete. This approach enhances code clarity and aligns with your domain-specific terminology, providing a more intuitive and developer-friendly way to interact with the database.
Conclusion
Eclipse JNoSQL 1.1.0, with its support for Oracle NoSQL databases, simplifies and streamlines the interaction between Java applications and NoSQL data stores. With the introduction of Jakarta Data annotations and custom repositories, developers can express database operations in a more business-centric language, making code more intuitive and easier to maintain.
This article has covered the critical aspects of Eclipse JNoSQL’s interaction with Oracle NoSQL, including setting up configurations, creating data models, and executing various database operations. Whether you are working with document-oriented or key-value databases, Eclipse JNoSQL provides the necessary tools and abstractions to make NoSQL data access a breeze.
To dive deeper into the capabilities of Eclipse JNoSQL and explore more code samples, check out the official repository. There, you will find a wealth of information, examples, and resources to help you leverage the power of Eclipse JNoSQL in your Java applications.
Eclipse JNoSQL empowers developers to harness the flexibility and scalability of NoSQL databases while adhering to Java enterprise standards, making it a valuable tool for modern application development.
Opinions expressed by DZone contributors are their own.
Comments