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

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

commit 25f41ea0ef11133716dae10eba9e5c332108445b
Author: Sylwester Lachiewicz <[email protected]>
AuthorDate: Wed Oct 28 21:51:33 2026 +0000

    Read jar resources without the JVM jar: cache
    
    The DI index, the core extension descriptor and lifecycle.xml were read
    with URL.openStream(), which leaves the plugin or extension jar open in
    the JVM-wide jar: cache for the rest of the build (JDK-8239054): it stays
    locked on Windows and is read stale under mvnd once rebuilt.
---
 .../maven/plugin/descriptor/PluginDescriptor.java  |  6 +++-
 .../extension/internal/CoreExtensionEntry.java     |  6 +++-
 .../org/apache/maven/di/impl/InjectorImpl.java     |  6 +++-
 .../org/apache/maven/di/impl/InjectorImplTest.java | 39 ++++++++++++++++++++++
 4 files changed, 54 insertions(+), 3 deletions(-)

diff --git 
a/compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
 
b/compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
index 776ba84c01..6ef652cffb 100644
--- 
a/compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
+++ 
b/compat/maven-plugin-api/src/main/java/org/apache/maven/plugin/descriptor/PluginDescriptor.java
@@ -25,6 +25,7 @@
 import java.io.InputStream;
 import java.net.MalformedURLException;
 import java.net.URL;
+import java.net.URLConnection;
 import java.nio.file.Files;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -446,7 +447,10 @@ private InputStream getDescriptorStream(String descriptor) 
throws IOException {
 
         if (pluginFile.isFile()) {
             try {
-                return new URL("jar:" + pluginFile.toURI() + "!/" + 
descriptor).openStream();
+                URLConnection connection = new URL("jar:" + pluginFile.toURI() 
+ "!/" + descriptor).openConnection();
+                // Uncached, so that closing the stream closes the jar 
(JDK-8239054)
+                connection.setUseCaches(false);
+                return connection.getInputStream();
             } catch (MalformedURLException e) {
                 throw new IllegalStateException(e);
             }
diff --git 
a/impl/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
 
b/impl/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
index f19a5bf6ef..b1d5e39f45 100644
--- 
a/impl/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
+++ 
b/impl/maven-core/src/main/java/org/apache/maven/extension/internal/CoreExtensionEntry.java
@@ -22,6 +22,7 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Enumeration;
@@ -110,7 +111,10 @@ public static CoreExtensionEntry discoverFrom(ClassRealm 
loader) {
             Enumeration<URL> urls = 
loader.getResources(BUILDER.getExtensionDescriptorLocation());
             while (urls.hasMoreElements()) {
 
-                try (InputStream is = urls.nextElement().openStream()) {
+                URLConnection connection = urls.nextElement().openConnection();
+                // Uncached, so that closing the stream closes the jar 
(JDK-8239054)
+                connection.setUseCaches(false);
+                try (InputStream is = connection.getInputStream()) {
                     ExtensionDescriptor descriptor = BUILDER.build(is);
                     artifacts.addAll(descriptor.getExportedArtifacts());
                     packages.addAll(descriptor.getExportedPackages());
diff --git 
a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java 
b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java
index 42a90e6945..b71e3f4e9e 100644
--- a/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java
+++ b/impl/maven-di/src/main/java/org/apache/maven/di/impl/InjectorImpl.java
@@ -26,6 +26,7 @@
 import java.lang.reflect.Modifier;
 import java.lang.reflect.Type;
 import java.net.URL;
+import java.net.URLConnection;
 import java.util.AbstractList;
 import java.util.AbstractMap;
 import java.util.AbstractSet;
@@ -97,7 +98,10 @@ public Injector discover(@Nonnull ClassLoader classLoader) {
             while (enumeration.hasMoreElements()) {
                 URL url = enumeration.nextElement();
                 if (loadedUrls.add(url.toExternalForm())) {
-                    try (InputStream is = url.openStream();
+                    URLConnection connection = url.openConnection();
+                    // Uncached, so that closing the stream closes the jar 
(JDK-8239054)
+                    connection.setUseCaches(false);
+                    try (InputStream is = connection.getInputStream();
                             BufferedReader reader =
                                     new BufferedReader(new 
InputStreamReader(Objects.requireNonNull(is)))) {
                         for (String line : reader.lines()
diff --git 
a/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java 
b/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java
index 01c32cc989..cef4bf586e 100644
--- a/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java
+++ b/impl/maven-di/src/test/java/org/apache/maven/di/impl/InjectorImplTest.java
@@ -18,14 +18,23 @@
  */
 package org.apache.maven.di.impl;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.lang.annotation.Retention;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
+import java.nio.file.Path;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.jar.JarOutputStream;
 import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
 
 import org.apache.maven.api.annotations.Nullable;
 import org.apache.maven.api.di.Inject;
@@ -38,6 +47,7 @@
 import org.apache.maven.di.Injector;
 import org.apache.maven.di.Key;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
 import static org.assertj.core.api.Assertions.assertThat;
@@ -52,6 +62,35 @@
 @SuppressWarnings("unused")
 public class InjectorImplTest {
 
+    @Test
+    void discoverReadsRewrittenJar(@TempDir Path tempDir) throws Exception {
+        Path jar = tempDir.resolve("plugin.jar");
+        writeIndex(jar, "# first");
+        discover(jar);
+
+        // Rewritten in place, as a plugin rebuilt in the reactor is.
+        writeIndex(jar, "# second, and longer than the first");
+        discover(jar);
+
+        // Nothing keeps the jar open, so it can be deleted (fails on Windows 
while it is open).
+        Files.delete(jar);
+    }
+
+    private static void discover(Path jar) throws IOException {
+        try (URLClassLoader loader = new URLClassLoader(new URL[] 
{jar.toUri().toURL()}, null)) {
+            Injector.create().discover(loader);
+        }
+    }
+
+    private static void writeIndex(Path jar, String content) throws 
IOException {
+        try (OutputStream out = Files.newOutputStream(jar);
+                JarOutputStream jarOut = new JarOutputStream(out)) {
+            jarOut.putNextEntry(new 
ZipEntry("META-INF/maven/org.apache.maven.api.di.Inject"));
+            jarOut.write(content.getBytes(StandardCharsets.UTF_8));
+            jarOut.closeEntry();
+        }
+    }
+
     @Test
     void markerQualifierTest() {
         Injector injector = 
Injector.create().bindImplicit(QualifierTest.class);

Reply via email to