Skip to content

Dependencies

Geert Bevin edited this page Jul 31, 2024 · 8 revisions

As mentioned in the Configuring Files section, unlike other build tools, bld doesn't rely on automatic dependency resolution to create the classpaths for your Java project. Instead, the jar files inside your project's lib directory will be used to create the classpath for the various scopes:

...
├── lib             // library files creating classpaths for different scopes 
│   ├── bld         // libraries for bld
│   ├── compile     // libraries for compiling your project
│   ├── provided    // libraries for compiling, provided by a container
│   ├── runtime     // libraries for running your project
│   ├── standalone  // libraries for running your project standalone
│   └── test        // libraries for testing your project
...

NOTE: the Project Creation section contains more details about your project structure.

Defining project dependencies

Putting files inside those lib directories can be done manually, without ever using any automated dependency downloads. For many projects this can be inconvenient, especially since Maven has inspired such a rich ecosystem of readily available artifact repositories.

bld supports the Maven dependency management style and syntax, directly integrating with any Maven repository and resolving dependency trees in the same way, but with a Java API.

For instance:

// ...
public class MyappBuild extends WebProject {
    public MyappBuild() {
        // ...
        repositories = List.of(MAVEN_CENTRAL, RIFE2_RELEASES);
        scope(compile)
            .include(dependency("com.uwyn.rife2", "rife2", version(1,8,0)));
        scope(test)
            .include(dependency("org.jsoup", "jsoup", version(1,18,1)))
            .include(dependency("org.junit.jupiter", "junit-jupiter", version(5,10,3)))
            .include(dependency("org.junit.platform", "junit-platform-console-standalone", version(1,10,3)));
        scope(standalone)
            .include(dependency("org.eclipse.jetty.ee10", "jetty-ee10", version(12,0,11)))
            .include(dependency("org.eclipse.jetty.ee10", "jetty-ee10-servlet", version(12,0,11)))
            .include(dependency("org.slf4j", "slf4j-simple", version(2,0,13)));
    }
    // public static void main ...
}

This sets up Maven Central, and RIFE2's own artifact repository as the repositories your project will use to find dependencies. They will be queried in the order they are specified.

Then, for each scope, a series of dependencies are defined.

If you prefer, a shorter dependency syntax can also be used, which could be convenient if you're copy-pasting dependencies from Maven central by using the Gradle (short) format.

    // ...
    scope(compile)
        .include(dependency("com.uwyn.rife2:rife2:1.8.0"));
    scope(test)
        .include(dependency("org.jsoup:jsoup:1.18.1"))
        .include(dependency("org.junit.jupiter:junit-jupiter:5.10.3"))
        .include(dependency("org.junit.platform:junit-platform-console-standalone:1.10.3"));
    scope(standalone)
        .include(dependency("org.eclipse.jetty.ee10:jetty-ee10:12.0.11"))
        .include(dependency("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.11"))
        .include(dependency("org.slf4j:slf4j-simple:2.0.13"));
    // ...

The downside of the shorter syntax is that it can be less convenient to use Java language capabilities for your dependencies, like extracting common groups and versions:

    // ...
    var jetty_group = "org.eclipse.jetty.ee10";
    var jetty_version = version(12,0,11);
    scope(standalone)
        .include(dependency(jetty_group, "jetty-ee10", jetty_version))
        .include(dependency(jetty_group, "jetty-ee10-servlet", jetty_version))
        .include(dependency("org.slf4j", "slf4j-simple", version(2,0,13)));
    // ...

With these dependencies defined, nothing really changed, the jar files are still not in the lib directories. You get them there by telling bld that it should download the dependencies for your project:

./bld download
Downloading: …/maven2/com/uwyn/rife2/rife2/1.8.0/rife2-1.8.0.jar ... done
Downloading: …/maven2/org/eclipse/jetty/ee10/jetty-ee10/12.0.11/jetty-ee10-12.0.11.jar ... not found
Downloading: …/maven2/org/eclipse/jetty/ee10/jetty-ee10-servlet/12.0.11/jetty-ee10-servlet-12.0.11.jar ... done
Downloading: …/maven2/jakarta/servlet/jakarta.servlet-api/6.0.0/jakarta.servlet-api-6.0.0.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-security/12.0.11/jetty-security-12.0.11.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-server/12.0.11/jetty-server-12.0.11.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-session/12.0.11/jetty-session-12.0.11.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-http/12.0.11/jetty-http-12.0.11.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-io/12.0.11/jetty-io-12.0.11.jar ... done
Downloading: …/maven2/org/eclipse/jetty/jetty-util/12.0.11/jetty-util-12.0.11.jar ... done
Downloading: …/maven2/org/slf4j/slf4j-simple/2.0.13/slf4j-simple-2.0.13.jar ... done
Downloading: …/maven2/org/slf4j/slf4j-api/2.0.13/slf4j-api-2.0.13.jar ... done
Downloading: …/maven2/org/jsoup/jsoup/1.18.1/jsoup-1.18.1.jar ... done
Downloading: …/maven2/org/junit/jupiter/junit-jupiter/5.10.3/junit-jupiter-5.10.3.jar ... done
Downloading: …/maven2/org/junit/jupiter/junit-jupiter-api/5.10.3/junit-jupiter-api-5.10.3.jar ... done
Downloading: …/maven2/org/junit/jupiter/junit-jupiter-params/5.10.3/junit-jupiter-params-5.10.3.jar ... done
Downloading: …/maven2/org/junit/jupiter/junit-jupiter-engine/5.10.3/junit-jupiter-engine-5.10.3.jar ... done
Downloading: …/maven2/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar ... done
Downloading: …/maven2/org/junit/platform/junit-platform-commons/1.10.3/junit-platform-commons-1.10.3.jar ... done
Downloading: …/maven2/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar ... done
Downloading: …/maven2/org/junit/platform/junit-platform-engine/1.10.3/junit-platform-engine-1.10.3.jar ... done
Downloading: …/maven2/org/junit/platform/junit-platform-console-standalone/1.10.3/junit-platform-console-standalone-1.10.3.jar ... done
Downloading finished successfully.

If you now look into the lib directory, you'll see that all the transitive dependencies have been downloaded into the directories of their respective scopes:

lib
├── bld
├── compile
│   └── rife2-1.8.0.jar
├── provided
├── runtime
├── standalone
│   ├── jakarta.servlet-api-6.0.0.jar
│   ├── jetty-ee10-servlet-12.0.11.jar
│   ├── jetty-http-12.0.11.jar
│   ├── jetty-io-12.0.11.jar
│   ├── jetty-security-12.0.11.jar
│   ├── jetty-server-12.0.11.jar
│   ├── jetty-session-12.0.11.jar
│   ├── jetty-util-12.0.11.jar
│   ├── slf4j-api-2.0.13.jar
│   └── slf4j-simple-2.0.13.jar
└── test
    ├── apiguardian-api-1.1.2.jar
    ├── jsoup-1.18.1.jar
    ├── junit-jupiter-5.10.3.jar
    ├── junit-jupiter-api-5.10.3.jar
    ├── junit-jupiter-engine-5.10.3.jar
    ├── junit-jupiter-params-5.10.3.jar
    ├── junit-platform-commons-1.10.3.jar
    ├── junit-platform-console-standalone-1.10.3.jar
    ├── junit-platform-engine-1.10.3.jar
    └── opentest4j-1.3.0.jar

Now, for as long as you're using the same dependencies, you don't have to issue the download command again. The jar files just remain into these directories and bld uses them to construct the classpaths. Dependency resolution doesn't need to happen anymore until you actually change the dependencies of your project.

This saves a lot on execution time and makes your project directory fully self-contained with the following benefits:

  • You always have everything you need to work, even without network access.
  • IDEs can use the same jars and properly analyze your project, compile and run it.
  • Automated backup system always capture a complete snapshot of your project at any given time.
  • and more ...

Updating dependencies

As time goes on, you'll likely want to check if there's newer versions of your dependencies available and update them. bld comes with a handy updates command that checks if there's any updates for your project's dependencies:

./bld updates
The following dependency updates were found.
standalone:
    org.eclipse.jetty.ee10:jetty-ee10:12.0.12
    org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.12

You can then decide if this is a version you want to update to, and change your build file accordingly:

    // ...
    var jetty_group = "org.eclipse.jetty.ee10";
    var jetty_version = version(12,0,12);
    scope(standalone)
        .include(dependency(jetty_group, "jetty-ee10", jetty_version))
        .include(dependency(jetty_group, "jetty-ee10-servlet", jetty_version))
        .include(dependency("org.slf4j", "slf4j-simple", version(2,0,13)));
    // ...

Now it's time to run the download command again:

./bld download
Downloading: …/com/uwyn/rife2/rife2/1.8.0/rife2-1.8.0.jar ... exists
Downloading: …/org/eclipse/jetty/ee10/jetty-ee10/12.0.12/jetty-ee10-12.0.12.jar ... not found
Downloading: …/org/eclipse/jetty/ee10/jetty-ee10-servlet/12.0.12/jetty-ee10-servlet-12.0.12.jar ... done
Downloading: …/jakarta/servlet/jakarta.servlet-api/6.0.0/jakarta.servlet-api-6.0.0.jar ... exists
Downloading: …/org/eclipse/jetty/jetty-security/12.0.12/jetty-security-12.0.12.jar ... done
Downloading: …/org/eclipse/jetty/jetty-server/12.0.12/jetty-server-12.0.12.jar ... done
Downloading: …/org/eclipse/jetty/jetty-session/12.0.12/jetty-session-12.0.12.jar ... done
Downloading: …/org/slf4j/slf4j-api/2.0.13/slf4j-api-2.0.13.jar ... exists
Downloading: …/org/eclipse/jetty/jetty-http/12.0.12/jetty-http-12.0.12.jar ... done
Downloading: …/org/eclipse/jetty/jetty-io/12.0.12/jetty-io-12.0.12.jar ... done
Downloading: …/org/eclipse/jetty/jetty-util/12.0.12/jetty-util-12.0.12.jar ... done
Downloading: …/org/slf4j/slf4j-simple/2.0.13/slf4j-simple-2.0.13.jar ... exists
Downloading: …/org/jsoup/jsoup/1.18.1/jsoup-1.18.1.jar ... exists
Downloading: …/org/junit/jupiter/junit-jupiter/5.10.3/junit-jupiter-5.10.3.jar ... exists
Downloading: …/org/junit/jupiter/junit-jupiter-api/5.10.3/junit-jupiter-api-5.10.3.jar ... exists
Downloading: …/org/junit/jupiter/junit-jupiter-params/5.10.3/junit-jupiter-params-5.10.3.jar ... exists
Downloading: …/org/junit/jupiter/junit-jupiter-engine/5.10.3/junit-jupiter-engine-5.10.3.jar ... exists
Downloading: …/org/opentest4j/opentest4j/1.3.0/opentest4j-1.3.0.jar ... exists
Downloading: …/org/junit/platform/junit-platform-commons/1.10.3/junit-platform-commons-1.10.3.jar ... exists
Downloading: …/org/apiguardian/apiguardian-api/1.1.2/apiguardian-api-1.1.2.jar ... exists
Downloading: …/org/junit/platform/junit-platform-engine/1.10.3/junit-platform-engine-1.10.3.jar ... exists
Downloading: …/org/junit/platform/junit-platform-console-standalone/1.10.3/junit-platform-console-standalone-1.10.3.jar ... exists
Downloading finished successfully.

bld is smart enough to check the existing files and to detect that they exist and are identical, and downloads the new files for your updated dependencies.

However, since you might be combining automated dependency downloads with manually providing jars, bld doesn't automatically delete the old dependency jars. Since these are still in the lib directories, they will be included in the classpaths. This is most likely not what you want, so you can manually delete them, or if you fully rely on bld for your dependency management, you can use the handy purge command to get rid of any jar that doesn't correspond to the current dependencies of your project:

./bld purge
Deleting from standalone:
    jetty-io-12.0.11.jar
    jetty-security-12.0.11.jar
    jetty-server-12.0.11.jar
    jetty-http-12.0.11.jar
    jetty-session-12.0.11.jar
    jetty-ee10-servlet-12.0.11.jar
    jetty-util-12.0.11.jar
Purging finished successfully.

In practice, many people will just combine these command in one line:

./bld download purge

or abbreviated:

./bld dl pg

Automating download and purge

If you fully want to hand over dependency management to bld and have all jars automatically update as soon as you make changes to your project dependencies, you can set the autoDownloadPurge option to true:

// ...
public class MyappBuild extends WebProject {
    public MyappBuild() {
        // ...
        autoDownloadPurge = true;
        // ...
    }
    // public static void main ...
}

bld will now calculate and store a signature of your project's dependencies and automatically download and purge them when that signature changes. This will still keep your build running as fast as before, as long your dependencies stay the same.

If you have any SNAPSHOT dependency versions in your dependencies, this will also cause bld to access the internet every time you run it for your project. To work offline, you'll then have to use bld with the --offline argument.

Version resolution

When dependency trees get bigger, you'll start seeing the same dependencies being pulled in by other dependencies. It's also very common that the versions of those common dependencies are not the same. To ensure that only one version of a particular dependency is used in the classpaths of your project, like Maven and Gradle, bld remembers the first version number that was encountered for a particular dependency, and uses that for any later instances of that dependency in the tree.

This has the added benefit that if you want to lock a dependency in the tree to a particular version, all you need to do is to define that dependency version yourself in the relevant scope before other dependencies get to use it.


Next learn more about Team Setup

Clone this wiki locally