Search code examples
bazelspark-java

ClassNotFoundException using Spark library through Bazel


I am trying to run a "hello world" server in Spark building it with Bazel, but I am getting this error:

$ bazel run //:app
INFO: Analysed target //:app (0 packages loaded).
INFO: Found 1 target...
Target //:app up-to-date:
  bazel-bin/app.jar
  bazel-bin/app
INFO: Elapsed time: 0.201s, Critical Path: 0.00s
INFO: 0 processes.
INFO: Build completed successfully, 1 total action
INFO: Build completed successfully, 1 total action
Exception in thread "main" java.lang.NoClassDefFoundError: org/slf4j/LoggerFactory
        at spark.Service.<clinit>(Service.java:56)
        at spark.Spark$SingletonHolder.<clinit>(Spark.java:51)
        at spark.Spark.getInstance(Spark.java:55)
        at spark.Spark.<clinit>(Spark.java:61)
        at io.app.server.Main.main(Main.java:7)
Caused by: java.lang.ClassNotFoundException: org.slf4j.LoggerFactory
        at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:338)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
        ... 5 more

BUILD:

java_binary(
    name = "app",
    main_class = "io.app.server.Main",
    srcs = ["src/main/java/io/app/server/Main.java"],
    deps = [
        "@org_slf4j_slf4j_simple//jar",
        "@com_sparkjava_spark_core//jar",
    ]
)

The same error happens if I don't include slf4j, and it should not be a required dependency of spark.

WORKSPACE:

maven_jar(
    name = "com_sparkjava_spark_core",
    artifact = "com.sparkjava:spark-core:2.7.2"
)

maven_jar(
    name = "org_slf4j_slf4j_simple",
    artifact = "org.slf4j:slf4j-simple:1.7.21"
)

And finally, src/main/java/io/app/server/Main.java:

package io.app.server;

import static spark.Spark.*;

public class Main {
  public static void main(String[] args) {
    port(3000);
    get("/", (req, res) -> "Hello World");
  }
}

Any idea of what I could be doing wrong here?


Solution

  • Found what I was missing. It seems that maven_jar does not automatically fetch the "transitive dependencies" that the library itself has, see this.

    Bazel only reads dependencies listed in your WORKSPACE file. If your project (A) depends on another project (B) which list a dependency on a third project (C) in its WORKSPACE file, you'll have to add both B and C to your project's WORKSPACE file. This requirement can balloon the WORKSPACE file size, but hopefully limits the chances of having one library include C at version 1.0 and another include C at 2.0.

    Large WORKSPACE files can be generated using the tool generate_workspace. For details, see Generate external dependencies from Maven projects.

    So the solution seems to be to write a pom.xml and use generate_workspace.

    EDIT: generate_workspace seems to be deprecated, use bazel_deps instead.