Setheron
Setheron

Reputation: 3740

Why doesn't java_binary propagate runtime dependencies to java_test

I wrote a small application and used java_binary as follows:

java_binary(
    name = "MyCommand",
    srcs = [
        "MyCommand.java",
    ],
    visibility = ["//visibility:public"],
    deps = [
        "//src/main/java/com/example/two",
    ],
)

It depends on a java_library target //src/main/java/com/example/two

I then wrote a java_test as follows:

java_test(
    name = "TestMyCommand",
    size = "small",
    srcs = [
        "TestMyCommand.java",
    ],
    deps = [
        ":MyCommand",
    ],
)

The test is pretty simple and just does new MyCommand().

This unfortunately fails quickly with a ClassDefNotFoundException with a class file found in //src/main/java/com/example/two. Setting a breakpoint it looks like that library is not included in the ClassPath.

HOWEVER, if I change my java_test to depend on a java_library THEN the transitive dependency of //src/main/java/com/example/two is included.

I could not find anything in the documentation explaining why?

Upvotes: 0

Views: 613

Answers (1)

ahumesky
ahumesky

Reputation: 5006

This is because java_binary is a "binary" rule, i.e., it outputs an executable, or another way, it's typically a "terminal" or "root" rule. So it doesn't pass along the info to add its deps to the final classpath, because it doesn't typically expect to be in the dependencies[1] of other targets (even java_test).

You could refactor the BUILD file so that MyCommand.java is in a java_library, and the java_test and the java_binary targets depend on that:

java_binary(
    name = "MyCommandMain",
    runtime_deps = [":MyCommand"],
    main_class = "com.example.one.MyCommand",
)

java_library(
    name = "MyCommand",
    srcs = [
        "MyCommand.java",
    ],
    visibility = ["//visibility:public"],
    deps = [
        "//src/main/java/com/example/two",
    ],
)

1: But you do sometimes see things like this:

# or other kinds of binary rules (cc_binary, py_binary, etc)
java_binary(
  name = "my_java_bin",
  ...,
)

sh_binary(
  name = "my_shell_script",
  srcs = ["script.sh"],
  data = [":my_java_bin"],
)

and script.sh runs my_java_bin as part of whatever it's accomplishing. The difference here is that my_shell_script is using the whole binary, rather than programming against code within it.

Upvotes: 1

Related Questions