I have been experimenting with the hexagonal architecture with Gradle myself and
I have found the following setup working quite well for me.
(Please excuse for using the Kotlin DSL
as I only have one repo to demo while
time of writing this answer).
To start off, here is the package structure I follow:
<project root>
| build.gradle.kts
| ...
└─── apps
| └─── <putting everything together>
| | build.gradle.kts
| | ...
└─── core
| └─── <business logic>
| | build.gradle.kts
| | ...
└─── libs
└─── <some common lib>
| build.gradle.kts
| ...
Let's focus on build.gradle.kts
in project root:
plugins {
id("io.spring.dependency-management") version "1.0.12.RELEASE"
}
subprojects {
apply(plugin = "io.spring.dependency-management")
dependencyManagement {
dependencies {
dependency("ch.qos.logback:logback-classic:1.2.11")
dependency("org.javamoney:moneta:1.4.2")
dependency("nl.hiddewieringa:money-kotlin:1.0.1")
dependencySet("io.jsonwebtoken:0.11.5") {
entry("jjwt-api")
entry("jjwt-impl")
}
}
}
}
configure(subprojects) {
dependencies {
implementation("ch.qos.logback:logback-classic")
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
}
Quick explanation,
I am using Spring IO's Gradle plugin which enables
declaration of packages and their version across projects in one place.
If you observe, I only apply this plugin across subprojects.
Now in the configuration, I keep common configs applicable to all the subprojects.
Let's jump to core -> build.gradle.kts
:
dependencies {
api("nl.hiddewieringa:money-kotlin")
}
Here you can see the core only uses money-kotlin
(Kotlin extensions for javax.money)
which is api only.
Note that since logger is defined in the configuration for the subproject, I can use that in core logic to define logs.
Also, versions are acquired from the ones mentioned in the main Gradle file.
Something similar would go for libs -> build.gradle.kts
.
Finally apps -> build.gradle.kts
looks like:
dependencies {
api("io.jsonwebtoken:jjwt-api")
api("nl.hiddewieringa:money-kotlin")
implementation("org.javamoney:moneta")
runtimeOnly("io.jsonwebtoken:jjwt-impl")
}
Here, I am applying the actual implementation of java-money using moneta
(separating logic and api from actual impl).
Similarly, jjwt
is only applied here.
This way, all the versions are controlled in a single place. Logic gets separated out of impl details.
As I see, this covers most things needed for hexagonal pattern.
Hope it helps.