This bug is present in the latest 1.7 and 1.8 versions of the JDK (7u72, 8u25). Required: jackson-databind 2.5.0. Tested on Linux x86_64 (Ubuntu 14.10 to be precise).
Code:
public static void main(final String... args)
throws IOException
{
final Map<String, String> map
= Collections.singletonMap("create", "true");
final Path zipfile = Paths.get("/tmp/foo.zip");
Files.deleteIfExists(zipfile);
final URI uri = URI.create("jar:" + zipfile.toUri());
final ObjectMapper mapper = new ObjectMapper();
try (
final FileSystem zipfs = FileSystems.newFileSystem(uri, map);
final OutputStream out
= Files.newOutputStream(zipfs.getPath("/t.json"));
) {
mapper.writeValue(out, "hello");
}
}
This produces an invalid zip file:
$ unzip /tmp/foo.zip
Archive: /tmp/foo.zip
replace t.json? [y]es, [n]o, [A]ll, [N]one, [r]ename: A
inflating: t.json
error: invalid compressed data to inflate
I have originally opened the bug on Jackson's issue tracker even though it really isn't the culprit here, and a solution was found to work around it: disable JsonGenerator.Feature.AUTO_CLOSE_SOURCE
in the ObjectMapper
. This option which is enabled by default tells the mapper to close the stream.
While I'd like to open the bug to Oracle, I'd first like to be able to write an SSCCE, but I can't. I have tried to close the stream twice (since it is closed twice in the example), not to use a try-with-resources statement etc... To no avail.
Can you come up with an SSCCE for this problem?
Methods. getComment(): String – returns the zip file comment, or null if none. getEntry(String name): ZipEntry – returns the zip file entry for the specified name, or null if not found. getInputStream(ZipEntry entry) : InputStream – Returns an input stream for reading the contents of the specified zip file entry.
The zip file system provider treats a zip or JAR file as a file system and provides the ability to manipulate the contents of the file. The zip file system provider creates multiple file systems — one file system for each zip or JAR file.
A file system is the factory for several types of objects: The getPath method converts a system dependent path string, returning a Path object that may be used to locate and access a file. The getPathMatcher method is used to create a PathMatcher that performs match operations on paths.
I had thought Jackson was doing something untoward, but it turns out one can reproduce the problem without any Jackson code. I replaced the body of the try
block with two lines that (I'm pretty sure) do the same thing, and the result is still an invalid zip file:
try (
final FileSystem zipfs = FileSystems.newFileSystem(uri, map);
final OutputStream out
= Files.newOutputStream(zipfs.getPath("/t.json"));
) {
out.write("\"hello\"".getBytes(StandardCharsets.US_ASCII));
out.close();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With