Skip to content

Commit 991221e

Browse files
romtsnclaude
andcommitted
fix(spring-boot2): use separate patchSpringMetadata task for JAR patching
The doLast on shadowJar doesn't run when the task is cached/up-to-date. Move JAR patching to a separate `patchSpringMetadata` task that is finalized by shadowJar, ensuring it always runs. Also use recursive walkTopDown to handle nested directories (e.g. META-INF/spring/). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 4a277ae commit 991221e

File tree

5 files changed

+92
-59
lines changed

5 files changed

+92
-59
lines changed

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -87,23 +87,30 @@ val mergeSpringMetadata by
8787

8888
// Configure the Shadow JAR (executable JAR with all dependencies)
8989
tasks.shadowJar {
90-
dependsOn(mergeSpringMetadata)
9190
manifest { attributes["Main-Class"] = "io.sentry.samples.netflix.dgs.NetlixDgsApplication" }
9291
archiveClassifier.set("")
9392
mergeServiceFiles()
93+
outputs.upToDateWhen { false }
94+
finalizedBy("patchSpringMetadata")
95+
}
96+
97+
tasks.register("patchSpringMetadata") {
98+
dependsOn(mergeSpringMetadata, tasks.shadowJar)
9499
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata")
100+
val jarFile = tasks.shadowJar.flatMap { it.archiveFile }
101+
inputs.dir(metadataDir)
102+
inputs.file(jarFile)
95103
doLast {
96-
val jarFile = archiveFile.get().asFile
97-
val metaDir = metadataDir.get().asFile
98-
if (!metaDir.exists()) return@doLast
99-
val uri = URI.create("jar:${jarFile.toURI()}")
104+
val baseDir = metadataDir.get().asFile
105+
val jar = jarFile.get().asFile
106+
if (!baseDir.exists()) return@doLast
107+
val uri = URI.create("jar:${jar.toURI()}")
100108
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
101-
metaDir.listFiles()?.forEach { merged ->
102-
Files.copy(
103-
merged.toPath(),
104-
fs.getPath("META-INF/${merged.name}"),
105-
StandardCopyOption.REPLACE_EXISTING,
106-
)
109+
baseDir.walkTopDown().filter { it.isFile }.forEach { merged ->
110+
val relative = merged.relativeTo(baseDir).path
111+
val target = fs.getPath(relative)
112+
if (target.parent != null) Files.createDirectories(target.parent)
113+
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
107114
}
108115
}
109116
}

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -128,23 +128,30 @@ val mergeSpringMetadata by
128128

129129
// Configure the Shadow JAR (executable JAR with all dependencies)
130130
tasks.shadowJar {
131-
dependsOn(mergeSpringMetadata)
132131
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
133132
archiveClassifier.set("")
134133
mergeServiceFiles()
134+
outputs.upToDateWhen { false }
135+
finalizedBy("patchSpringMetadata")
136+
}
137+
138+
tasks.register("patchSpringMetadata") {
139+
dependsOn(mergeSpringMetadata, tasks.shadowJar)
135140
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata")
141+
val jarFile = tasks.shadowJar.flatMap { it.archiveFile }
142+
inputs.dir(metadataDir)
143+
inputs.file(jarFile)
136144
doLast {
137-
val jarFile = archiveFile.get().asFile
138-
val metaDir = metadataDir.get().asFile
139-
if (!metaDir.exists()) return@doLast
140-
val uri = URI.create("jar:${jarFile.toURI()}")
145+
val baseDir = metadataDir.get().asFile
146+
val jar = jarFile.get().asFile
147+
if (!baseDir.exists()) return@doLast
148+
val uri = URI.create("jar:${jar.toURI()}")
141149
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
142-
metaDir.listFiles()?.forEach { merged ->
143-
Files.copy(
144-
merged.toPath(),
145-
fs.getPath("META-INF/${merged.name}"),
146-
StandardCopyOption.REPLACE_EXISTING,
147-
)
150+
baseDir.walkTopDown().filter { it.isFile }.forEach { merged ->
151+
val relative = merged.relativeTo(baseDir).path
152+
val target = fs.getPath(relative)
153+
if (target.parent != null) Files.createDirectories(target.parent)
154+
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
148155
}
149156
}
150157
}

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -124,23 +124,30 @@ val mergeSpringMetadata by
124124

125125
// Configure the Shadow JAR (executable JAR with all dependencies)
126126
tasks.shadowJar {
127-
dependsOn(mergeSpringMetadata)
128127
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
129128
archiveClassifier.set("")
130129
mergeServiceFiles()
130+
outputs.upToDateWhen { false }
131+
finalizedBy("patchSpringMetadata")
132+
}
133+
134+
tasks.register("patchSpringMetadata") {
135+
dependsOn(mergeSpringMetadata, tasks.shadowJar)
131136
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata")
137+
val jarFile = tasks.shadowJar.flatMap { it.archiveFile }
138+
inputs.dir(metadataDir)
139+
inputs.file(jarFile)
132140
doLast {
133-
val jarFile = archiveFile.get().asFile
134-
val metaDir = metadataDir.get().asFile
135-
if (!metaDir.exists()) return@doLast
136-
val uri = URI.create("jar:${jarFile.toURI()}")
141+
val baseDir = metadataDir.get().asFile
142+
val jar = jarFile.get().asFile
143+
if (!baseDir.exists()) return@doLast
144+
val uri = URI.create("jar:${jar.toURI()}")
137145
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
138-
metaDir.listFiles()?.forEach { merged ->
139-
Files.copy(
140-
merged.toPath(),
141-
fs.getPath("META-INF/${merged.name}"),
142-
StandardCopyOption.REPLACE_EXISTING,
143-
)
146+
baseDir.walkTopDown().filter { it.isFile }.forEach { merged ->
147+
val relative = merged.relativeTo(baseDir).path
148+
val target = fs.getPath(relative)
149+
if (target.parent != null) Files.createDirectories(target.parent)
150+
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
144151
}
145152
}
146153
}

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

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -97,23 +97,30 @@ val mergeSpringMetadata by
9797

9898
// Configure the Shadow JAR (executable JAR with all dependencies)
9999
tasks.shadowJar {
100-
dependsOn(mergeSpringMetadata)
101100
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
102101
archiveClassifier.set("")
103102
mergeServiceFiles()
103+
outputs.upToDateWhen { false }
104+
finalizedBy("patchSpringMetadata")
105+
}
106+
107+
tasks.register("patchSpringMetadata") {
108+
dependsOn(mergeSpringMetadata, tasks.shadowJar)
104109
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata")
110+
val jarFile = tasks.shadowJar.flatMap { it.archiveFile }
111+
inputs.dir(metadataDir)
112+
inputs.file(jarFile)
105113
doLast {
106-
val jarFile = archiveFile.get().asFile
107-
val metaDir = metadataDir.get().asFile
108-
if (!metaDir.exists()) return@doLast
109-
val uri = URI.create("jar:${jarFile.toURI()}")
114+
val baseDir = metadataDir.get().asFile
115+
val jar = jarFile.get().asFile
116+
if (!baseDir.exists()) return@doLast
117+
val uri = URI.create("jar:${jar.toURI()}")
110118
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
111-
metaDir.listFiles()?.forEach { merged ->
112-
Files.copy(
113-
merged.toPath(),
114-
fs.getPath("META-INF/${merged.name}"),
115-
StandardCopyOption.REPLACE_EXISTING,
116-
)
119+
baseDir.walkTopDown().filter { it.isFile }.forEach { merged ->
120+
val relative = merged.relativeTo(baseDir).path
121+
val target = fs.getPath(relative)
122+
if (target.parent != null) Files.createDirectories(target.parent)
123+
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
117124
}
118125
}
119126
}

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

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -126,30 +126,35 @@ val mergeSpringMetadata by
126126

127127
// Configure the Shadow JAR (executable JAR with all dependencies)
128128
tasks.shadowJar {
129-
dependsOn(mergeSpringMetadata)
130129
manifest { attributes["Main-Class"] = "io.sentry.samples.spring.boot.SentryDemoApplication" }
131130
archiveClassifier.set("")
132131
mergeServiceFiles()
132+
// Mark as never up-to-date so doLast always runs to patch Spring metadata
133+
outputs.upToDateWhen { false }
134+
finalizedBy("patchSpringMetadata")
135+
}
133136

134-
// After the shadow JAR is built, replace Spring metadata files with pre-merged versions.
135-
// Shadow 9.x's `append` transformer doesn't properly merge these files because
136-
// DuplicatesStrategy is enforced before transformers run.
137+
// Patch the shadow JAR with pre-merged Spring metadata after it's built.
138+
// Shadow 9.x's `append` transformer doesn't properly merge these files because
139+
// DuplicatesStrategy is enforced before transformers run.
140+
tasks.register("patchSpringMetadata") {
141+
dependsOn(mergeSpringMetadata, tasks.shadowJar)
137142
val metadataDir = project.layout.buildDirectory.dir("merged-spring-metadata")
143+
val jarFile = tasks.shadowJar.flatMap { it.archiveFile }
144+
inputs.dir(metadataDir)
145+
inputs.file(jarFile)
138146
doLast {
139-
val jarFile = archiveFile.get().asFile
140147
val baseDir = metadataDir.get().asFile
148+
val jar = jarFile.get().asFile
141149
if (!baseDir.exists()) return@doLast
142-
val uri = URI.create("jar:${jarFile.toURI()}")
150+
val uri = URI.create("jar:${jar.toURI()}")
143151
FileSystems.newFileSystem(uri, mapOf("create" to "false")).use { fs ->
144-
baseDir
145-
.walkTopDown()
146-
.filter { it.isFile }
147-
.forEach { merged ->
148-
val relative = merged.relativeTo(baseDir).path
149-
val target = fs.getPath(relative)
150-
if (target.parent != null) Files.createDirectories(target.parent)
151-
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
152-
}
152+
baseDir.walkTopDown().filter { it.isFile }.forEach { merged ->
153+
val relative = merged.relativeTo(baseDir).path
154+
val target = fs.getPath(relative)
155+
if (target.parent != null) Files.createDirectories(target.parent)
156+
Files.copy(merged.toPath(), target, StandardCopyOption.REPLACE_EXISTING)
157+
}
153158
}
154159
}
155160
}

0 commit comments

Comments
 (0)