diff --git a/src/java.base/share/classes/java/util/zip/Deflater.java b/src/java.base/share/classes/java/util/zip/Deflater.java index bec7d460c84..c75dd4a33f0 100644 --- a/src/java.base/share/classes/java/util/zip/Deflater.java +++ b/src/java.base/share/classes/java/util/zip/Deflater.java @@ -25,6 +25,9 @@ package java.util.zip; +import java.lang.ref.Cleaner.Cleanable; +import jdk.internal.ref.CleanerFactory; + /** * This class provides support for general purpose compression using the * popular ZLIB compression library. The ZLIB compression library was @@ -88,7 +91,7 @@ package java.util.zip; public class Deflater { - private final ZStreamRef zsRef; + private final DeflaterZStreamRef zsRef; private byte[] buf = new byte[0]; private int off, len; private int level, strategy; @@ -183,9 +186,8 @@ public class Deflater { public Deflater(int level, boolean nowrap) { this.level = level; this.strategy = DEFAULT_STRATEGY; - this.zsRef = ZStreamRef.get(this, - () -> init(level, DEFAULT_STRATEGY, nowrap), - Deflater::end); + this.zsRef = DeflaterZStreamRef.get(this, + init(level, DEFAULT_STRATEGY, nowrap)); } /** @@ -591,4 +593,75 @@ public class Deflater { private static native int getAdler(long addr); private static native void reset(long addr); private static native void end(long addr); + + /** + * A reference to the native zlib's z_stream structure. It also + * serves as the "cleaner" to clean up the native resource when + * the Deflater is ended, closed or cleaned. + */ + static class DeflaterZStreamRef implements Runnable { + + private long address; + private final Cleanable cleanable; + + private DeflaterZStreamRef(Deflater owner, long addr) { + this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null; + this.address = addr; + } + + long address() { + return address; + } + + void clean() { + cleanable.clean(); + } + + public synchronized void run() { + long addr = address; + address = 0; + if (addr != 0) { + end(addr); + } + } + + /* + * If {@code Deflater} has been subclassed and the {@code end} method is + * overridden, uses {@code finalizer} mechanism for resource cleanup. So + * {@code end} method can be called when the {@code Deflater} is unreachable. + * This mechanism will be removed when the {@code finalize} method is + * removed from {@code Deflater}. + */ + static DeflaterZStreamRef get(Deflater owner, long addr) { + Class clz = owner.getClass(); + while (clz != Deflater.class) { + try { + clz.getDeclaredMethod("end"); + return new FinalizableZStreamRef(owner, addr); + } catch (NoSuchMethodException nsme) {} + clz = clz.getSuperclass(); + } + return new DeflaterZStreamRef(owner, addr); + } + + private static class FinalizableZStreamRef extends DeflaterZStreamRef { + final Deflater owner; + + FinalizableZStreamRef (Deflater owner, long addr) { + super(null, addr); + this.owner = owner; + } + + @Override + void clean() { + run(); + } + + @Override + @SuppressWarnings("deprecation") + protected void finalize() { + owner.end(); + } + } + } } diff --git a/src/java.base/share/classes/java/util/zip/Inflater.java b/src/java.base/share/classes/java/util/zip/Inflater.java index 9e02f4dbc5c..9c6d8aa3d83 100644 --- a/src/java.base/share/classes/java/util/zip/Inflater.java +++ b/src/java.base/share/classes/java/util/zip/Inflater.java @@ -25,6 +25,9 @@ package java.util.zip; +import java.lang.ref.Cleaner.Cleanable; +import jdk.internal.ref.CleanerFactory; + /** * This class provides support for general purpose decompression using the * popular ZLIB compression library. The ZLIB compression library was @@ -88,7 +91,7 @@ package java.util.zip; public class Inflater { - private final ZStreamRef zsRef; + private final InflaterZStreamRef zsRef; private byte[] buf = defaultBuf; private int off, len; private boolean finished; @@ -115,7 +118,7 @@ public class Inflater { * @param nowrap if true then support GZIP compatible compression */ public Inflater(boolean nowrap) { - this.zsRef = ZStreamRef.get(this, () -> init(nowrap), Inflater::end); + this.zsRef = InflaterZStreamRef.get(this, init(nowrap)); } /** @@ -428,4 +431,75 @@ public class Inflater { private static native int getAdler(long addr); private static native void reset(long addr); private static native void end(long addr); + + /** + * A reference to the native zlib's z_stream structure. It also + * serves as the "cleaner" to clean up the native resource when + * the Inflater is ended, closed or cleaned. + */ + static class InflaterZStreamRef implements Runnable { + + private long address; + private final Cleanable cleanable; + + private InflaterZStreamRef(Inflater owner, long addr) { + this.cleanable = (owner != null) ? CleanerFactory.cleaner().register(owner, this) : null; + this.address = addr; + } + + long address() { + return address; + } + + void clean() { + cleanable.clean(); + } + + public synchronized void run() { + long addr = address; + address = 0; + if (addr != 0) { + end(addr); + } + } + + /* + * If {@code Inflater} has been subclassed and the {@code end} method is + * overridden, uses {@code finalizer} mechanism for resource cleanup. So + * {@code end} method can be called when the {@code Inflater} is unreachable. + * This mechanism will be removed when the {@code finalize} method is + * removed from {@code Inflater}. + */ + static InflaterZStreamRef get(Inflater owner, long addr) { + Class clz = owner.getClass(); + while (clz != Inflater.class) { + try { + clz.getDeclaredMethod("end"); + return new FinalizableZStreamRef(owner, addr); + } catch (NoSuchMethodException nsme) {} + clz = clz.getSuperclass(); + } + return new InflaterZStreamRef(owner, addr); + } + + private static class FinalizableZStreamRef extends InflaterZStreamRef { + final Inflater owner; + + FinalizableZStreamRef(Inflater owner, long addr) { + super(null, addr); + this.owner = owner; + } + + @Override + void clean() { + run(); + } + + @Override + @SuppressWarnings("deprecation") + protected void finalize() { + owner.end(); + } + } + } } diff --git a/src/java.base/share/classes/java/util/zip/ZStreamRef.java b/src/java.base/share/classes/java/util/zip/ZStreamRef.java deleted file mode 100644 index 2a32d7cd8a8..00000000000 --- a/src/java.base/share/classes/java/util/zip/ZStreamRef.java +++ /dev/null @@ -1,113 +0,0 @@ -/* - * Copyright (c) 2009, 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 - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - */ - -package java.util.zip; - -import java.util.function.LongConsumer; -import java.util.function.LongSupplier; -import java.lang.ref.Cleaner.Cleanable; -import jdk.internal.ref.CleanerFactory; - -/** - * A reference to the native zlib's z_stream structure. It also - * serves as the "cleaner" to clean up the native resource when - * the deflater or infalter is ended, closed or cleaned. - */ -class ZStreamRef implements Runnable { - - private LongConsumer end; - private long address; - private final Cleanable cleanable; - - private ZStreamRef (Object owner, LongSupplier addr, LongConsumer end) { - this.cleanable = CleanerFactory.cleaner().register(owner, this); - this.end = end; - this.address = addr.getAsLong(); - } - - long address() { - return address; - } - - void clean() { - cleanable.clean(); - } - - public synchronized void run() { - long addr = address; - address = 0; - if (addr != 0) { - end.accept(addr); - } - } - - private ZStreamRef (LongSupplier addr, LongConsumer end) { - this.cleanable = null; - this.end = end; - this.address = addr.getAsLong(); - } - - /* - * If {@code Inflater/Deflater} has been subclassed and the {@code end} method - * is overridden, uses {@code finalizer} mechanism for resource cleanup. So - * {@code end} method can be called when the {@code Inflater/Deflater} is - * unreachable. This mechanism will be removed when the {@code finalize} method - * is removed from {@code Inflater/Deflater}. - */ - static ZStreamRef get(Object owner, LongSupplier addr, LongConsumer end) { - Class clz = owner.getClass(); - while (clz != Deflater.class && clz != Inflater.class) { - try { - clz.getDeclaredMethod("end"); - return new FinalizableZStreamRef(owner, addr, end); - } catch (NoSuchMethodException nsme) {} - clz = clz.getSuperclass(); - } - return new ZStreamRef(owner, addr, end); - } - - private static class FinalizableZStreamRef extends ZStreamRef { - final Object owner; - - FinalizableZStreamRef (Object owner, LongSupplier addr, LongConsumer end) { - super(addr, end); - this.owner = owner; - } - - @Override - void clean() { - run(); - } - - @Override - @SuppressWarnings("deprecation") - protected void finalize() { - if (owner instanceof Inflater) - ((Inflater)owner).end(); - else - ((Deflater)owner).end(); - } - } -} diff --git a/src/java.base/share/classes/java/util/zip/ZipFile.java b/src/java.base/share/classes/java/util/zip/ZipFile.java index b34f11cc781..bb0b8da6a1c 100644 --- a/src/java.base/share/classes/java/util/zip/ZipFile.java +++ b/src/java.base/share/classes/java/util/zip/ZipFile.java @@ -412,6 +412,21 @@ class ZipFile implements ZipConstants, Closeable { } } + private static class InflaterCleanupAction implements Runnable { + private final Inflater inf; + private final CleanableResource res; + + InflaterCleanupAction(Inflater inf, CleanableResource res) { + this.inf = inf; + this.res = res; + } + + @Override + public void run() { + res.releaseInflater(inf); + } + } + private class ZipFileInflaterInputStream extends InflaterInputStream { private volatile boolean closeRequested; private boolean eof = false; @@ -427,8 +442,8 @@ class ZipFile implements ZipConstants, Closeable { Inflater inf, int size) { super(zfin, inf, size); this.cleanable = CleanerFactory.cleaner().register(this, - () -> res.releaseInflater(inf)); - } + new InflaterCleanupAction(inf, res)); + } public void close() throws IOException { if (closeRequested)