I am unsure how to title the issue, or how many issues should I create. There seems to be general problem in Spring's Resource when using NIO.2 FileSystem that's not default filesystem.

For reference, I have used ZipFileSystem that's part of JDK and does not require any additional dependencies

https://docs.oracle.com/en/java/javase/17/docs/api/jdk.zipfs/module-summary.html

When constructing a java.nio.file.Path using FileSystem other than default filesystem, its Path::toFile will always throw UnsupportedOperationException

https://docs.oracle.com/javase/8/docs/api/java/nio/file/Path.html#toFile--

Spring's Resource exposes Resource::getFile, and FileSystemResource, which accepts java.nio.file.Path in its constructor, will always end up calling Path::toFile whenever Resource::getFile is called.

It might be a great idea to go through all Resource::getFile usages and replace them with other calls wherever possible. So far, the calls that I've stumbled upon are used to either get the file size or to get the Path itself.

I have stubled upon FileSystemResource handling in Spring WebFlux response, where it explicitly calls "resource.getFile()" only to get its size

https://github.com/spring-projects/spring-framework/blob/main/spring-web/src/main/java/org/springframework/http/codec/ResourceHttpMessageWriter.java#L196-L198

Problem may be reproduced using https://github.com/krezovic/spring-nio-resource by simply running ./mvnw clean verify

I have also added another test that circumvents Resource machinery, and that one works as expected.

Another usage can be found in DataBufferUtils::read, which is called from ResourceRegionEncoder, which is called from ResourceHttpMessageWriter

https://github.com/spring-projects/spring-framework/blob/main/spring-core/src/main/java/org/springframework/core/io/buffer/DataBufferUtils.java#L226

Final issue I have found with NIO.2 and Spring Framework is in FileSystemUtils::copyRecursively, where on Windows I get a ProviderMismatchException

java.nio.file.ProviderMismatchException
    at java.base/sun.nio.fs.WindowsPath.toWindowsPath(WindowsPath.java:389)
    at java.base/sun.nio.fs.WindowsPath.resolve(WindowsPath.java:596)
    at java.base/sun.nio.fs.WindowsPath.resolve(WindowsPath.java:42)
    at org.springframework.util.FileSystemUtils$2.preVisitDirectory(FileSystemUtils.java:133)
    at org.springframework.util.FileSystemUtils$2.preVisitDirectory(FileSystemUtils.java:130)
    at java.base/java.nio.file.Files.walkFileTree(Files.java:2816)
    at org.springframework.util.FileSystemUtils.copyRecursively(FileSystemUtils.java:130)

Test is available in reproducer. This way one can easily unpack a ZIP file.

Comment From: jhoeller

I'm addressing your overall case with a new Path getFilePath() method in the Resource interface, defaulting to getFile().toPath() but overridden to return the Path directly in FileSystemResource (and also in the deprecated PathResource). This new method is being used in the above-mentioned places now for consistent support for non-default file systems. This will be available in 7.0 M9.

For 6.2.11, I consider adding UnsupportedOperationException to those two existing IOException catch blocks that are meant to lead to the corresponding fallback code path. While this would not use the optimized zero-copy code path yet (like in 7.0), it would gracefully fall back to regular channel access at least.