Mongo JDBC - JakartaEE library to increase the productivity allowing the developer focus on the logic he needs to work forgetting about Mongodb-JDBC concerns.

Mongo JDBC-JakartaEE library provide below capabilities.

  • It is done on CDI this makes it compatible with Jakarta EE (JavaEE 8) applications and every CDI application.

  • Provide Serializer implementation for ObjectId class.

  • Developer work based on the use of MongoDatabase injectable instance.

  • Ready to work with Mongodb JDBC Pojo Decoder.

  • Configurable via environment variables.

  • Mongo entity interface provided to create BSON documents based on POJO.

Getting started

Add this dependency on your project.

Maven

<dependency>
    <groupId>io.github.pablobastidasv</groupId>
    <artifactId>mongojdbc-utils</artifactId>
    <version>1.4.1</version>
</dependency>

Gradle

compile 'io.github.pablobastidasv:mongojdbc-utils:1.4.1'
This dependency already include Mongodb JDBC driver version 3.10.2, you don’t need to included it.
If you already have provided a Mongodb JDBC driver, exclude this library to avoid dependencies clash.

Default behaviour

By default the Mongo JDBC - JakartaEE library will run connecting to localhost though 27017 port without certificate and creating a database called avalane.

This behaviour can be changed setting some environment variables in the host overriding the default values.

Available environment variables

Environment variable Name Description Default value

MONGO_USERNAME

User name to connect to MongoDB server

<Empty>

MONGO_PASSWORD

Password of the defined username

<Empty>

MONGO_SERVER

Hostname of the MongoDB server

localhost

MONGO_PORT

Port of the MongoDB server

27017

DATABASE_NAME

Database name

avalane

MONGO_OPTIONS

Mongo options that will be attached in string built if BUILD_CONNECTION_STRING is set to true

<Empty>

BUILD_CONNECTION_STRING

If true a connection string will be build with values in MONGO_USERNAME, MONGO_PASSWORD, MONGO_SERVER, MONGO_PORT, DATABASE_NAME and MONGO_OPTIONS

false

MONGO_CONNECTION_STRING

Connection string

<Empty>

Mongo JDBC

Mongo JDBC - JakartaEE uses Mongo JDBC driver version 3.10.2.

This library is a transitive dependency what means it is not needed to add the JDBC mongo driver when this library is used, only adding the Mongo JDBC - JakartaEE as dependency it’s enough to start to work with mongo in the application.

The MongodbEntity interface

The Mongo entity interface gives to user the ability to create a BSON object based on the POJO which implements the interface.

Why does this interface exist

The MongodbEntity was created to provide method toDocument() which will convert the entity to a BSON object that can be created to save into database to get the id, because over POJO codec is not possible to obtain the new ID after save.

MongoClient

The MongoClient instance is injectable via CDI as explained below.

@Inject private MongoClient client;

The instance is created when the application is started.

Customizer

In the case of the necessity to create an index the library provides an interface which can be implemented and this will run as soon as the MongoDatabase reference is created.

The interface co.pablob.mongo.boundary.MongodbCustomizer requires the implementation of the method customize which receives a reference of the database (MongoDatabase) to make the needed customizations like index creation.

When multitenant mode is enabled customizer only will run in default database other databases will not apply the customizers.

Multi-tenant

Since version 1.3.0, there is a strategy to support multi tenant database.

How does it work?

This library creates one MongodbClient instance, this instance is used to provide the database reference which is used by the collections injection.

The collection injector is a generic method which must be @Dependent scope and cannot be @RequestScoped doing this provider not an option when a multi-tenant behaviour is needed due to the database must be choose based on each request. On the other hand, the database provider is not a generic producer method allowing this to be scoped as @RequestScoped hitting the connection to the database based on each request.

To achieve a multi-tenant behaviour, the library provide the option to specialize the class co.pablob.mongo.control.DatabaseNameProvider which is in charge to specify to the Database producer what is the database name.|

Examples

Below some examples to clarify the uses this library has.

Working with MongoDatabase

In case you need to work directly with the MongoDatabase instance, the injection of this instance is available by @Inject cdi annotation.

import com.mongodb.client.MongoDatabase;

...
    @Inject
    private MongoDatabase database;
...

Above example will inject the unique instance of database which is share by the whole application.

Injecting MongoCollection<Document>

To inject a MongoCollection of type org.bson.Document, follow the below sniped.

    @Inject
    @Definition(collection = MyEntity.COLLECTION_NAME) (1)
    MongoCollection<Document> vanillaCollection; (2)
1 Use the annotaion @Definition specifying the collection attribute with the collection name.
2 Declare the MongoCollection object of type org.bson.Document.
This collection is useful when you want to save a document and get its id after save.

Working with MongoCollection<T>

Mongo JDBC - JakartaEE provides a way to inject a MongoCollection specifying the POJO type of the MongoCollection.

    @Inject
    @Definition(collection = MyEntity.COLLECTION_NAME, clazz = MyEntity.class) (1)
    MongoCollection<MyEntity> collection; (2)
1 Use the annotation Definition to specify the definition of the Collection
  • collection (Required): Name of the collection in the database.

  • clazz: Class type of the POJO who represents the document. By default the clazz value is org.bson.Document (see this example to more information).

2 The MongoCollection of the specified type on clazz attribute in step 1.

Using MongodbEntity interface

The Mongo JDBC - JakartaEE defines a interface to provide the method toDocument() to your classes.

This method will be useful to convert the actual POJO to a org.bson.Document object that can be handle by the Mongo JDBC driver.

MyEntity.java
import co.pablob.mongo.entity.MongodbEntity; (1)

public MyEntity implements MongodbEntity { (2)
    ...
}
1 Import the respective interface.
2 Implements this interface in your entity.

How to get id after save a document

There is a know behaviour in Mongodb JDBC driver, this not allow to get the id of an POJO object just after creation (JAVA-2374).

Because of this, bellow an example of how to obtain this id using MongodbEntity and MongoCollection<Document> with Mongo JDBC - JakartaEE.

MyEntity.java
import co.pablob.mongo.entity.MongodbEntity; (1)

public MyEntity implements MongodbEntity { (2)
    ...
}
Dao.java
    (3)
    @Inject
    @Definition(MyEntity.COLLECTION_NAME)
    MongoCollection<Document> vanillaCollection;

    ...

    Document document = myEntity.toDocument(); (4)
    vanillaCollection.insertOne(document); (5)
    ObjectId id = document.getObjectId("_id"); (6)
    System.out.println(id);
1 Inside the entity import the Interface MongodbEntity
2 In the entity, implement the interface MongodbEntity
3 In the a vanilla MongoCollection (Inject MongoCollection).
4 Use the method toDocument() (Use Mongodb Interface).
5 Use the method insertOne from the MongoCollection instance.
6 From the document, obtain the value of the id (ObjectId)

How to create indexes

When there is the necessity to create index into your database proceed based on below example.

public class Indexer implements MongodbCustomizer { @Override public void customize(MongoDatabase mongoDatabase) { MongoCollection<Document> collection = mongoDatabase.getCollection("collection");

IndexOptions options = new IndexOptions();
options.unique(true);
        collection.createIndex(Indexes.ascending("unq_field"), options);
    }
}

Multi-tenant based on user

On this example let’s assume the database will depend on the user and we can get the user information via CDI Injection.

@Specializes (1)
public class MultiTenantDatabaseNameProvider extends DatabaseNameProvider { (2)

    @Inject
    private JwtPrincipal principal; (3)

    @Override
    public String produceDatabaseName() {
        return principal.getDatabase(); (4)
    }
}

public class MyService {

    @Inject
    private Database database; (5)

    public void doSomething() {
        Collection collection = database.getCollection("colection_name"); (6)

        ...
    }
}
  1. The class must be an specialization, this can achieved annotation the class Specializes from javax.enterprise.inject package.

  2. The class must extends co.pablob.mongo.control.DatabaseNameProvider.

  3. In this example, the user information is stored in JwtPrincipal object so the injection of this instance is done (CDI injection is supported in this point).

  4. In the produceDatabaseName method overwriting a String is returned, this String is the database name that will be used in Database reference instantiation.

  5. Now, on our service or where we needed, we can inject the database and this will reference the database specified in the DatabaseNameProvider specialized class.

  6. Use this instance to access the collection and do whatever you need.