This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-javadoc-plugin.git


The following commit(s) were added to refs/heads/master by this push:
     new 1ec5f318 Close resource jars after copying from them
1ec5f318 is described below

commit 1ec5f31819ca050993aa573128b420d834faf31f
Author: Sylwester Lachiewicz <[email protected]>
AuthorDate: Wed Oct 28 22:02:30 2026 +0000

    Close resource jars after copying from them
    
    copyResource never closed the stream it copied, and read it through the
    JVM-wide jar: cache, so a resourcesArtifacts jar stayed open for the
    rest of the build (JDK-8239054): locked on Windows and read stale under
    mvnd once rebuilt.
---
 .../apache/maven/plugins/javadoc/JavadocUtil.java  |  9 +++++-
 .../maven/plugins/javadoc/JavadocUtilTest.java     | 35 ++++++++++++++++++++++
 2 files changed, 43 insertions(+), 1 deletion(-)

diff --git a/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java 
b/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
index 86b7670a..eca0ac4a 100644
--- a/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
+++ b/src/main/java/org/apache/maven/plugins/javadoc/JavadocUtil.java
@@ -24,6 +24,7 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.FilterOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStream;
 import java.io.PrintStream;
@@ -34,6 +35,7 @@ import java.net.URI;
 import java.net.URISyntaxException;
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.net.URLConnection;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.StandardCharsets;
@@ -724,7 +726,12 @@ public class JavadocUtil {
             throw new NullPointerException("The url could not be null.");
         }
 
-        Files.copy(url.openStream(), file.toPath(), 
StandardCopyOption.REPLACE_EXISTING);
+        URLConnection connection = url.openConnection();
+        // Uncached, so that closing the stream closes the jar (JDK-8239054)
+        connection.setUseCaches(false);
+        try (InputStream in = connection.getInputStream()) {
+            Files.copy(in, file.toPath(), StandardCopyOption.REPLACE_EXISTING);
+        }
     }
 
     /**
diff --git 
a/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java 
b/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
index 5f118b83..337788ef 100644
--- a/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
+++ b/src/test/java/org/apache/maven/plugins/javadoc/JavadocUtilTest.java
@@ -30,6 +30,8 @@ import java.net.SocketTimeoutException;
 import java.net.URI;
 import java.net.URL;
 import java.net.UnknownHostException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.ArrayList;
@@ -41,6 +43,8 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.jar.JarOutputStream;
+import java.util.zip.ZipEntry;
 
 import org.apache.maven.plugin.testing.stubs.MavenProjectStub;
 import org.apache.maven.plugins.javadoc.ProxyServer.AuthAsyncProxyServlet;
@@ -57,6 +61,7 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.junit.jupiter.api.extension.ExtensionContext;
 import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
+import org.junit.jupiter.api.io.TempDir;
 
 import static org.apache.maven.api.plugin.testing.MojoExtension.getBasedir;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -74,6 +79,36 @@ import static org.junit.jupiter.api.Assumptions.abort;
 @ExtendWith(JavadocUtilTest.AbortWhenRemoteUnreachable.class)
 class JavadocUtilTest {
 
+    @Test
+    void copyResourceReadsRewrittenJar(@TempDir Path tempDir) throws Exception 
{
+        Path jar = tempDir.resolve("resources.jar");
+        File target = tempDir.resolve("stylesheet.css").toFile();
+        URL url = new URL("jar:" + jar.toUri() + "!/stylesheet.css");
+
+        writeJar(jar, "first");
+        JavadocUtil.copyResource(url, target);
+        assertEquals("first", new String(Files.readAllBytes(target.toPath()), 
StandardCharsets.UTF_8));
+
+        // Rewritten in place, as a resources module rebuilt in the reactor is.
+        writeJar(jar, "second, and longer than the first");
+        JavadocUtil.copyResource(url, target);
+        assertEquals(
+                "second, and longer than the first",
+                new String(Files.readAllBytes(target.toPath()), 
StandardCharsets.UTF_8));
+
+        // Nothing keeps the jar open, so it can be deleted (fails on Windows 
while it is open).
+        Files.delete(jar);
+    }
+
+    private static void writeJar(Path jar, String content) throws IOException {
+        try (OutputStream out = Files.newOutputStream(jar);
+                JarOutputStream jarOut = new JarOutputStream(out)) {
+            jarOut.putNextEntry(new ZipEntry("stylesheet.css"));
+            jarOut.write(content.getBytes(StandardCharsets.UTF_8));
+            jarOut.closeEntry();
+        }
+    }
+
     @Test
     void testParseJavadocVersionNull() {
         try {

Reply via email to