From 105f81bd598b7c8e2152b1b1f5f20a7af96cd1e2 Mon Sep 17 00:00:00 2001 From: Guillermo Calvo Date: Fri, 10 Nov 2023 09:31:59 +0100 Subject: [PATCH] Make `DefaultClassPathResourceLoader` handle URLs with format `jar:file:/{JAR_PATH}!/{PREFIX}!/{RESOURCE}` gracefully (#10092) --- .../scan/DefaultClassPathResourceLoader.java | 11 ++++++ .../DefaultClassPathResourceLoaderSpec.groovy | 32 ++++++++++++++++++ core/src/test/resources/test.war | Bin 0 -> 435 bytes 3 files changed, 43 insertions(+) create mode 100644 core/src/test/groovy/io/micronaut/core/io/scan/DefaultClassPathResourceLoaderSpec.groovy create mode 100644 core/src/test/resources/test.war diff --git a/core/src/main/java/io/micronaut/core/io/scan/DefaultClassPathResourceLoader.java b/core/src/main/java/io/micronaut/core/io/scan/DefaultClassPathResourceLoader.java index 1c1fb60ccb7..2c242e500a8 100644 --- a/core/src/main/java/io/micronaut/core/io/scan/DefaultClassPathResourceLoader.java +++ b/core/src/main/java/io/micronaut/core/io/scan/DefaultClassPathResourceLoader.java @@ -35,10 +35,12 @@ import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.ProviderNotFoundException; +import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.Map; import java.util.Optional; +import java.util.stream.Collectors; import java.util.stream.Stream; import org.slf4j.helpers.NOPLogger; @@ -147,6 +149,15 @@ public Optional getResourceAsStream(String path) { } } Path pathObject = fileSystem.getPath(path); + if (!Files.exists(pathObject) && uri.toString().contains("!/")) { + // Gracefully transform a URL: "jar:file:/{JAR_PATH}!/{PREFIX}!/{RESOURCE}" to path: "{PREFIX}/{RESOURCE}" + final String altPath = Arrays.stream(uri.toString().split("\\!\\/")).skip(1).collect(Collectors.joining("/")); + final Path altPathObject = fileSystem.getPath(altPath); + if (Files.exists(altPathObject) && !Files.isDirectory(pathObject)) { + // Use this path only if the resource exists at that location + pathObject = altPathObject; + } + } if (Files.isDirectory(pathObject)) { return Optional.empty(); } diff --git a/core/src/test/groovy/io/micronaut/core/io/scan/DefaultClassPathResourceLoaderSpec.groovy b/core/src/test/groovy/io/micronaut/core/io/scan/DefaultClassPathResourceLoaderSpec.groovy new file mode 100644 index 00000000000..165ba900012 --- /dev/null +++ b/core/src/test/groovy/io/micronaut/core/io/scan/DefaultClassPathResourceLoaderSpec.groovy @@ -0,0 +1,32 @@ +package io.micronaut.core.io.scan + +import spock.lang.Specification +import spock.lang.Subject +import spock.mock.MockFactory + +class DefaultClassPathResourceLoaderSpec extends Specification { + + ClassLoader parent = Mock() { + getResource(_) >> { + args -> new URL("jar:" + this.class.classLoader.getResource("test.war") + "!/WEB-INF/classes!/" + args[0]) + } + } + + @Subject + DefaultClassPathResourceLoader loader = new DefaultClassPathResourceLoader(parent) + + def 'get file resource in war file'() { + when: + Optional input = loader.getResourceAsStream("application.yml") + then: + !input.empty + input.get().text.contains("application configuration") + } + + def 'no such resource in war file'() { + when: + Optional input = loader.getResourceAsStream("no-such-file.yml") + then: + input.empty + } +} diff --git a/core/src/test/resources/test.war b/core/src/test/resources/test.war new file mode 100644 index 0000000000000000000000000000000000000000..98e0b88ce55529cb525125d50d9fe9742c332c41 GIT binary patch literal 435 zcmWIWW@Zs#VBp|j$Z1FqX8-~w5CH@nKpgJsr0ePDrq9d}fK#0SlDg!a#Ny)AVuX62 zDPMy!!*6$*v?&ACsRFS)7WIh*1v#0?i6xo&d3u$(Il*BbIvOWV`uORbJaazSCyl)VY*zDukwJpNp#DwXJE2>QFj{Vzg+GWN;LXYg PQo{^{Pl5Cf5QhN(KOtN; literal 0 HcmV?d00001