While providing a solution customized for many customers, you might want to package an application artefact in multiple flavours. Each with a set of dependencies to provide just the customer specific implementations.
With gradle this can be accomplished fairly easy. To demonstrate it, I’ve created an example project available on github.
It consists of five modules:
- an application module
- an API interface module
- three modules as API implementations
The API interface module is not needed during runtime but helpful during development time. It helps to enforce the same expected interface in the implementation classes.
lib-impl* modules contain each a custom implementation for the
CustomDataProvider and demonstrate the different flavours of the artefacts.
Now, the question is how to provide several artefacts of the application, each bundled with one of the library implementations.
One solution (as always, there a probably many possible out there) is to use Gradle configurations with the Shadow Plugin. Using the shadow plugin is the exchangeable part here. As we basically do rely on the grade configurations, the way the application is package is completely open and this solution can probably also be applied to other packaging plugins.
Having a look at the
build.gradle of the application module reveals that we create a configuration for each flavour we want to have a seperate artefact for.
Now, we add the dependencies…
To make it easier to execute sub-steps of the build, it’s nice to have a task for each artefact to be generated.
Thus we need a way to dynamically add build tasks for each variant we want to build.
In our case the type of such is a
To make this concise, clean and easy to extend, we can use the Gradle DSL based on Groovy.
First, we define a array of the variants we want:
And then we use that array to loop over and create the build tasks:
classifierproperty is used to get an distingushable artefact name.
configurations make up the thing comined together into the shadowJar artefact.
If you need to apply the base idea of this article to another packaging context, those two properties are probably those you want to take and apply accordingly.
To get executeable jar artefacts, we define the
Main-Class name as an attribute for the manifest.
ShadowJar usually adopts it automatically when the application plugin is used,
but as we are using a custom shadowJar task here, we also need to apply it with those three lines.
Finally, by defining the dependency with
dependsOn, we can afterwards just type
gradle shadowJar to have all variants build and waiting for us in
Execution shows the expected behaviour for each of them:
Have fun building the solutions that make your customers happy! 😃