We will use the Phylonco project as an example, to learn how to setup project dependencies, and understand the difference between consumers and producers.
After the version and base name are defined, the second block declares the
The first dependency is lphy module.
implementation is a Gradle pre-defined
to resolve dependencies.
The string inside implementation defines GAV coordinate (Group, Artifact, Version),
which will map to a unique corresponding version of a software from all releases.
It also can be used as a keyword to search in the Maven central repo, for example,
the group io.github.linguaphylo.
We use the default model “require”
declaring versions, such as
This implies that the selected version of lphy cannot be lower than 1.3.1
but could be higher through conflict resolution, when there are multiple versions in the local dependency repository.
When the exact version is required, the “strictly”
declaring versions can be used.
For example, if only lphy 1.2.0 is required, you can use
The second dependency is lphy-studio module, because we want to run the studio from this project.
But it certainly should not be required by the code, which has no GUI extension.
runtimeOnly configuration is used.
The third dependency is only used for unit tests.
Using module dependencies, you do not have to worry about any manual process to load the dependency tree of lphy module. They will be automatically downloaded into your Gradle local repository when you first build, according to the dependencies declared in the pom.xml created by publishing task.
Updating your dependencies is important. IntelliJ provides a nice UI for the Gradle project to manage the dependencies.
The BEAST 2 and its packages are not using the GAV and Maven central repo mechanism, so that we have to use the file dependencies to host their dependencies in Gradle. In order to recognise the version, we rename the released BEAST 2 jars into a format similar with GAV, where the package name follows the version.
is declared for BEAST 2 and BEASTLabs, which means these 2 jars will be exposed to consumers,
which means, for instance, the dependencies of subproject “phylonco-lphybeast” has already included these 2 jars,
because it depends on this subproject.
So, we do not have to replicate jars in the “phylonco-lphybeast”
But please use
api wisely and
be respectful of consumers.
The list of available BEAST 2 packages and their package dependencies can be seen from Package Viewer or Package Manager. If you change the drop-down list from the default XML into “packages-extra.xml” in Package Viewer, you can find the webpage to list both “lphybeast” package and “Phylonco” package. Alternatively, you can find the BEAST 2 package dependencies from the version.xml.
This subproject integrates all LPhy components and BEAST 2 components, so its dependencies must include LPhy and its extension, BEAST 2 and its extensions, LPhyBEAST core, and all of their dependencies.
In Figure 4, the first
implementation uses GAV to import the LPhy core into the dependencies.
The second loads the module “phylonco-lphy”, which is the LPhy extension, as
We recommend to always use GAV if possible, but at the time of writing,
“phylonco-lphy” has not been published to the Maven central repo yet.
implementation loads the module “phylonco-beast”. Referring to the section 2,
we defined the BEAST 2’s and BEASTLabs’ dependency configuration type as
Therefore, this project dependences (
project(":phylonco-beast")) include these two jars.
Moreover, the last
implementation imports the rest of required BEAST 2 libraries from the
In the middle, there is a
zippedConfig to import LPhyBEAST core into the dependencies.
It is a zip file, so we have to use another task named as
installLPhyBEAST to unzip it,
and pass all of jar file names in its
lib folder into a Gradle property “lblibs”.
Then, the next
implementation loads all jar file names stored in “lblibs”.
You can find all these jars from the External Libraries in IntelliJ’s project view.
Understanding your role
Producers and consumers are introduced by the dependency management with Gradle. We strongly recommend you read the linked article to understand the roles.
Please note project dependencies across different repositories are absolutely discouraged by Gradle, due to the encapsulation. This also helps to distinguish the responsibilities of producers and consumers. The producer has the responsibility to provide the reliable version of the software, and use the transitive dependency wisely. It is the consumer’s responsibility to decide what version of the library to use. The consumers should always consume the released or published version, not the latest version of the repository. But a snapshot version built from the latest code can be used only for an emergency situation or testing. This principle allows the developer in a consumer role to focus on one version to develop or extend, so as to produce a stable version of his software.
So the developers cannot load multiple projects (repositories) into the same window of IntelliJ anymore, even though one depends on another project. Therefore, for convenience of consumers, the producer has to provide the source code during the release.
Gradle alos introduces a useful feature, the variant model, which allows a producer creates different releases using the same source code for different kinds of consumers.