Java and Scala overview

Pants's support for Java and Scala.


Java and Scala support is beta stage

We are done implementing most functionality for Pants's Java and Scala support (tracked here). However, there may be use cases that we aren't yet handling.

Please share feedback for what you need to use Pants with your JVM project by either opening a GitHub issue or joining our Slack!


Example Java and Scala repository

Check out to try out Pants's Java and Scala support.

Initial setup

First, activate the relevant backends in pants.toml:

backend_packages = [
  # Each backend can be used independently, so there is no need to enable Scala if you
  # have a pure-Java repository (or vice versa).

Then run ./pants tailor to generate BUILD files. This will create java_sources and scala_sources targets in every directory containing library code, as well as test targets like scalatest_tests and junit_tests for filenames that look like tests.

❯ ./pants tailor
Created src/jvm/org/pantsbuild/example/app/BUILD:
  - Add scala_sources target app
Created src/jvm/org/pantsbuild/example/lib/BUILD:
  - Add java_sources target lib
Created tests/jvm/org/pantsbuild/example/lib/BUILD:
  - Add scalatest_tests target lib

You can run ./pants list :: to see all targets in your project:

❯ ./pants list

Choosing JDK and Scala versions

Pants 2.11.x adds support for choosing JDK and Scala versions per target in your repository, but to reduce the amount of boilerplate required, most users set repository-wide defaults in pants.toml, and then only override them when necessary for particular targets.


JDKs used by Pants are automatically fetched using Coursier, and are chosen using the [jvm].jdk setting to set a repository-wide default.

To override the default on a particular target, you can use the jdk= field. It can be useful to use the parametrize builtin with the jdk= field, particularly to run test targets under multiple JDKs.

Scala version

The Scala version to use is configured on a resolve-by-resolve basis (see the "Third-party dependencies" section below) using the [scala].version_for_resolve option. The default Scala version for your repository will thus be whichever Scala version is configured for the "default" resolve, which is configured by the [jvm].default_resolve option.

To use multiple Scala versions in a repository, you would define multiple resolves, and then adjust the resolve field of any targets which should be used with the non-default_resolve resolve.

To cross-build a set of Scala targets for multiple Scala versions, you can use the parametrize builtin with the resolve= field of the target and its dependencies.


A jvm_artifact for scala-library artifact is explicitly required.

The Scala backend currently requires that a jvm_artifact target for the org.scala-lang:scala-library Scala runtime be present in any resolve used for Scala. If such a jvm_artifact is missing, Pants will error. Pants will automatically inject a dependency on the runtime. (This target may be automatically supplied by Pants in a future version, but that is not currently implemented.)

First-party dependencies

In many cases, the dependencies of your first-party code are automatically inferred via dependency inference based on your import statements. If you do need to declare additional dependencies for any reason, you can do so using Pants' syntax for declaring dependencies for targets.

Third-party dependencies and lockfiles

Third-party dependencies (i.e. those from repositories like Maven central) are also automatically inferred via dependency inference, but must first be declared once per repository as jvm_artifact targets:

    # See the callout below for more information on the `packages` argument.

Pants requires use of a lockfile for thirdparty dependencies. After adding or editing jvm_artifact targets, you will need to update affected lockfiles by running ./pants generate-lockfiles. The default lockfile is located at 3rdparty/jvm/default.lock, but it can be relocated (as well as additional resolves declared) via the [jvm].resolves option.


Thirdparty symbols and the packages argument

To efficiently determine which symbols are provided by thirdparty code (i.e., without hitting the network in order to compute dependencies in the common case), Pants relies on a static mapping of which artifacts provide which symbols, and defaults to treating each jvm_artifact as providing symbols within its group.

The packages argument allows you to override which symbols a jvm_artifact provides. See the jvm_artifact docs for more information.

resource targets

To have your code load files as "resources":

  1. Add a resource or resources target with the relevant files in the source / sources field, respectively.
  2. Ensure that an appropriate source_root is detected for the resources target, in order to trim the relevant prefix from the filename to align with the layout of your JVM packages.
  3. Add that target to the dependencies field of the relevant JVM target (usually the one that uses the JVM APIs to load the resource).

For example:

# In order for the resource to be loadable as `org/pantsbuild/example/lib/hello.txt`,
# the `/src/jvm/ prefix needs to be stripped.
root_patterns = ["/src/*"]

resources(name="hello", sources=["hello.txt"])
package org.pantsbuild.example.lib;


public class Loader {
  public static String load() {
    ... = Resources.getResource(Loader.class, "hello.txt");
Hello world!

Compile code

To manually check that sources compile, use ./pants check:

# Check a single file
❯ ./pants check src/jvm/org/pantsbuild/example/lib/

# Check files located recursively under a directory
❯ ./pants check src/jvm::

# Check the whole repository
❯ ./pants check ::

Run tests

To run tests, use ./pants test:

# Run a single test file
❯ ./pants test tests/jvm/org/pantsbuild/example/lib/ExampleLibSpec.scala

# Test all files in a directory
❯ ./pants test tests/jvm::

# Test the whole repository
❯ ./pants test ::

You can also pass through arguments to the test runner with --, e.g.:

# Pass `-z hello` to scalatest in order to test a single method
❯ ./pants test tests/jvm/org/pantsbuild/example/lib/ExampleLibSpec.scala -- -z hello

Lint and Format

scalafmt and Google Java Format can be enabled by adding the pants.backend.experimental.scala.lint.scalafmt and backends (respectively) to backend_packages in the [GLOBAL] section of pants.toml.

Once enabled, lint and fmt will check and automatically reformat your code:

# Format this directory and all subdirectories
❯ ./pants fmt src/jvm::

# Check that the whole project is formatted
❯ ./pants lint ::

# Format all changed files
❯ ./pants --changed-since=HEAD fmt

Did this page help you?