Building Java Enterprise applications using MongoDB

This article will teach you how to use MongoDB NoSQL database in the context of an Enterprise application. For the purpose of this example, we will deploy an example application on a Jakarta EE application server.

The most common way to connect to MongoDB from Java Enterprise applications is by means of the MongoDB Java Driver which provides a simple and clean interface to perform CRUD operations and advanced searches on your MongoDB documents.

MongoDB Driver also includes a standalone BSON library that you can use to build high-performance encoders and decoders without requiring the cooperation of a Map instance.

There are two versions of the Driver:

  • The MongoDB Java Driver for synchronous Java applications
  • The MongoDB Reactive Streams Driver to use the Reactive Streams API for asynchronous stream processing.

In this article, we will be using the MongoDB Java Driver for synchronous Java applications.

Starting Mongo DB

In order to run this tutorial you need MongoDB. Use any of the following options:

  • Use a Docker image to start MongoDB

To start MongoDB as Docker image, you can use the following docker-compose.yml file which contains the image reference as well as user/password credentials:

version: '3.1'

services:

  myMongo:
    image: mongo
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: example

  mongo-express:
    image: mongo-express
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: example
      ME_CONFIG_MONGODB_URL: mongodb://root:example@myMongo:27017/

Start the docker deamon first:

service docker start

Then, launch docker-compose from the same location of your YML file:

docker-compose up

Coding the Enterprise application

Next step is to code our Enterprise application. We will be creating a REST application to access MongoDB Documents, therefore any web application archetype will be good:

 mvn archetype:generate -DgroupId=org.acme -DartifactId=mongodb-demo -DarchetypeArtifactId=maven-archetype-webapp -DinteractiveMode=false

Next, add the dependencies for your application. You will need the Enterprise stack and MongoDB Driver:

<dependencies>
    <dependency>
       <groupId>jakarta.platform</groupId>
       <artifactId>jakarta.jakartaee-api</artifactId>
       <scope>provided</scope>
       <version>${jakartaee.version}</version>
    </dependency>
  
    <dependency>
       <groupId>org.mongodb</groupId>
       <artifactId>mongodb-driver-sync</artifactId>
       <version>4.7.1</version>
    </dependency>

</dependencies>

Fix the jakartaee.version in a variable. For example:

 <jakartaee.version>9.0.0</jakartaee.version>

Finally, if you are going to deploy this example on WildFly, we recommend adding the WildFly Maven plugin:

<plugin>
    <groupId>org.wildfly.plugins</groupId>
    <artifactId>wildfly-maven-plugin</artifactId>
    <version>2.0.0.Final</version>
</plugin>

Connecting to MongoDB from Java

Firstly, we will be adding a CDI producer Bean which Produces a com.mongodb.client.MongoClient using the Factory method of the class com.mongodb.client.MongoClients:

@ApplicationScoped
public class MongoDBProducer {

    @Produces
    public MongoClient createMongo() {
        return  MongoClients.create("mongodb://root:[email protected]:27017/?maxPoolSize=20&w=majority");
    }

    @Produces
    public MongoDatabase createDB(MongoClient client) {
        return client.getDatabase("testdb");
    }

    public void close(@Disposes MongoClient toClose) {
        toClose.close();
    }
}

Most applications only require a single instance of a MongoClient, even across multiple threads. All resource usage limits, such as max connections, apply to individual MongoClient instances.

To connect to MongoDB, we need to use a connection URI which provides a set of instructions that the driver uses to connect to a MongoDB deployment. For example:

mongodb java ee enterprise

Coding the Model

MongoDB stores data records as BSON documents. In our example, we will be storing a collection of Customer Documents. Our Model will be the following minimal POJO Class:

public class Customer {
    public Customer() {
	}

    public Customer(Long id, String name, String surname) {
		super();
		this.id = id;
		this.name = name;
		this.surname = surname;
	}

    private Long id;
    private String name;
    private String surname;

    // Getters/Setters omitted
}

Coding the Service Class

In order to manage MongoDB Documents, we will need a Service Class that has access to the com.mongodb.client.MongoDatabase. The MongoDatabase is our gateway to the MongoDB Collection “customers“:

@ApplicationScoped
public class CustomerService {

    @Inject
    MongoDatabase mongoDB;

    public List<Customer> list(){
        List<Customer> list = new ArrayList<>();

        try {
        	Bson filter =  Filters.empty();
        	getCollection().find(filter).
        	    forEach(doc -> list.add(new Customer(doc.getLong("id"), doc.getString("name"),doc.getString("surname"))));

        }
        	catch (Exception exc ) {
        		exc.printStackTrace();
        	}
        return list;
    }

    public void add(Customer customer){
        Document document = new Document()
                .append("name", customer.getName())
                .append("surname", customer.getSurname())
                .append("id", customer.getId());
        InsertOneResult result = getCollection().insertOne(document);
        System.out.println("Inserted a document with the following id: " 
        	    + result.getInsertedId().asObjectId().getValue());
    }

    public void update(Customer customer){
        // update one document

        Bson filter = eq("id", customer.getId());
        Bson updateOperation = set("name", customer.getName());
        getCollection().updateOne(filter, updateOperation);
    }

    public void delete(Customer customer){
        Bson filter = eq("id", customer.getId());
        getCollection().deleteOne(filter);
    }
    private MongoCollection<Document> getCollection(){
        return mongoDB.getCollection("customers");
    }
}

Coding the REST Endpoint

Finally, to make our Class accessible to Clients, we will add a REST Service which wraps the CustomerService with HTTP methods:

@Path("/customer")
@Produces("application/json")
@Consumes("application/json")
public class CustomerEndpoint {

    @Inject CustomerService service;

    @GET
    public List<Customer> list() {
        return service.list();
    }

    @POST
    public List<Customer> add(Customer customer) {
        service.add(customer);
        return list();
    }

    @PUT
    public List<Customer> put(Customer customer) {
        service.update(customer);
        return list();
    }

    @DELETE
    public List<Customer> delete(Customer customer) {
        service.delete(customer);
        return list();
    }
}

Our REST Service in turn needs a JAX-RS Activator:

@ApplicationPath("/rest")
public class JaxRsActivator extends Application {
 
}

Running the example

WildFly users can simply build and deploy the application as follows:

$ mvn install wildfly:deploy

As soon as the application is available, you will see in the server logs that the Connection producer kicked-in:

27017) Opened connection [connectionId{localValue:2, serverValue:2}] to 172.24.0.3:27017
17:07:05,150 INFO  [org.mongodb.driver.cluster] (cluster-ClusterId{value='630e2799589b3f0449116034', description='null'}-172.24.0.3:27017) Monitor thread successfully connected to server with description ServerDescription{address=172.24.0.3:27017, type=STANDALONE, state=CONNECTED, ok=true, minWireVersion=0, maxWireVersion=13, maxDocumentSize=16777216, logicalSessionTimeoutMinutes=30, roundTripTimeNanos=16070627}
17:07:05,223 INFO  [org.mongodb.driver.connection] (default task-1) Opened connection [connectionId{localValue:3, serverValue:4}] to 172.24.0.3:27017

Let’s begin by adding a new Document with an HTTP POST:

curl -X POST http://localhost:8080/mongoclient-wildfly/rest/customer  -H 'Content-Type: application/json'  -d '{"id":"1","name":"John","surname":"Smith"}'

Then, let’s check the list of Documents for the customers collections:

curl http://localhost:8080/mongoclient-wildfly/rest/customer

Which results in:

[{"id":1,"name":"John","surname":"Smith"}]

Besides, you can also check the available connections in the DB using the mongo client tool:

> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
testdb  0.000GB

> use testdb
switched to db testdb

> db.customers.find()
{ "_id" : ObjectId("630e34a7095911151a09c344"), "name" : "John", "surname" : "Smith", "id" : NumberLong(1) }

Next, we can try to update the Resource with an HTTP PUT from the Command Line:

 curl -X PUT http://localhost:8080/mongoclient-wildfly/rest/customer  -H 'Content-Type: application/json'  -d '{"id":1,"name":"Frank","surname":"Smith"}'

Finally, you can DELETE the Document as well

curl -X DELETE http://localhost:8080/mongoclient-wildfly/rest/customer  -H 'Content-Type: application/json'  -d '{"id":1,"name":"Frank","surname":"Smith"}'

Source code

The source code for the full MongoDB example is available here: https://github.com/fmarchioni/mastertheboss/tree/master/nosql/mongodb/mongoclient-wildfly

Found the article helpful? if so please follow us on Socials