diff --git a/build.gradle b/build.gradle index 0f51f9c..39a7d39 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,7 @@ plugins { id "signing" id "io.github.gradle-nexus.publish-plugin" version "1.3.0" id 'com.vanniktech.maven.publish' version '0.30.0' + id 'com.gradleup.shadow' version '8.3.5' } group 'ai.chalk' @@ -47,6 +48,35 @@ dependencies { testImplementation 'org.slf4j:slf4j-simple:2.0.9' } +// Self-contained "shaded" jar: relocates ALL third-party deps into ai.chalk.shaded.* so the artifact +// is immune to whatever versions a consumer (or their Flink runtime) pins. Flink is compileOnly, so +// it is not bundled (stays provided by the cluster). Publish as the `shaded` classifier. +shadowJar { + archiveClassifier = 'shaded' + mergeServiceFiles() // rewrite META-INF/services (grpc providers, jackson, etc.) to shaded names + + // slf4j-api is the logging facade — let the runtime (Flink) own it exclusively, so there's no + // facade version skew (1.x vs 2.x binding). chalk-java's org.slf4j refs bind to the runtime's. + dependencies { exclude(dependency('org.slf4j:slf4j-api')) } + + relocate 'com.google', 'ai.chalk.shaded.google' // protobuf, guava, gson, flatbuffers, api-protos + relocate 'io.grpc', 'ai.chalk.shaded.grpc' // incl. grpc-netty-shaded + relocate 'io.netty', 'ai.chalk.shaded.netty' // arrow-memory-netty (pure JVM here) + relocate 'io.perfmark', 'ai.chalk.shaded.perfmark' + relocate 'com.fasterxml.jackson', 'ai.chalk.shaded.jackson' + relocate 'org.apache.arrow', 'ai.chalk.shaded.arrow' + relocate 'org.apache.commons', 'ai.chalk.shaded.commons' // codec, io, compress, lang3 + relocate 'org.yaml.snakeyaml', 'ai.chalk.shaded.snakeyaml' + relocate 'org.checkerframework', 'ai.chalk.shaded.checkerframework' + relocate 'org.codehaus.mojo', 'ai.chalk.shaded.mojo' + // Intentionally NOT relocated: + // ai.chalk.* -> the public API (consumers import these) + // org.slf4j -> logging facade; must bind to the runtime's logging + // javax.annotation -> standard annotations, no conflict + // com.github.luben -> zstd-jni: native JNI, relocating its package breaks the .so binding + // org.apache.flink.* -> provided by the cluster (compileOnly, not bundled) +} + test { useJUnitPlatform() jvmArgs '--add-opens=java.base/java.nio=ALL-UNNAMED' @@ -124,4 +154,34 @@ mavenPublishing { url = 'https://github.com/chalk-ai/chalk-java/' } } +} + +// Second coordinate: ai.chalk:chalk-java-shaded. Identical classes to chalk-java, but every +// third-party dependency is relocated into ai.chalk.shaded.* (see the shadowJar block). Its POM +// declares only slf4j-api (a non-relocatable logging facade) — every other dep lives inside the jar, +// so a consumer pinned to older protobuf/grpc/jackson/arrow/netty never gets a conflicting transitive +// pulled in. Built as a manual publication (not `from components.java`) to keep the POM minimal. +publishing { + publications { + shaded(MavenPublication) { + artifactId = 'chalk-java-shaded' + // Publish the shaded jar as the module's main artifact (strip the 'shaded' classifier). + artifact(tasks.shadowJar) { classifier = null } + // POM name/license/scm/developers are applied to all publications by the vanniktech + // mavenPublishing block below. The ONLY declared dependency is slf4j-api: bundled + // arrow/netty classes reference org.slf4j, but it is not relocatable (it's a logging + // facade that must bind to the runtime's logging). Declaring it guarantees the class is + // present for any consumer; in a Flink runtime, Flink parent-first-loads org.slf4j, so + // its own version always wins regardless of what we declare. Everything else is bundled + + // relocated inside the jar, so no other (conflict-prone) dependency is declared. + pom.withXml { + def deps = asNode().appendNode('dependencies') + def slf4j = deps.appendNode('dependency') + slf4j.appendNode('groupId', 'org.slf4j') + slf4j.appendNode('artifactId', 'slf4j-api') + slf4j.appendNode('version', '2.0.9') + slf4j.appendNode('scope', 'runtime') + } + } + } } \ No newline at end of file