Skip to content

Commit 4a48a27

Browse files
romtsnclaude
andcommitted
fix(spring-boot2): replace from() with doLast JAR patching for spring metadata
The from() approach with DuplicatesStrategy.INCLUDE doesn't work because dependency JARs' spring.factories overwrites the pre-merged version. Instead, let the shadow JAR build normally, then use a doLast action to replace the Spring metadata files in the built JAR with the properly merged versions using the NIO ZIP filesystem API. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 8ae3c9c commit 4a48a27

File tree

5 files changed

+90
-16
lines changed

5 files changed

+90
-16
lines changed

sentry-samples/sentry-samples-netflix-dgs/build.gradle.kts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import java.net.URI
2+
import java.nio.file.FileSystems
3+
import java.nio.file.Files
4+
import java.nio.file.StandardCopyOption
15
import java.util.zip.ZipFile
26
import org.jetbrains.kotlin.config.KotlinCompilerVersion
37
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -83,10 +87,19 @@ tasks.shadowJar {
8387
dependsOn(mergeSpringMetadata)
8488
manifest { attributes["Main-Class"] = "io.sentry.samples.netflix.dgs.NetlixDgsApplication" }
8589
archiveClassifier.set("")
86-
from(mergeSpringMetadata.map { project.layout.buildDirectory.dir("merged-spring-metadata") }) {
87-
duplicatesStrategy = DuplicatesStrategy.INCLUDE
88-
}
8990
mergeServiceFiles()
91+
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata/META-INF")
92+
doLast {
93+
val jarFile = archiveFile.get().asFile
94+
val metaDir = metadataDir.get().asFile
95+
if (!metaDir.exists()) return@doLast
96+
val uri = URI.create("jar:${jarFile.toURI()}")
97+
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
98+
metaDir.listFiles()?.forEach { merged ->
99+
Files.copy(merged.toPath(), fs.getPath("META-INF/${merged.name}"), StandardCopyOption.REPLACE_EXISTING)
100+
}
101+
}
102+
}
90103
}
91104

92105
tasks.jar {

sentry-samples/sentry-samples-spring-boot-opentelemetry-noagent/build.gradle.kts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import java.net.URI
2+
import java.nio.file.FileSystems
3+
import java.nio.file.Files
4+
import java.nio.file.StandardCopyOption
15
import java.util.zip.ZipFile
26
import org.jetbrains.kotlin.config.KotlinCompilerVersion
37
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -124,10 +128,19 @@ tasks.shadowJar {
124128
dependsOn(mergeSpringMetadata)
125129
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
126130
archiveClassifier.set("")
127-
from(mergeSpringMetadata.map { project.layout.buildDirectory.dir("merged-spring-metadata") }) {
128-
duplicatesStrategy = DuplicatesStrategy.INCLUDE
129-
}
130131
mergeServiceFiles()
132+
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata/META-INF")
133+
doLast {
134+
val jarFile = archiveFile.get().asFile
135+
val metaDir = metadataDir.get().asFile
136+
if (!metaDir.exists()) return@doLast
137+
val uri = URI.create("jar:${jarFile.toURI()}")
138+
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
139+
metaDir.listFiles()?.forEach { merged ->
140+
Files.copy(merged.toPath(), fs.getPath("META-INF/${merged.name}"), StandardCopyOption.REPLACE_EXISTING)
141+
}
142+
}
143+
}
131144
}
132145

133146
tasks.jar {

sentry-samples/sentry-samples-spring-boot-opentelemetry/build.gradle.kts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import java.net.URI
2+
import java.nio.file.FileSystems
3+
import java.nio.file.Files
4+
import java.nio.file.StandardCopyOption
15
import java.util.zip.ZipFile
26
import org.jetbrains.kotlin.config.KotlinCompilerVersion
37
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -120,10 +124,19 @@ tasks.shadowJar {
120124
dependsOn(mergeSpringMetadata)
121125
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
122126
archiveClassifier.set("")
123-
from(mergeSpringMetadata.map { project.layout.buildDirectory.dir("merged-spring-metadata") }) {
124-
duplicatesStrategy = DuplicatesStrategy.INCLUDE
125-
}
126127
mergeServiceFiles()
128+
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata/META-INF")
129+
doLast {
130+
val jarFile = archiveFile.get().asFile
131+
val metaDir = metadataDir.get().asFile
132+
if (!metaDir.exists()) return@doLast
133+
val uri = URI.create("jar:${jarFile.toURI()}")
134+
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
135+
metaDir.listFiles()?.forEach { merged ->
136+
Files.copy(merged.toPath(), fs.getPath("META-INF/${merged.name}"), StandardCopyOption.REPLACE_EXISTING)
137+
}
138+
}
139+
}
127140
}
128141

129142
tasks.jar {

sentry-samples/sentry-samples-spring-boot-webflux/build.gradle.kts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import java.net.URI
2+
import java.nio.file.FileSystems
3+
import java.nio.file.Files
4+
import java.nio.file.StandardCopyOption
15
import java.util.zip.ZipFile
26
import org.jetbrains.kotlin.config.KotlinCompilerVersion
37
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -93,10 +97,19 @@ tasks.shadowJar {
9397
dependsOn(mergeSpringMetadata)
9498
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
9599
archiveClassifier.set("")
96-
from(mergeSpringMetadata.map { project.layout.buildDirectory.dir("merged-spring-metadata") }) {
97-
duplicatesStrategy = DuplicatesStrategy.INCLUDE
98-
}
99100
mergeServiceFiles()
101+
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata/META-INF")
102+
doLast {
103+
val jarFile = archiveFile.get().asFile
104+
val metaDir = metadataDir.get().asFile
105+
if (!metaDir.exists()) return@doLast
106+
val uri = URI.create("jar:${jarFile.toURI()}")
107+
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
108+
metaDir.listFiles()?.forEach { merged ->
109+
Files.copy(merged.toPath(), fs.getPath("META-INF/${merged.name}"), StandardCopyOption.REPLACE_EXISTING)
110+
}
111+
}
112+
}
100113
}
101114

102115
tasks.jar {

sentry-samples/sentry-samples-spring-boot/build.gradle.kts

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import java.net.URI
2+
import java.nio.file.FileSystems
3+
import java.nio.file.Files
4+
import java.nio.file.StandardCopyOption
15
import java.util.zip.ZipFile
26
import org.jetbrains.kotlin.config.KotlinCompilerVersion
37
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@@ -122,11 +126,29 @@ tasks.shadowJar {
122126
dependsOn(mergeSpringMetadata)
123127
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
124128
archiveClassifier.set("")
125-
// Pre-merged Spring metadata files must come first so they win over duplicates from JARs
126-
from(mergeSpringMetadata.map { project.layout.buildDirectory.dir("merged-spring-metadata") }) {
127-
duplicatesStrategy = DuplicatesStrategy.INCLUDE
128-
}
129129
mergeServiceFiles()
130+
131+
// After the shadow JAR is built, replace Spring metadata files with pre-merged versions.
132+
// Shadow 9.x's `append` transformer doesn't properly merge these files because
133+
// DuplicatesStrategy is enforced before transformers run.
134+
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata/META-INF")
135+
doLast {
136+
val jarFile = archiveFile.get().asFile
137+
val metaDir = metadataDir.get().asFile
138+
if (!metaDir.exists()) return@doLast
139+
val uri = URI.create("jar:${jarFile.toURI()}")
140+
val env = mapOf("create" to "false")
141+
FileSystems.newFileSystem(uri, env).use { fs ->
142+
metaDir.listFiles()?.forEach { merged ->
143+
val target = fs.getPath("META-INF/${merged.name}")
144+
Files.copy(
145+
merged.toPath(),
146+
target,
147+
StandardCopyOption.REPLACE_EXISTING,
148+
)
149+
}
150+
}
151+
}
130152
}
131153

132154
tasks.jar {

0 commit comments

Comments
 (0)