diff --git a/api/src/main/java/jakarta/mail/util/SharedFileInputStream.java b/api/src/main/java/jakarta/mail/util/SharedFileInputStream.java index b0f7c6c8..8d62026b 100644 --- a/api/src/main/java/jakarta/mail/util/SharedFileInputStream.java +++ b/api/src/main/java/jakarta/mail/util/SharedFileInputStream.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; +import java.util.Objects; /** * A SharedFileInputStream is a @@ -426,10 +427,24 @@ public boolean markSupported() { public void close() throws IOException { if (in == null) return; - sf.close(); - sf = null; - in = null; - buf = null; + try { + sf.close(); + } finally { + sf = null; + in = null; + buf = null; + /* + * This avoids that 'new SharedFileInputStream(file)' + * is GCed meanwhile #newStream is invoked, for example: + * new SharedFileInputStream(file).newStream(0, -1) + * + * That could be an issue if a subclass of this one invokes #close + * from #finalize (not a good practice anyway). + */ + Objects.requireNonNull(this); + // TODO Replace it by the next +// Reference.reachabilityFence(this); + } } /** diff --git a/api/src/test/java/jakarta/mail/util/SharedFileInputStreamTest.java b/api/src/test/java/jakarta/mail/util/SharedFileInputStreamTest.java index 01409b33..d3aae154 100644 --- a/api/src/test/java/jakarta/mail/util/SharedFileInputStreamTest.java +++ b/api/src/test/java/jakarta/mail/util/SharedFileInputStreamTest.java @@ -16,8 +16,7 @@ package jakarta.mail.util; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.fail; +import org.junit.Test; import jakarta.mail.util.SharedFileInputStream.SharedFile; @@ -25,13 +24,11 @@ import java.io.IOException; import java.io.InputStream; import java.io.RandomAccessFile; -import java.lang.ref.PhantomReference; -import java.lang.ref.Reference; -import java.lang.ref.ReferenceQueue; import java.lang.reflect.Field; -import java.util.concurrent.TimeoutException; -import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; /** * Please note: @@ -101,25 +98,6 @@ public void testOpenIfOneOpened() throws Exception { assertEquals(true, isClosed(ra1)); } - @Test - public void testGC() throws Exception { - File file = new File(SharedFileInputStreamTest.class.getResource("/jakarta/mail/util/sharedinputstream.txt").toURI()); - SharedFileInputStream in = new SharedFileInputStream(file); - GCUtil gcUtil = new GCUtil(in); - SharedFileInputStream in0 = (SharedFileInputStream) in.newStream(0, 6); - in.close(); - in = null; - gcUtil.waitTillGCed(1000); - gcUtil = new GCUtil(in0); - SharedFileInputStream in1 = (SharedFileInputStream) in0.newStream(6, 12); - assertEquals("test0\n", new String(in0.readAllBytes())); - in0.close(); - in0 = null; - gcUtil.waitTillGCed(1000); - assertEquals("test1\n", new String(in1.readAllBytes())); - in1.close(); - } - private RandomAccessFile getRandomAccessFile(SharedFileInputStream in) throws Exception { Field f1 = SharedFileInputStream.class.getDeclaredField("sf"); f1.setAccessible(true); @@ -137,27 +115,4 @@ private boolean isClosed(RandomAccessFile rf) throws Exception { } } - private static class GCUtil { - - private final ReferenceQueue rq = new ReferenceQueue<>(); - private final PhantomReference phantomRef; - - private GCUtil(Object ref) { - phantomRef = new PhantomReference<>(ref, rq); - } - - private void waitTillGCed(long timeout) throws Exception { - Reference gced; - long time = 0; - long sleep = 100; - while ((gced = rq.poll()) != phantomRef) { - Thread.sleep(sleep); - time = time + sleep; - if (time >= timeout) { - throw new TimeoutException("Instance not GCed after " + timeout + " millis"); - } - System.gc(); - } - } - } } \ No newline at end of file