mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-26 14:24:46 +02:00
8225763: Inflater and Deflater should implement AutoCloseable
Reviewed-by: lancea, rriggs, alanb, smarks
This commit is contained in:
parent
d6d45c6eae
commit
36b7abd617
7 changed files with 647 additions and 87 deletions
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -49,29 +49,30 @@ import static java.util.zip.ZipUtils.NIO_ACCESS;
|
|||
* thrown.
|
||||
* <p>
|
||||
* This class deflates sequences of bytes into ZLIB compressed data format.
|
||||
* The input byte sequence is provided in either byte array or byte buffer,
|
||||
* The input byte sequence is provided in either a byte array or a {@link ByteBuffer},
|
||||
* via one of the {@code setInput()} methods. The output byte sequence is
|
||||
* written to the output byte array or byte buffer passed to the
|
||||
* written to the output byte array or {@code ByteBuffer} passed to the
|
||||
* {@code deflate()} methods.
|
||||
* <p>
|
||||
* The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and
|
||||
* {@code Inflater}.
|
||||
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
|
||||
* To release the resources used by a {@code Deflater}, an application must close it
|
||||
* by invoking its {@link #end()} or {@link #close()} method.
|
||||
*
|
||||
* @apiNote
|
||||
* To release resources used by this {@code Deflater}, the {@link #end()} method
|
||||
* should be called explicitly. Subclasses are responsible for the cleanup of resources
|
||||
* acquired by the subclass. Subclasses that override {@link #finalize()} in order
|
||||
* to perform cleanup should be modified to use alternative cleanup mechanisms such
|
||||
* as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
|
||||
* This class implements {@link AutoCloseable} to facilitate its usage with
|
||||
* {@code try}-with-resources statement. The {@linkplain Deflater#close() close() method} simply
|
||||
* calls {@code end()}.
|
||||
*
|
||||
* <p>
|
||||
* The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and {@code Inflater}.
|
||||
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
|
||||
*
|
||||
* @see Inflater
|
||||
* @author David Connelly
|
||||
* @since 1.1
|
||||
*/
|
||||
|
||||
public class Deflater {
|
||||
public class Deflater implements AutoCloseable {
|
||||
|
||||
private final DeflaterZStreamRef zsRef;
|
||||
private ByteBuffer input = ZipUtils.defaultBuf;
|
||||
|
@ -269,6 +270,7 @@ public class Deflater {
|
|||
* @param dictionary the dictionary data bytes
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @see Inflater#inflate
|
||||
* @see Inflater#getAdler()
|
||||
*/
|
||||
|
@ -287,6 +289,7 @@ public class Deflater {
|
|||
* in order to get the Adler-32 value of the dictionary required for
|
||||
* decompression.
|
||||
* @param dictionary the dictionary data bytes
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @see Inflater#inflate
|
||||
* @see Inflater#getAdler()
|
||||
*/
|
||||
|
@ -305,6 +308,7 @@ public class Deflater {
|
|||
* return, its position will equal its limit.
|
||||
*
|
||||
* @param dictionary the dictionary data bytes
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @see Inflater#inflate
|
||||
* @see Inflater#getAdler()
|
||||
*
|
||||
|
@ -437,6 +441,7 @@ public class Deflater {
|
|||
* @param len the maximum number of bytes of compressed data
|
||||
* @return the actual number of bytes of compressed data written to the
|
||||
* output buffer
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
public int deflate(byte[] output, int off, int len) {
|
||||
return deflate(output, off, len, NO_FLUSH);
|
||||
|
@ -456,6 +461,7 @@ public class Deflater {
|
|||
* @param output the buffer for the compressed data
|
||||
* @return the actual number of bytes of compressed data written to the
|
||||
* output buffer
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
public int deflate(byte[] output) {
|
||||
return deflate(output, 0, output.length, NO_FLUSH);
|
||||
|
@ -476,6 +482,7 @@ public class Deflater {
|
|||
* @return the actual number of bytes of compressed data written to the
|
||||
* output buffer
|
||||
* @throws ReadOnlyBufferException if the given output buffer is read-only
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @since 11
|
||||
*/
|
||||
public int deflate(ByteBuffer output) {
|
||||
|
@ -531,6 +538,7 @@ public class Deflater {
|
|||
* the output buffer
|
||||
*
|
||||
* @throws IllegalArgumentException if the flush mode is invalid
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @since 1.7
|
||||
*/
|
||||
public int deflate(byte[] output, int off, int len, int flush) {
|
||||
|
@ -657,6 +665,7 @@ public class Deflater {
|
|||
*
|
||||
* @throws IllegalArgumentException if the flush mode is invalid
|
||||
* @throws ReadOnlyBufferException if the given output buffer is read-only
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @since 11
|
||||
*/
|
||||
public int deflate(ByteBuffer output, int flush) {
|
||||
|
@ -783,6 +792,7 @@ public class Deflater {
|
|||
|
||||
/**
|
||||
* {@return the ADLER-32 value of the uncompressed data}
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
public int getAdler() {
|
||||
synchronized (zsRef) {
|
||||
|
@ -802,6 +812,7 @@ public class Deflater {
|
|||
* @deprecated Use {@link #getBytesRead()} instead
|
||||
*
|
||||
* @return the total number of uncompressed bytes input so far
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
@Deprecated(since = "23")
|
||||
public int getTotalIn() {
|
||||
|
@ -812,6 +823,7 @@ public class Deflater {
|
|||
* Returns the total number of uncompressed bytes input so far.
|
||||
*
|
||||
* @return the total (non-negative) number of uncompressed bytes input so far
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
|
@ -832,6 +844,7 @@ public class Deflater {
|
|||
* @deprecated Use {@link #getBytesWritten()} instead
|
||||
*
|
||||
* @return the total number of compressed bytes output so far
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
@Deprecated(since = "23")
|
||||
public int getTotalOut() {
|
||||
|
@ -842,6 +855,7 @@ public class Deflater {
|
|||
* Returns the total number of compressed bytes output so far.
|
||||
*
|
||||
* @return the total (non-negative) number of compressed bytes output so far
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesWritten() {
|
||||
|
@ -854,6 +868,7 @@ public class Deflater {
|
|||
/**
|
||||
* Resets deflater so that a new set of input data can be processed.
|
||||
* Keeps current compression level and strategy settings.
|
||||
* @throws IllegalStateException if the Deflater is closed
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (zsRef) {
|
||||
|
@ -868,23 +883,45 @@ public class Deflater {
|
|||
}
|
||||
|
||||
/**
|
||||
* Closes the compressor and discards any unprocessed input.
|
||||
* Closes and releases the resources held by this {@code Deflater}
|
||||
* and discards any unprocessed input.
|
||||
* <p>
|
||||
* If the {@code Deflater} is already closed then invoking this method has no effect.
|
||||
*
|
||||
* This method should be called when the compressor is no longer
|
||||
* being used. Once this method is called, the behavior of the
|
||||
* Deflater object is undefined.
|
||||
* @implSpec Subclasses should override this method to clean up the resources
|
||||
* acquired by the subclass.
|
||||
*
|
||||
* @see #close()
|
||||
*/
|
||||
public void end() {
|
||||
synchronized (zsRef) {
|
||||
// check if already closed
|
||||
if (zsRef.address() == 0) {
|
||||
return;
|
||||
}
|
||||
zsRef.clean();
|
||||
input = ZipUtils.defaultBuf;
|
||||
inputArray = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes and releases the resources held by this {@code Deflater}
|
||||
* and discards any unprocessed input.
|
||||
*
|
||||
* @implSpec This method calls the {@link #end()} method.
|
||||
* @since 25
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void ensureOpen() {
|
||||
assert Thread.holdsLock(zsRef);
|
||||
if (zsRef.address() == 0)
|
||||
throw new NullPointerException("Deflater has been closed");
|
||||
if (zsRef.address() == 0) {
|
||||
throw new IllegalStateException("Deflater has been closed");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -928,10 +965,11 @@ public class Deflater {
|
|||
*/
|
||||
static class DeflaterZStreamRef implements Runnable {
|
||||
|
||||
private long address;
|
||||
private long address; // will be a non-zero value when the native resource is in use
|
||||
private final Cleanable cleanable;
|
||||
|
||||
private DeflaterZStreamRef(Deflater owner, long addr) {
|
||||
assert addr != 0 : "native address is 0";
|
||||
this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
|
||||
this.address = addr;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
|
@ -49,21 +49,22 @@ import static java.util.zip.ZipUtils.NIO_ACCESS;
|
|||
* thrown.
|
||||
* <p>
|
||||
* This class inflates sequences of ZLIB compressed bytes. The input byte
|
||||
* sequence is provided in either byte array or byte buffer, via one of the
|
||||
* sequence is provided in either a byte array or a {@link ByteBuffer}, via one of the
|
||||
* {@code setInput()} methods. The output byte sequence is written to the
|
||||
* output byte array or byte buffer passed to the {@code inflate()} methods.
|
||||
* output byte array or {@code ByteBuffer} passed to the {@code inflate()} methods.
|
||||
* <p>
|
||||
* The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and
|
||||
* {@code Inflater}.
|
||||
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
|
||||
* To release the resources used by an {@code Inflater}, an application must close it
|
||||
* by invoking its {@link #end()} or {@link #close()} method.
|
||||
*
|
||||
* @apiNote
|
||||
* To release resources used by this {@code Inflater}, the {@link #end()} method
|
||||
* should be called explicitly. Subclasses are responsible for the cleanup of resources
|
||||
* acquired by the subclass. Subclasses that override {@link #finalize()} in order
|
||||
* to perform cleanup should be modified to use alternative cleanup mechanisms such
|
||||
* as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
|
||||
* This class implements {@link AutoCloseable} to facilitate its usage with
|
||||
* {@code try}-with-resources statement. The {@linkplain Inflater#close() close() method} simply
|
||||
* calls {@code end()}.
|
||||
*
|
||||
* <p>
|
||||
* The following code fragment demonstrates a trivial compression
|
||||
* and decompression of a string using {@code Deflater} and {@code Inflater}.
|
||||
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
|
||||
*
|
||||
* @see Deflater
|
||||
* @author David Connelly
|
||||
|
@ -71,7 +72,7 @@ import static java.util.zip.ZipUtils.NIO_ACCESS;
|
|||
*
|
||||
*/
|
||||
|
||||
public class Inflater {
|
||||
public class Inflater implements AutoCloseable {
|
||||
|
||||
private final InflaterZStreamRef zsRef;
|
||||
private ByteBuffer input = ZipUtils.defaultBuf;
|
||||
|
@ -192,6 +193,7 @@ public class Inflater {
|
|||
* @param dictionary the dictionary data bytes
|
||||
* @param off the start offset of the data
|
||||
* @param len the length of the data
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsDictionary
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
|
@ -210,6 +212,7 @@ public class Inflater {
|
|||
* indicating that a preset dictionary is required. The method getAdler()
|
||||
* can be used to get the Adler-32 value of the dictionary needed.
|
||||
* @param dictionary the dictionary data bytes
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsDictionary
|
||||
* @see Inflater#getAdler
|
||||
*/
|
||||
|
@ -227,6 +230,7 @@ public class Inflater {
|
|||
* return, its position will equal its limit.
|
||||
*
|
||||
* @param dictionary the dictionary data bytes
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsDictionary
|
||||
* @see Inflater#getAdler
|
||||
* @since 11
|
||||
|
@ -331,6 +335,7 @@ public class Inflater {
|
|||
* @param len the maximum number of uncompressed bytes
|
||||
* @return the actual number of uncompressed bytes
|
||||
* @throws DataFormatException if the compressed data format is invalid
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsInput
|
||||
* @see Inflater#needsDictionary
|
||||
*/
|
||||
|
@ -437,6 +442,7 @@ public class Inflater {
|
|||
* @param output the buffer for the uncompressed data
|
||||
* @return the actual number of uncompressed bytes
|
||||
* @throws DataFormatException if the compressed data format is invalid
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsInput
|
||||
* @see Inflater#needsDictionary
|
||||
*/
|
||||
|
@ -474,6 +480,7 @@ public class Inflater {
|
|||
* @return the actual number of uncompressed bytes
|
||||
* @throws DataFormatException if the compressed data format is invalid
|
||||
* @throws ReadOnlyBufferException if the given output buffer is read-only
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @see Inflater#needsInput
|
||||
* @see Inflater#needsDictionary
|
||||
* @since 11
|
||||
|
@ -600,6 +607,7 @@ public class Inflater {
|
|||
|
||||
/**
|
||||
* {@return the ADLER-32 value of the uncompressed data}
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
*/
|
||||
public int getAdler() {
|
||||
synchronized (zsRef) {
|
||||
|
@ -619,6 +627,7 @@ public class Inflater {
|
|||
* @deprecated Use {@link #getBytesRead()} instead
|
||||
*
|
||||
* @return the total number of compressed bytes input so far
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
*/
|
||||
@Deprecated(since = "23")
|
||||
public int getTotalIn() {
|
||||
|
@ -629,6 +638,7 @@ public class Inflater {
|
|||
* Returns the total number of compressed bytes input so far.
|
||||
*
|
||||
* @return the total (non-negative) number of compressed bytes input so far
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesRead() {
|
||||
|
@ -649,6 +659,7 @@ public class Inflater {
|
|||
* @deprecated Use {@link #getBytesWritten()} instead
|
||||
*
|
||||
* @return the total number of uncompressed bytes output so far
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
*/
|
||||
@Deprecated(since = "23")
|
||||
public int getTotalOut() {
|
||||
|
@ -659,6 +670,7 @@ public class Inflater {
|
|||
* Returns the total number of uncompressed bytes output so far.
|
||||
*
|
||||
* @return the total (non-negative) number of uncompressed bytes output so far
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
* @since 1.5
|
||||
*/
|
||||
public long getBytesWritten() {
|
||||
|
@ -670,6 +682,7 @@ public class Inflater {
|
|||
|
||||
/**
|
||||
* Resets inflater so that a new set of input data can be processed.
|
||||
* @throws IllegalStateException if the Inflater is closed
|
||||
*/
|
||||
public void reset() {
|
||||
synchronized (zsRef) {
|
||||
|
@ -684,14 +697,22 @@ public class Inflater {
|
|||
}
|
||||
|
||||
/**
|
||||
* Closes the decompressor and discards any unprocessed input.
|
||||
* Closes and releases the resources held by this {@code Inflater}
|
||||
* and discards any unprocessed input.
|
||||
* <p>
|
||||
* If the {@code Inflater} is already closed then invoking this method has no effect.
|
||||
*
|
||||
* This method should be called when the decompressor is no longer
|
||||
* being used. Once this method is called, the behavior of the
|
||||
* Inflater object is undefined.
|
||||
* @implSpec Subclasses should override this method to clean up the resources
|
||||
* acquired by the subclass.
|
||||
*
|
||||
* @see #close()
|
||||
*/
|
||||
public void end() {
|
||||
synchronized (zsRef) {
|
||||
// check if already closed
|
||||
if (zsRef.address() == 0) {
|
||||
return;
|
||||
}
|
||||
zsRef.clean();
|
||||
input = ZipUtils.defaultBuf;
|
||||
inputArray = null;
|
||||
|
@ -699,10 +720,23 @@ public class Inflater {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes and releases the resources held by this {@code Inflater}
|
||||
* and discards any unprocessed input.
|
||||
*
|
||||
* @implSpec This method calls the {@link #end()} method.
|
||||
* @since 25
|
||||
*/
|
||||
@Override
|
||||
public void close() {
|
||||
end();
|
||||
}
|
||||
|
||||
private void ensureOpen () {
|
||||
assert Thread.holdsLock(zsRef);
|
||||
if (zsRef.address() == 0)
|
||||
throw new NullPointerException("Inflater has been closed");
|
||||
if (zsRef.address() == 0) {
|
||||
throw new IllegalStateException("Inflater has been closed");
|
||||
}
|
||||
}
|
||||
|
||||
boolean hasPendingOutput() {
|
||||
|
@ -737,10 +771,11 @@ public class Inflater {
|
|||
*/
|
||||
static class InflaterZStreamRef implements Runnable {
|
||||
|
||||
private long address;
|
||||
private long address; // will be a non-zero value when the native resource is in use
|
||||
private final Cleanable cleanable;
|
||||
|
||||
private InflaterZStreamRef(Inflater owner, long addr) {
|
||||
assert addr != 0 : "native address is 0";
|
||||
this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
|
||||
this.address = addr;
|
||||
}
|
||||
|
|
|
@ -38,8 +38,7 @@ class Snippets {
|
|||
|
||||
// Compress the bytes
|
||||
ByteArrayOutputStream compressedBaos = new ByteArrayOutputStream();
|
||||
Deflater compressor = new Deflater();
|
||||
try {
|
||||
try (Deflater compressor = new Deflater()) {
|
||||
compressor.setInput(input);
|
||||
// Let the compressor know that the complete input
|
||||
// has been made available
|
||||
|
@ -55,15 +54,11 @@ class Snippets {
|
|||
// buffer into the final byte array
|
||||
compressedBaos.write(tmpBuffer, 0, numCompressed);
|
||||
}
|
||||
} finally {
|
||||
// Release the resources held by the compressor
|
||||
compressor.end();
|
||||
}
|
||||
|
||||
// Decompress the bytes
|
||||
Inflater decompressor = new Inflater();
|
||||
ByteArrayOutputStream decompressedBaos = new ByteArrayOutputStream();
|
||||
try {
|
||||
try (Inflater decompressor = new Inflater()) {
|
||||
byte[] compressed = compressedBaos.toByteArray();
|
||||
decompressor.setInput(compressed, 0, compressed.length);
|
||||
while (!decompressor.finished()) {
|
||||
|
@ -83,9 +78,6 @@ class Snippets {
|
|||
// buffer into the final byte array
|
||||
decompressedBaos.write(tmpBuffer, 0, numDecompressed);
|
||||
}
|
||||
} finally {
|
||||
// Release the resources held by the decompressor
|
||||
decompressor.end();
|
||||
}
|
||||
// Decode the bytes into a String
|
||||
String outputString = decompressedBaos.toString(StandardCharsets.UTF_8);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue