buildlogic.pf-module-conventions.gradle.kts1 plugins { 2 id("java-library") 3 }
java-library extends java with api vs implementation separation. When module A applies this plugin and uses api() to declare a dependency, that dependency leaks to consumers of module A. This matters for the plugin system: plugins depend on ProjectForge modules via api dependencies.
5 repositories { 6 mavenLocal() 7 gradlePluginPortal() 8 maven { url = uri("https://oss.sonatype.org/content/repositories/public/") } 9 maven { url = uri("https://repo.maven.apache.org/maven2/") } 10 maven { url = uri("https://raw.githubusercontent.com/gephi/gephi/mvn-thirdparty-repo/") } 11 }
Five repository sources, searched in order:
| Line | Repository | Purpose |
|---|---|---|
| 6 | mavenLocal() | Local ~/.m2/repository — for locally built artifacts during development |
| 7 | gradlePluginPortal() | Gradle plugins — Spring Boot plugin, etc. |
| 8 | Sonatype OSS | Snapshot and staging releases |
| 9 | Maven2 | Standard Maven repository mirror |
| 10 | gephi/gephi GitHub | Gephi — graph visualization library used by ProjectForge for network diagrams |
13 val libs = project.extensions.getByType<VersionCatalogsExtension>().named("libs") 14 15 // libs.versions etc. not available in buildSrc. Must use findVersion and findLibrary instead. 16 17 group = "org.projectforge" 18 version = libs.findVersion("org.projectforge").get().requiredVersion
libs.versions.xxx shorthand that works in regular build.gradle.kts files does NOT work inside buildSrc/ convention plugins. Instead, you must use findVersion() and findLibrary() as shown on line 13 and throughout this file.Line 13: Gets the version catalog extension by type — the only way to access it in buildSrc.
Line 17: Sets group = "org.projectforge" — identical to the root build.gradle.kts line 8. Duplicated here because buildSrc is a separate project.
Line 18: Reads the version from the catalog (libs.versions.toml) — no hardcoded version number.
20 extensions.configure<JavaPluginExtension> { 21 sourceCompatibility = JavaVersion.VERSION_17 22 targetCompatibility = JavaVersion.VERSION_17 23 } 24 25 tasks.withType<JavaCompile> { 26 options.encoding = "UTF-8" 27 options.isIncremental = true 28 options.release.set(17) 29 }
Lines 21–22: sourceCompatibility and targetCompatibility — tell Gradle which Java version the source code uses (17) and which bytecode version to produce (17). These control language features and compilation output.
Line 28: options.release.set(17) — the --release 17 compiler flag. This is stronger than sourceCompatibility alone — it restricts the compiler to only Java 17 API symbols. Without this, building on JDK 21 could produce bytecode referencing Java 18+ APIs that don't exist on JDK 17, causing UnsupportedClassVersionError at runtime.
Why Java 17? It's the current LTS version supported by Spring Boot 3.x (required minimum). ProjectForge uses Kotlin which compiles to JVM bytecode, so the JDK version matters for both languages.
30 /* 31 tasks.withType<KotlinCompile> { 32 compilerOptions { 33 jvmTarget.set(JvmTarget.JVM_17) 34 } 35 }*/
Kotlin JVM target 17 — currently commented out. Kotlin compiles to 1.8 (Java 8) bytecode by default, which is compatible with Java 17. The file uses options.release = 17 on line 28 for Java files. The Kotlin equivalent would be uncommented when the project explicitly needs Java 17 Kotlin bytecode.
37 tasks.withType<Test> { 38 useJUnitPlatform() 39 }
Enables JUnit 5 (Jupiter) for all test tasks across all modules. Without this, Gradle defaults to JUnit 4. ProjectForge migrated from mixed TestNG + JUnit4 to pure JUnit5 in commits like 20e07f9d1.
45 configurations.all { 46 resolutionStrategy { 47 preferProjectModules() 48 // Force all Jackson module versions to match project's explicit Jackson version. 49 // Transitive dependencies (e.g. ez-vcard, groovy-yaml, flyway) may pull in newer Jackson versions. 50 val jacksonVersion = libs.findVersion("com.fasterxml.jackson").get().requiredVersion 51 force("com.fasterxml.jackson:jackson-bom:$jacksonVersion") 52 force("com.fasterxml.jackson.core:jackson-core:$jacksonVersion") 53 force("com.fasterxml.jackson.core:jackson-databind:$jacksonVersion") 54 force("com.fasterxml.jackson.core:jackson-annotations:$jacksonVersion") 55 } 56 }
This is the most important section for build stability. Jackson is a transitive dependency of many libraries (ez-vcard, groovy-yaml, flyway). Each library may pull a different Jackson version, leading to runtime NoSuchMethodError or ClassNotFoundException.
How force() works: Gradle's dependency resolution collects all requested versions of Jackson across the entire dependency tree. The force() directive overrides any version — regardless of what any library requests, Jackson will be pinned to the version from libs.versions.toml.
Why four artifacts: Jackson is split into modules (jackson-core, jackson-databind, jackson-annotations) that must be version-synced. The jackson-bom (Bill of Materials) provides coordinated versions, but force() on individual artifacts is more explicit.
Without this section: Different subprojects could compile against different Jackson versions — the fat JAR would contain multiple Jackson JARs, and the classloader would pick whichever it finds first. This manifests as mysterious serialisation errors in production.
58 dependencies { 59 api(libs.findLibrary("org-jetbrains-kotlin-stdlib").get()) 60 api(libs.findLibrary("io-github-microutils-kotlin-logging").get()) 61 testImplementation(libs.findLibrary("org-junit-jupiter-api").get()) 62 testImplementation(libs.findLibrary("org-junit-jupiter-engine").get()) 63 testImplementation(libs.findLibrary("org-junit-platform-launcher").get()) 64 }
Five dependencies applied to every module:
| Dependency | Scope | Purpose |
|---|---|---|
kotlin-stdlib | api | Kotlin standard library — all modules use Kotlin |
kotlin-logging | api | Kotlin wrapper around SLF4J — microutils/kotlin-logging |
junit-jupiter-api | testImplementation | JUnit 5 test annotations (@Test, @BeforeEach) |
junit-jupiter-engine | testImplementation | JUnit 5 test execution engine |
junit-platform-launcher | testImplementation | IDE/test runner integration |
--release 17 is why ProjectForge builds on JDK 21 but runs on JDK 17.findVersion()/findLibrary() is used instead of the usual libs.versions.xxx shorthand.
This is the heart of ProjectForge's build system. Every module (
projectforge-business,projectforge-webapp, etc.) applies this plugin with one line, and gets:--release 17(builds on JDK 21, runs on JDK 17)useJUnitPlatform())