-
Notifications
You must be signed in to change notification settings - Fork 13
Dependencies
As mentioned in the Configuring Files section, unlike other
build tools, bld
doesn't rely on automatic dependency resolution to create the classpaths
and modules paths for your Java project. Instead, the jar files inside your project's lib
directory will be used to create the classpath and module path for the various scopes:
...
├── lib // library files creating classpaths for different scopes
│ ├── bld // libraries for bld
│ ├── compile // libraries for compiling your project
│ │ └── modules // java modules for compiling your project
│ ├── provided // libraries for compiling, provided by a container
│ │ └── modules // java modules for compiling, provided by a container
│ ├── runtime // libraries for running your project
│ │ └── modules // java modules for running your project
│ ├── standalone // libraries for running your project standalone
│ │ └── modules // java modules for running your project standalone
│ └── test // libraries for testing your project
│ └── modules // java modules for testing your project
...
NOTE: the Project Creation section contains more details about your project structure.
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
│ │── modules
│ └── rife2-1.8.0.jar
├── provided
│ └── modules
├── runtime
│ └── modules
├── standalone
│ │── modules
│ ├── 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
│── modules
├── 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 in 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 ...
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 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 do pur
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's 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.
bld
has direct support for Java modules, which are distributed as regular jars.
The main difference when using Java modules is that alongside the traditional Java classpath, there's now also a module path. Any jar that is specified on the module path will be interpreted as an explicit or an automatic Java module.
bld
automatically creates the module path for the various scopes by looking inside
the lib/*/modules
directories. You can freely use any organization of classpaths and
module paths.
In order to have bld
download project dependencies inside those modules
directories,
all that is necessary is to replace dependency(…)
with module(…)
.
For example:
// ...
scope(compile)
.include(module("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(module("org.eclipse.jetty.ee10:jetty-ee10:12.0.11"))
.include(module("org.eclipse.jetty.ee10:jetty-ee10-servlet:12.0.11"))
.include(module("org.slf4j:slf4j-simple:2.0.13"));
// ...
If you now look into the lib
directory, you'll see that the module dependencies have
been placed inside the appropriate modules
sub-directories:
lib
├── bld
│ ├── bld-wrapper.jar
│ ├── bld-wrapper.properties
│ └── bld.cache
├── compile
│ └── modules
│ └── rife2-1.8.0.jar
├── provided
│ └── modules
├── runtime
│ └── modules
├── standalone
│ └── modules
│ ├── jakarta.servlet-api-6.0.0.jar
│ ├── jetty-ee10-servlet-12.0.12.jar
│ ├── jetty-http-12.0.12.jar
│ ├── jetty-io-12.0.12.jar
│ ├── jetty-security-12.0.12.jar
│ ├── jetty-server-12.0.12.jar
│ ├── jetty-session-12.0.12.jar
│ ├── jetty-util-12.0.12.jar
│ ├── slf4j-api-2.0.13.jar
│ └── slf4j-simple-2.0.13.jar
└── test
├── modules
├── apiguardian-api-1.1.2.jar
├── jsoup-1.18.1.jar
├── junit-jupiter-5.11.0.jar
├── junit-jupiter-api-5.11.0.jar
├── junit-jupiter-engine-5.11.0.jar
├── junit-jupiter-params-5.11.0.jar
├── junit-platform-commons-1.11.0.jar
├── junit-platform-console-standalone-1.11.0.jar
├── junit-platform-engine-1.11.0.jar
└── opentest4j-1.3.0.jar
bld
projects use semantic versioning
for its projects. Dependencies that also use semantic versioning, use the precedence
rules defined by that specification. When a dependency version can't be parsed as a
semantic version, bld
will fall back to a generic version that uses the exact same
complex rules as those that Maven uses in this case. This allows bld
to support any
existing Maven artifact versioning scheme, while promoting a more standardized approach
for its own projects.
When no version number is specified for a dependency, bld
will look for the latest
version in the specified repositories and use that for the dependency in question.
When dependency trees get bigger, you'll start seeing the same dependencies being pulled
in by others. 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.
As detailed in Sensitive and Common Data, bld
allows you
to use RIFE2's hierarchical properties
infrastructure to pass properties into your project. The same hierarchical properties
function with bld
extensions with the bld-wrapper.properties
file being
the final property collection.
Here's an overview of how the property collection hierarchies work for your bld
project and for the extension bld
wrapper. Please refer to the Sensitive and Common Data
section for more details:
Project Properties Bld Wrapper Properties
↓ ↓
Java System Properties Java System Properties
↓ ↓
[Local Properties File] [Local Properties File]
↓ ↓
[Bld Properties File] [Bld Properties File]
↓ ↓
[Custom Properties File] [Custom Properties File]
↓ ↓
System Env Variables System Env Variables
bld
supports a special property format that allows you to override the version of
any dependency that is encountered in your project or extensions. All that is required
is to use a property key that starts with bld.override
somewhere in the property
hierarchy, and then to list the dependencies you want to override, seperated by commas.
For instance:
bld.override=org.jsoup:jsoup:1.17.1,org.slf4j:slf4j-simple:2.0.12
For clarity this can also be written as such, as long as each key starts with bld.override
:
bld.override-jsoup=org.jsoup:jsoup:1.17.1
bld.override-slf4j=org.slf4j:slf4j-simple:2.0.12
There are so many use-cases for this, like making sure your organization only uses a particular version of a dependency throughout, overriding a transitive dependency in your extensions, trying out new dependency versions before fully committing, and more ...
For example, typing this:
./bld -Dbld.override=org.jsoup:jsoup:1.17.1,org.slf4j:slf4j-simple:2.0.12 \
download purge compile test
Allows you to quickly check if your project compiles with different dependency versions and if the tests still pass, without having to make a change to the project file itself.
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 ... exists
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 ... exists
Downloading: …/org/eclipse/jetty/jetty-server/12.0.12/jetty-server-12.0.12.jar ... exists
Downloading: …/org/eclipse/jetty/jetty-session/12.0.12/jetty-session-12.0.12.jar ... exists
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 ... exists
Downloading: …/org/eclipse/jetty/jetty-io/12.0.12/jetty-io-12.0.12.jar ... exists
Downloading: …/org/eclipse/jetty/jetty-util/12.0.12/jetty-util-12.0.12.jar ... exists
Downloading: …/org/slf4j/slf4j-simple/2.0.12/slf4j-simple-2.0.12.jar ... done
Downloading: …/org/jsoup/jsoup/1.17.1/jsoup-1.17.1.jar ... done
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.
Deleting from standalone:
slf4j-simple-2.0.13.jar
Deleting from test:
jsoup-1.18.1.jar
Purging finished successfully.
Compilation finished successfully.
Test plan execution started. Number of static tests: 2
╷
├─ JUnit Jupiter
│ ├─ MyappTest
│ │ ├─ verifyHello()
│ │ │ tags: []
│ │ │ uniqueId: [engine:junit-jupiter]/[class:com.example.MyappTest]/[method:verifyHello()]
│ │ │ parent: [engine:junit-jupiter]/[class:com.example.MyappTest]
│ │ │ source: MethodSource [className = 'com.example.MyappTest', methodName = 'verifyHello', methodParameterTypes = '']
│ │ │ duration: 99 ms
│ │ │ status: ✔ SUCCESSFUL
│ │ ├─ verifyRoot()
│ │ │ tags: []
│ │ │ uniqueId: [engine:junit-jupiter]/[class:com.example.MyappTest]/[method:verifyRoot()]
│ │ │ parent: [engine:junit-jupiter]/[class:com.example.MyappTest]
│ │ │ source: MethodSource [className = 'com.example.MyappTest', methodName = 'verifyRoot', methodParameterTypes = '']
│ │ │ duration: 2 ms
│ │ │ status: ✔ SUCCESSFUL
│ └─ MyappTest finished after 111 ms.
└─ JUnit Jupiter finished after 118 ms.
Test plan execution finished. Number of all tests: 2
Test run finished after 134 ms
[ 2 containers found ]
[ 0 containers skipped ]
[ 2 containers started ]
[ 0 containers aborted ]
[ 2 containers successful ]
[ 0 containers failed ]
[ 2 tests found ]
[ 0 tests skipped ]
[ 2 tests started ]
[ 0 tests aborted ]
[ 2 tests successful ]
[ 0 tests failed ]
Next learn more about Team Setup