FULL PRODUCT VERSION :
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.15063]
A DESCRIPTION OF THE PROBLEM :
The class com.sun.nio.zipfs.ZipPath throws a java.nio.file.ProviderMismatchException from its startsWith(Path) and endsWith(Path) methods when the argument is not an instance of ZipPath. This contradicts the javadoc for those methods as specified in the java.nio.file.Path interface, which states, "If the given path is associated with a different FileSystem to this path then false is returned."
The implementation of those methods in ZipPath should be changed to return false instead of throwing ProviderMismatchException in order to match the documented behavior.
For what it's worth, sun.nio.fs.WindowsPath conforms to that documented behavior (returning false) in both cases.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and execute the attached source code, then compare the output to the expected result.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (sun.nio.fs.WindowsFileSystemProvider)?
false
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (sun.nio.fs.WindowsFileSystemProvider)?
false
ACTUAL -
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (sun.nio.fs.WindowsFileSystemProvider)?
java.nio.file.ProviderMismatchException
at com.sun.nio.zipfs.ZipPath.checkPath(ZipPath.java:378)
at com.sun.nio.zipfs.ZipPath.startsWith(ZipPath.java:309)
at test.ZipTest.testStartsWith(ZipTest.java:43)
at test.ZipTest.main(ZipTest.java:26)
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (sun.nio.fs.WindowsFileSystemProvider)?
java.nio.file.ProviderMismatchException
at com.sun.nio.zipfs.ZipPath.checkPath(ZipPath.java:378)
at com.sun.nio.zipfs.ZipPath.endsWith(ZipPath.java:326)
at test.ZipTest.testEndsWith(ZipTest.java:58)
at test.ZipTest.main(ZipTest.java:28)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ProviderMismatchException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipTest {
public static void main(String[] args) throws Exception {
Path tempFile = Files.createTempFile("ZipTest", ".zip");
try {
try (ZipOutputStream out =
new ZipOutputStream(Files.newOutputStream(tempFile))) {
out.putNextEntry(new ZipEntry("test/hello.txt"));
out.write("Hello, World!".getBytes(StandardCharsets.UTF_8));
out.closeEntry();
}
try (FileSystem zipfs = FileSystems.newFileSystem(tempFile, null)) {
Path textFile = zipfs.getPath("test/hello.txt");
testStartsWith(textFile, zipfs.getPath("test"));
testStartsWith(textFile, Paths.get("test"));
testEndsWith(textFile, zipfs.getPath("hello.txt"));
testEndsWith(textFile, Paths.get("hello.txt"));
}
} finally {
Files.delete(tempFile);
}
}
static void testStartsWith(Path path, Path prefix) {
System.out.printf(
"\"%s\" (%s) starts with \"%s\" (%s)?%n",
path,
getProviderName(path),
prefix,
getProviderName(prefix));
try {
System.out.println(path.startsWith(prefix));
} catch (ProviderMismatchException e) {
e.printStackTrace(System.out);
}
System.out.println();
}
static void testEndsWith(Path path, Path suffix) {
System.out.printf(
"\"%s\" (%s) ends with \"%s\" (%s)?%n",
path,
getProviderName(path),
suffix,
getProviderName(suffix));
try {
System.out.println(path.endsWith(suffix));
} catch (ProviderMismatchException e) {
e.printStackTrace(System.out);
}
System.out.println();
}
static String getProviderName(Path path) {
return path.getFileSystem().provider().getClass().getName();
}
}
---------- END SOURCE ----------
java version "1.8.0_141"
Java(TM) SE Runtime Environment (build 1.8.0_141-b15)
Java HotSpot(TM) 64-Bit Server VM (build 25.141-b15, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 10.0.15063]
A DESCRIPTION OF THE PROBLEM :
The class com.sun.nio.zipfs.ZipPath throws a java.nio.file.ProviderMismatchException from its startsWith(Path) and endsWith(Path) methods when the argument is not an instance of ZipPath. This contradicts the javadoc for those methods as specified in the java.nio.file.Path interface, which states, "If the given path is associated with a different FileSystem to this path then false is returned."
The implementation of those methods in ZipPath should be changed to return false instead of throwing ProviderMismatchException in order to match the documented behavior.
For what it's worth, sun.nio.fs.WindowsPath conforms to that documented behavior (returning false) in both cases.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile and execute the attached source code, then compare the output to the expected result.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (sun.nio.fs.WindowsFileSystemProvider)?
false
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (sun.nio.fs.WindowsFileSystemProvider)?
false
ACTUAL -
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) starts with "test" (sun.nio.fs.WindowsFileSystemProvider)?
java.nio.file.ProviderMismatchException
at com.sun.nio.zipfs.ZipPath.checkPath(ZipPath.java:378)
at com.sun.nio.zipfs.ZipPath.startsWith(ZipPath.java:309)
at test.ZipTest.testStartsWith(ZipTest.java:43)
at test.ZipTest.main(ZipTest.java:26)
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider)?
true
"test/hello.txt" (com.sun.nio.zipfs.ZipFileSystemProvider) ends with "hello.txt" (sun.nio.fs.WindowsFileSystemProvider)?
java.nio.file.ProviderMismatchException
at com.sun.nio.zipfs.ZipPath.checkPath(ZipPath.java:378)
at com.sun.nio.zipfs.ZipPath.endsWith(ZipPath.java:326)
at test.ZipTest.testEndsWith(ZipTest.java:58)
at test.ZipTest.main(ZipTest.java:28)
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.ProviderMismatchException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
public class ZipTest {
public static void main(String[] args) throws Exception {
Path tempFile = Files.createTempFile("ZipTest", ".zip");
try {
try (ZipOutputStream out =
new ZipOutputStream(Files.newOutputStream(tempFile))) {
out.putNextEntry(new ZipEntry("test/hello.txt"));
out.write("Hello, World!".getBytes(StandardCharsets.UTF_8));
out.closeEntry();
}
try (FileSystem zipfs = FileSystems.newFileSystem(tempFile, null)) {
Path textFile = zipfs.getPath("test/hello.txt");
testStartsWith(textFile, zipfs.getPath("test"));
testStartsWith(textFile, Paths.get("test"));
testEndsWith(textFile, zipfs.getPath("hello.txt"));
testEndsWith(textFile, Paths.get("hello.txt"));
}
} finally {
Files.delete(tempFile);
}
}
static void testStartsWith(Path path, Path prefix) {
System.out.printf(
"\"%s\" (%s) starts with \"%s\" (%s)?%n",
path,
getProviderName(path),
prefix,
getProviderName(prefix));
try {
System.out.println(path.startsWith(prefix));
} catch (ProviderMismatchException e) {
e.printStackTrace(System.out);
}
System.out.println();
}
static void testEndsWith(Path path, Path suffix) {
System.out.printf(
"\"%s\" (%s) ends with \"%s\" (%s)?%n",
path,
getProviderName(path),
suffix,
getProviderName(suffix));
try {
System.out.println(path.endsWith(suffix));
} catch (ProviderMismatchException e) {
e.printStackTrace(System.out);
}
System.out.println();
}
static String getProviderName(Path path) {
return path.getFileSystem().provider().getClass().getName();
}
}
---------- END SOURCE ----------