From a22a9432139a2725cd42e8e4d624e164e8d00a06 Mon Sep 17 00:00:00 2001 From: Ivo Smid Date: Sun, 28 Sep 2025 20:12:53 +0200 Subject: [PATCH] Support MountableFile when build by GraalVM as native-build We extract resource to temp path and then mount this path, as we already do with .jar resources. --- .../testcontainers/utility/MountableFile.java | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/core/src/main/java/org/testcontainers/utility/MountableFile.java b/core/src/main/java/org/testcontainers/utility/MountableFile.java index a8a9f465a19..23b7fcaf452 100644 --- a/core/src/main/java/org/testcontainers/utility/MountableFile.java +++ b/core/src/main/java/org/testcontainers/utility/MountableFile.java @@ -170,6 +170,7 @@ private static String unencodeResourceURIToFilePath(@NotNull final String resour .decode(resource.replaceAll("\\+", "%2B"), Charsets.UTF_8.name()) .replaceFirst("jar:", "") .replaceFirst("file:", "") + .replaceFirst("resource:", "") .replaceAll("!.*", ""); } catch (UnsupportedEncodingException e) { throw new IllegalStateException(e); @@ -217,6 +218,8 @@ private String resolveFilesystemPath() { private String getResourcePath() { if (path.contains(".jar!")) { resourcePath = extractClassPathResourceToTempLocation(this.path); + } else if (this.path.startsWith("resource:")) { + this.resourcePath = extractClassPathGraalVMResourceToTempLocation(this.path); } else { resourcePath = unencodeResourceURIToFilePath(path); } @@ -270,6 +273,54 @@ private String extractClassPathResourceToTempLocation(final String hostPath) { } } + private String extractClassPathGraalVMResourceToTempLocation(String hostPath) { + File tmpLocation = createTempDirectory(); + //noinspection ResultOfMethodCallIgnored + tmpLocation.delete(); + + String urldecodedResourcePath = unencodeResourceURIToFilePath(hostPath); + if (urldecodedResourcePath.startsWith("/")) { + urldecodedResourcePath = urldecodedResourcePath.replaceFirst("/", ""); + } + + try { + log.debug( + "Copying classpath GraalVM resource(s) from {} to {} to permit Docker to bind", + hostPath, + tmpLocation + ); + + try ( + InputStream is = Thread + .currentThread() + .getContextClassLoader() + .getResourceAsStream(urldecodedResourcePath) + ) { + if (is == null) { + throw new IllegalStateException( + urldecodedResourcePath + + " not found in classpath, probably need to update GraalVM's reachability-metadata.json" + ); + } + Files.copy(is, tmpLocation.toPath()); + } + } catch (IOException e) { + throw new IllegalStateException( + "Failed to process GraalVM file when extracting classpath resource: " + hostPath, + e + ); + } + + // Mark temporary files/dirs for deletion at JVM shutdown + deleteOnExit(tmpLocation.toPath()); + + try { + return tmpLocation.getCanonicalPath(); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + private File createTempDirectory() { try { if (SystemUtils.IS_OS_MAC) {