Home > Software design >  How to add MongoDB dependecy to Java
How to add MongoDB dependecy to Java

Time:04-17

I'm new to Maven and Gradle and I am trying to add MongoDB dependency to my JavaFx app. The problem is even though I add the dependency on build.gradle/pom and click on load changes, IntelliJ can't find that class. I tried many things such as Invalidate Caches, delete all and recreate project but it's still not working. Thanks. enter image description here

enter image description here

CodePudding user response:

Advice on adding dependencies to a modular project

Some (opinonated) advice:

  1. Don't import libraries you don't use:

    • e.g. controlsfx/formsfx/validatorfx/ikonli/bootstrapfx/tilesfx.
  2. If you don't know Gradle or Maven, choose Maven when using the idea new JavaFX project wizard.

    • Maven is likely easier to learn and understand for a simple project.
  3. If your project is modular when adding a 3rd party dependency like mongo, you also need to update your module-info.java file to require the new module.

    • By default, the Idea new JavaFX project wizard will create a module-info.java file which makes your project modular.
  4. To determine the module name of the required module you can check if the library has a module-info in its source repository or binary jar and use that.

  5. If there is no module-info, as in this case, it will be an automatic module.

  6. If it is an automatic module you can find out the module name from an Automatic-Module-Name manifest header in the jar, if that is defined.

  7. If no manifest header is defined, you can find out the module name from the jar name, according to the steps in the automatic module documentation linked.

  8. Possibly, you will need to add other statements to the module-info such as opens or exports clauses.

    • You will know this because you will receive runtime errors when trying to use the code from the dependent module. These runtime errors will inform you that you have access errors due to the constraints of the Java module system.

Even when you do all of the above, some libraries may not work as Java platform modules because they are not coded to work. In which case, you should run them the libraries off of the classpath. Probably it is best in such a case to make your project non-modular (while keeping the JavaFX libraries as modules on the module path). To do so, delete the module-info.java file and use VM arguments to allow access to the JavaFX modules. For more information on such a configuration, study the documentation on non-modular projects as openjfx.io, specifically the section non-modular with Maven. However, only do this if you fail or it is too inconvenient to get the project to work as a modular project.

If you don't understand information in the above steps, study both tutorials for:

  1. Your chosen build system.
  2. The Java module system.
  3. How to adapt your project to use the Java module system.
  4. How to use your build system to work with the Java module system.

If this is difficult (and it may be), you can contact the vendor of the third-party library and request assistance in getting the library to work as a Java platform module.

Specifically for MongoDB

I did try the above steps with the MongoDB java client libraries. After doing so, I came to the conclusion that it is best (currently) to use MongoDB from JavaFX with your project in a non-modular mode (i.e., without module-info.java defined in your project).

This is because as of MongoDB 4.5.1:

  1. MongoDB can only be used as automatic modules because it does not provide appropriate module-info.

  2. The MongoDB client comes in multiple jars and splits its package definitions across jars.

    • This split-package definition across multiple jars is a configuration not allowed by the Java platform module system as far as I can tell.
    • package com.mongodb has classes defined in both mongodb-driver.jar and mongodb-driver-core.jar.

Here is a non-modular setup for mongodb JavaFX

All files were generated by the Idea New JavaFX project wizard and some modifications were made as outlined below (non-modified files are not listed).

I don't use MongoDB and don't have a MongoDB server setup, so I just verified that the below configuration compiles and tries to connect to a server (then fails to connect due to no server running).

To ease setup, during wizard definition, I chose the JDK: "liberica-18 BellSoft Liberica version 18". This is Liberica's "full JDK" version that includes the JavaFX modules in its base JDK distribution so I don't need to define command-line switches to enable JavaFX at compile and runtime (which is a painful and error-prone process).

By default, the MongoDB java client does not ship with a logging implementation. To get logs from the client, you need to include a logging implementation dependency. For this example, I chose to include slf4j-simple as the logging implementation, you could replace that with another compatible library if you wish.

MongoDB client access code was copied from a MongoDB quick start tutorial, but it is using a local access URL rather than a clustered service URL instead of an Atlas cloud-hosted MongoDB instance.

module-info.java

File deleted.

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>mongodb-javafx-demo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <name>mongo</name>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <javafx.version>18</javafx.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-fxml</artifactId>
            <version>${javafx.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver-sync</artifactId>
            <version>4.5.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.36</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.9.0</version>
                <configuration>
                    <source>18</source>
                    <target>18</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

HelloApplication.java

import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.stage.Stage;
import org.bson.Document;

import java.io.IOException;

import static com.mongodb.client.model.Filters.eq;
public class HelloApplication extends Application {
    @Override
    public void start(Stage stage) throws IOException {
        FXMLLoader fxmlLoader = new FXMLLoader(HelloApplication.class.getResource("hello-view.fxml"));
        Scene scene = new Scene(fxmlLoader.load(), 320, 240);
        stage.setTitle("Hello!");
        stage.setScene(scene);
        stage.show();

        // Replace the uri string with your MongoDB deployment's connection string
        String uri = "mongodb://localhost:27017";
        try (MongoClient mongoClient = MongoClients.create(uri)) {
            MongoDatabase database = mongoClient.getDatabase("sample_mflix");
            MongoCollection<Document> collection = database.getCollection("movies");
            Document doc = collection.find(eq("title", "Back to the Future")).first();
            System.out.println(doc.toJson());
        }
    }

    public static void main(String[] args) {
        launch();
    }
}
  • Related