Skip to content

Commit 36b7abd

Browse files
committed
8225763: Inflater and Deflater should implement AutoCloseable
Reviewed-by: lancea, rriggs, alanb, smarks
1 parent d6d45c6 commit 36b7abd

File tree

7 files changed

+646
-86
lines changed

7 files changed

+646
-86
lines changed

src/java.base/share/classes/java/util/zip/Deflater.java

+58-20
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1996, 2024, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1996, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -49,29 +49,30 @@
4949
* thrown.
5050
* <p>
5151
* This class deflates sequences of bytes into ZLIB compressed data format.
52-
* The input byte sequence is provided in either byte array or byte buffer,
52+
* The input byte sequence is provided in either a byte array or a {@link ByteBuffer},
5353
* via one of the {@code setInput()} methods. The output byte sequence is
54-
* written to the output byte array or byte buffer passed to the
54+
* written to the output byte array or {@code ByteBuffer} passed to the
5555
* {@code deflate()} methods.
5656
* <p>
57-
* The following code fragment demonstrates a trivial compression
58-
* and decompression of a string using {@code Deflater} and
59-
* {@code Inflater}.
60-
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
57+
* To release the resources used by a {@code Deflater}, an application must close it
58+
* by invoking its {@link #end()} or {@link #close()} method.
6159
*
6260
* @apiNote
63-
* To release resources used by this {@code Deflater}, the {@link #end()} method
64-
* should be called explicitly. Subclasses are responsible for the cleanup of resources
65-
* acquired by the subclass. Subclasses that override {@link #finalize()} in order
66-
* to perform cleanup should be modified to use alternative cleanup mechanisms such
67-
* as {@link java.lang.ref.Cleaner} and remove the overriding {@code finalize} method.
61+
* This class implements {@link AutoCloseable} to facilitate its usage with
62+
* {@code try}-with-resources statement. The {@linkplain Deflater#close() close() method} simply
63+
* calls {@code end()}.
64+
*
65+
* <p>
66+
* The following code fragment demonstrates a trivial compression
67+
* and decompression of a string using {@code Deflater} and {@code Inflater}.
68+
* {@snippet id="compdecomp" lang="java" class="Snippets" region="DeflaterInflaterExample"}
6869
*
6970
* @see Inflater
7071
* @author David Connelly
7172
* @since 1.1
7273
*/
7374

74-
public class Deflater {
75+
public class Deflater implements AutoCloseable {
7576

7677
private final DeflaterZStreamRef zsRef;
7778
private ByteBuffer input = ZipUtils.defaultBuf;
@@ -269,6 +270,7 @@ public void setInput(ByteBuffer input) {
269270
* @param dictionary the dictionary data bytes
270271
* @param off the start offset of the data
271272
* @param len the length of the data
273+
* @throws IllegalStateException if the Deflater is closed
272274
* @see Inflater#inflate
273275
* @see Inflater#getAdler()
274276
*/
@@ -287,6 +289,7 @@ public void setDictionary(byte[] dictionary, int off, int len) {
287289
* in order to get the Adler-32 value of the dictionary required for
288290
* decompression.
289291
* @param dictionary the dictionary data bytes
292+
* @throws IllegalStateException if the Deflater is closed
290293
* @see Inflater#inflate
291294
* @see Inflater#getAdler()
292295
*/
@@ -305,6 +308,7 @@ public void setDictionary(byte[] dictionary) {
305308
* return, its position will equal its limit.
306309
*
307310
* @param dictionary the dictionary data bytes
311+
* @throws IllegalStateException if the Deflater is closed
308312
* @see Inflater#inflate
309313
* @see Inflater#getAdler()
310314
*
@@ -437,6 +441,7 @@ public boolean finished() {
437441
* @param len the maximum number of bytes of compressed data
438442
* @return the actual number of bytes of compressed data written to the
439443
* output buffer
444+
* @throws IllegalStateException if the Deflater is closed
440445
*/
441446
public int deflate(byte[] output, int off, int len) {
442447
return deflate(output, off, len, NO_FLUSH);
@@ -456,6 +461,7 @@ public int deflate(byte[] output, int off, int len) {
456461
* @param output the buffer for the compressed data
457462
* @return the actual number of bytes of compressed data written to the
458463
* output buffer
464+
* @throws IllegalStateException if the Deflater is closed
459465
*/
460466
public int deflate(byte[] output) {
461467
return deflate(output, 0, output.length, NO_FLUSH);
@@ -476,6 +482,7 @@ public int deflate(byte[] output) {
476482
* @return the actual number of bytes of compressed data written to the
477483
* output buffer
478484
* @throws ReadOnlyBufferException if the given output buffer is read-only
485+
* @throws IllegalStateException if the Deflater is closed
479486
* @since 11
480487
*/
481488
public int deflate(ByteBuffer output) {
@@ -531,6 +538,7 @@ public int deflate(ByteBuffer output) {
531538
* the output buffer
532539
*
533540
* @throws IllegalArgumentException if the flush mode is invalid
541+
* @throws IllegalStateException if the Deflater is closed
534542
* @since 1.7
535543
*/
536544
public int deflate(byte[] output, int off, int len, int flush) {
@@ -657,6 +665,7 @@ public int deflate(byte[] output, int off, int len, int flush) {
657665
*
658666
* @throws IllegalArgumentException if the flush mode is invalid
659667
* @throws ReadOnlyBufferException if the given output buffer is read-only
668+
* @throws IllegalStateException if the Deflater is closed
660669
* @since 11
661670
*/
662671
public int deflate(ByteBuffer output, int flush) {
@@ -783,6 +792,7 @@ public int deflate(ByteBuffer output, int flush) {
783792

784793
/**
785794
* {@return the ADLER-32 value of the uncompressed data}
795+
* @throws IllegalStateException if the Deflater is closed
786796
*/
787797
public int getAdler() {
788798
synchronized (zsRef) {
@@ -802,6 +812,7 @@ public int getAdler() {
802812
* @deprecated Use {@link #getBytesRead()} instead
803813
*
804814
* @return the total number of uncompressed bytes input so far
815+
* @throws IllegalStateException if the Deflater is closed
805816
*/
806817
@Deprecated(since = "23")
807818
public int getTotalIn() {
@@ -812,6 +823,7 @@ public int getTotalIn() {
812823
* Returns the total number of uncompressed bytes input so far.
813824
*
814825
* @return the total (non-negative) number of uncompressed bytes input so far
826+
* @throws IllegalStateException if the Deflater is closed
815827
* @since 1.5
816828
*/
817829
public long getBytesRead() {
@@ -832,6 +844,7 @@ public long getBytesRead() {
832844
* @deprecated Use {@link #getBytesWritten()} instead
833845
*
834846
* @return the total number of compressed bytes output so far
847+
* @throws IllegalStateException if the Deflater is closed
835848
*/
836849
@Deprecated(since = "23")
837850
public int getTotalOut() {
@@ -842,6 +855,7 @@ public int getTotalOut() {
842855
* Returns the total number of compressed bytes output so far.
843856
*
844857
* @return the total (non-negative) number of compressed bytes output so far
858+
* @throws IllegalStateException if the Deflater is closed
845859
* @since 1.5
846860
*/
847861
public long getBytesWritten() {
@@ -854,6 +868,7 @@ public long getBytesWritten() {
854868
/**
855869
* Resets deflater so that a new set of input data can be processed.
856870
* Keeps current compression level and strategy settings.
871+
* @throws IllegalStateException if the Deflater is closed
857872
*/
858873
public void reset() {
859874
synchronized (zsRef) {
@@ -868,23 +883,45 @@ public void reset() {
868883
}
869884

870885
/**
871-
* Closes the compressor and discards any unprocessed input.
886+
* Closes and releases the resources held by this {@code Deflater}
887+
* and discards any unprocessed input.
888+
* <p>
889+
* If the {@code Deflater} is already closed then invoking this method has no effect.
890+
*
891+
* @implSpec Subclasses should override this method to clean up the resources
892+
* acquired by the subclass.
872893
*
873-
* This method should be called when the compressor is no longer
874-
* being used. Once this method is called, the behavior of the
875-
* Deflater object is undefined.
894+
* @see #close()
876895
*/
877896
public void end() {
878897
synchronized (zsRef) {
898+
// check if already closed
899+
if (zsRef.address() == 0) {
900+
return;
901+
}
879902
zsRef.clean();
880903
input = ZipUtils.defaultBuf;
904+
inputArray = null;
881905
}
882906
}
883907

908+
/**
909+
* Closes and releases the resources held by this {@code Deflater}
910+
* and discards any unprocessed input.
911+
*
912+
* @implSpec This method calls the {@link #end()} method.
913+
* @since 25
914+
*/
915+
@Override
916+
public void close() {
917+
end();
918+
}
919+
884920
private void ensureOpen() {
885921
assert Thread.holdsLock(zsRef);
886-
if (zsRef.address() == 0)
887-
throw new NullPointerException("Deflater has been closed");
922+
if (zsRef.address() == 0) {
923+
throw new IllegalStateException("Deflater has been closed");
924+
}
888925
}
889926

890927
/**
@@ -928,10 +965,11 @@ private native long deflateBufferBuffer(long addr,
928965
*/
929966
static class DeflaterZStreamRef implements Runnable {
930967

931-
private long address;
968+
private long address; // will be a non-zero value when the native resource is in use
932969
private final Cleanable cleanable;
933970

934971
private DeflaterZStreamRef(Deflater owner, long addr) {
972+
assert addr != 0 : "native address is 0";
935973
this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null;
936974
this.address = addr;
937975
}

0 commit comments

Comments
 (0)