You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2026/09/09 14:28:45 UTC
(groovy) 01/01: GROOVY-12392: NativeImageMetadataGenerator references deprecated-for-removal Java9
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch GROOVY-12392
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit e4634917f265a0e61748cee73f49699411d056db
Author: Daniel Sun <su...@apache.org>
AuthorDate: Wed Sep 9 23:14:25 2026 +0900
GROOVY-12392: NativeImageMetadataGenerator references deprecated-for-removal Java9
NativeImageMetadataGenerator referenced the deprecated-for-removal Java9
class, which javac reported as [removal] on CI. Register those
Class.forName targets under Java17, the VM plugin Groovy 6 constructs,
as their own generate() family rather than as a rider on indyMachinery.
Package-list membership in checkAccessible now uses getOrDefault so
unknown modules are not inserted into the maps.
---
.../groovy/tools/NativeImageMetadataGenerator.java | 22 ++++-
.../codehaus/groovy/vmplugin/v17/package-info.java | 4 +
.../org/codehaus/groovy/vmplugin/v9/Java9.java | 19 +++-
.../codehaus/groovy/vmplugin/v9/package-info.java | 6 +-
.../groovy/tools/NativeImageMetadataTest.groovy | 13 +++
.../codehaus/groovy/vmplugin/v17/Java17Test.groovy | 104 +++++++++++++++++++++
6 files changed, 161 insertions(+), 7 deletions(-)
diff --git a/src/main/java/org/codehaus/groovy/tools/NativeImageMetadataGenerator.java b/src/main/java/org/codehaus/groovy/tools/NativeImageMetadataGenerator.java
index c0b084b44d..5843652b31 100644
--- a/src/main/java/org/codehaus/groovy/tools/NativeImageMetadataGenerator.java
+++ b/src/main/java/org/codehaus/groovy/tools/NativeImageMetadataGenerator.java
@@ -62,12 +62,12 @@ import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
import org.codehaus.groovy.vmplugin.VMPluginFactory;
+import org.codehaus.groovy.vmplugin.v17.Java17;
import org.codehaus.groovy.vmplugin.v8.IndyArrayAccess;
import org.codehaus.groovy.vmplugin.v8.IndyCompoundAssign;
import org.codehaus.groovy.vmplugin.v8.IndyGuardsFiltersAndSignatures;
import org.codehaus.groovy.vmplugin.v8.IndyInterface;
import org.codehaus.groovy.vmplugin.v8.IndyMath;
-import org.codehaus.groovy.vmplugin.v9.Java9;
import java.io.File;
import java.io.IOException;
@@ -118,6 +118,11 @@ import java.util.concurrent.Executors;
* Its classes obtain method handles to their own methods and to a few JDK and
* MOP methods through a {@code Lookup} held in a run-time-initialised class,
* which the image builder cannot fold, so the targets are registered.</li>
+ * <li><b>Default-import class discovery</b> (conditional on {@link Java17}).
+ * {@code getDefaultImportClasses} loads {@code GroovySystem} and
+ * {@code groovy.beans.ListenerList} by name to locate the groovy jar; those
+ * names are not constant {@code Class.forName} arguments the image builder
+ * can fold.</li>
* <li><b>Groovy-owned types that get a metaclass</b> (conditional on the
* registry too, since a metaclass can be created for a class before the class
* initialises). {@code CachedClass} reads their declared constructors, methods
@@ -392,6 +397,7 @@ public class NativeImageMetadataGenerator {
NativeImageMetadataGenerator generator = new NativeImageMetadataGenerator();
generator.registryBootstrap(records);
generator.indyMachinery();
+ generator.defaultImportClassLookups();
generator.asyncRuntime();
generator.introspectedTypes(records);
return generator.toJson();
@@ -512,9 +518,17 @@ public class NativeImageMetadataGenerator {
String reflectionUtils = ReflectionUtils.class.getName();
method(reflectionUtils, Class.class, "isSealed");
method(reflectionUtils, Class.class, "getPermittedSubclasses");
- // the Java 9 plugin locates the groovy jar by loading two of its classes by name
- addName(Java9.class.getName(), GroovySystem.class.getName(), NONE);
- addName(Java9.class.getName(), "groovy.beans.ListenerList", NONE); // Groovy source, not visible here
+ }
+
+ /**
+ * {@code getDefaultImportClasses} locates the groovy jar by loading two of
+ * its classes by name. Condition on {@link Java17}, not a deprecated Java 9
+ * ancestor.
+ */
+ private void defaultImportClassLookups() {
+ String vmPlugin = Java17.class.getName();
+ addName(vmPlugin, GroovySystem.class.getName(), NONE);
+ addName(vmPlugin, "groovy.beans.ListenerList", NONE); // Groovy source, not visible here
}
private void introspectedTypes(List<GeneratedMetaMethod.DgmMethodRecord> records) {
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v17/package-info.java b/src/main/java/org/codehaus/groovy/vmplugin/v17/package-info.java
index ee21d04433..9e84ced70f 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v17/package-info.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v17/package-info.java
@@ -19,5 +19,9 @@
/**
* Java 17 VM plugin. Compatibility layer for Java 17 LTS features.
+ * <p>
+ * This is the {@link org.codehaus.groovy.vmplugin.VMPluginFactory} entry point
+ * for Groovy 6 (JDK 17+). JPMS accessibility and default-import discovery are
+ * inherited from {@code org.codehaus.groovy.vmplugin.v9}.
*/
package org.codehaus.groovy.vmplugin.v17;
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
index e12de46762..3f63056716 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/Java9.java
@@ -55,6 +55,13 @@ import java.util.logging.Logger;
import java.util.stream.Collectors;
/**
+ * Java 9+ JPMS support: module-aware accessibility checks,
+ * {@code MethodHandles.privateLookupIn}, and default-import class discovery
+ * via the {@code jrt:} filesystem.
+ * <p>
+ * Groovy 6 selects {@link Java17} as the {@link org.codehaus.groovy.vmplugin.VMPluginFactory}
+ * entry point; this class remains the JPMS implementation that {@link Java17} inherits.
+ *
* @deprecated Use {@link Java17} instead. Groovy 6.0 requires JDK 17+.
*/
@Deprecated(since = "6.0.0", forRemoval = true)
@@ -283,12 +290,20 @@ public class Java9 extends Java8 {
return false;
}
+ /**
+ * JDK 8 packages in {@code module} that are now concealed.
+ * Unknown modules are not inserted into the map: callers only test membership.
+ */
private static Set<String> concealedPackageList(final Module module) {
- return CONCEALED_PACKAGES_TO_OPEN.computeIfAbsent(module.getName(), m -> new HashSet<>());
+ return CONCEALED_PACKAGES_TO_OPEN.getOrDefault(module.getName(), Set.of());
}
+ /**
+ * JDK 8 packages in {@code module} that are exported but not open.
+ * Unknown modules are not inserted into the map: callers only test membership.
+ */
private static Set<String> exportedPackageList(final Module module) {
- return EXPORTED_PACKAGES_TO_OPEN.computeIfAbsent(module.getName(), m -> new HashSet<>());
+ return EXPORTED_PACKAGES_TO_OPEN.getOrDefault(module.getName(), Set.of());
}
private static final Map<String, Set<String>> CONCEALED_PACKAGES_TO_OPEN;
diff --git a/src/main/java/org/codehaus/groovy/vmplugin/v9/package-info.java b/src/main/java/org/codehaus/groovy/vmplugin/v9/package-info.java
index e859199bf3..9a1684d089 100644
--- a/src/main/java/org/codehaus/groovy/vmplugin/v9/package-info.java
+++ b/src/main/java/org/codehaus/groovy/vmplugin/v9/package-info.java
@@ -18,6 +18,10 @@
*/
/**
- * Java 9 VM plugin. Compatibility layer for Java 9 module system.
+ * Java 9 VM plugin. Compatibility layer for the Java 9 module system (JPMS).
+ * <p>
+ * Groovy 6 requires JDK 17+ and selects {@link org.codehaus.groovy.vmplugin.v17.Java17}
+ * as the {@link org.codehaus.groovy.vmplugin.VMPluginFactory} entry point; types in this
+ * package remain the inherited JPMS implementation and are not constructed directly.
*/
package org.codehaus.groovy.vmplugin.v9;
diff --git a/src/test/groovy/org/codehaus/groovy/tools/NativeImageMetadataTest.groovy b/src/test/groovy/org/codehaus/groovy/tools/NativeImageMetadataTest.groovy
index cfb4081ee1..aebf2f7cad 100644
--- a/src/test/groovy/org/codehaus/groovy/tools/NativeImageMetadataTest.groovy
+++ b/src/test/groovy/org/codehaus/groovy/tools/NativeImageMetadataTest.groovy
@@ -25,6 +25,7 @@ import org.codehaus.groovy.reflection.GeneratedMetaMethod
import org.codehaus.groovy.runtime.DefaultGroovyMethods
import org.codehaus.groovy.runtime.DefaultGroovyStaticMethods
import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl
+import org.codehaus.groovy.vmplugin.VMPluginFactory
import org.codehaus.groovy.vmplugin.v8.IndyInterface
import org.junit.jupiter.api.Test
@@ -167,6 +168,18 @@ final class NativeImageMetadataTest {
}
}
+ @Test
+ void vmPluginLocatesTheGroovyJarByLoadingTwoOfItsClasses() {
+ // getDefaultImportClasses loads these by name to find the groovy jar;
+ // the condition must be the live plugin, not a deprecated ancestor.
+ String plugin = VMPluginFactory.plugin.class.name
+ ['groovy.lang.GroovySystem', 'groovy.beans.ListenerList'].each { name ->
+ def hits = reflection().findAll { it.type == name && it.condition.typeReached == plugin }
+ assert hits.size() == 1 : "$name under $plugin: $hits"
+ assert hits[0].keySet() == ['condition', 'type'] as Set : "name-only load: ${hits[0]}"
+ }
+ }
+
@Test
void asyncRuntimeLookupsAreRegisteredByName() {
def executors = reflection().findAll { it.type == 'java.util.concurrent.Executors' }
diff --git a/src/test/groovy/org/codehaus/groovy/vmplugin/v17/Java17Test.groovy b/src/test/groovy/org/codehaus/groovy/vmplugin/v17/Java17Test.groovy
new file mode 100644
index 0000000000..6ac2744700
--- /dev/null
+++ b/src/test/groovy/org/codehaus/groovy/vmplugin/v17/Java17Test.groovy
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.codehaus.groovy.vmplugin.v17
+
+import org.codehaus.groovy.vmplugin.VMPlugin
+import org.codehaus.groovy.vmplugin.VMPluginFactory
+import org.junit.jupiter.api.Test
+
+import java.lang.reflect.Modifier
+import java.net.http.HttpClient
+
+import static org.junit.jupiter.api.Assumptions.assumeTrue
+
+/**
+ * Membership lookups used by {@code checkAccessible}: JDK 8 packages that are
+ * now concealed or exported-but-not-open, and modules absent from those maps.
+ */
+final class Java17Test {
+
+ private static final VMPlugin PLUGIN = VMPluginFactory.plugin
+
+ @Test
+ void publicExportedJdkTypeIsAccessible() {
+ [false, true].each { allow ->
+ assert PLUGIN.checkAccessible(Java17Test, String, Modifier.PUBLIC, allow) : allow
+ }
+ }
+
+ @Test
+ void publicTypeInPostJava8ModuleIsAccessible() {
+ // java.net.http is not a JDK 8 package, so the module is absent from
+ // the concealed/exported-to-open maps; membership must still succeed.
+ [false, true].each { allow ->
+ assert PLUGIN.checkAccessible(Java17Test, HttpClient, Modifier.PUBLIC, allow) : allow
+ }
+ }
+
+ @Test
+ void concealedJdkPackageIsNotAccessible() {
+ Class type = concealedJdkType()
+ assumeTrue(type != null, 'no non-exported JDK class visible on this runtime')
+ [false, true].each { allow ->
+ assert !PLUGIN.checkAccessible(Java17Test, type, Modifier.PUBLIC, allow) : "$type $allow"
+ assert !PLUGIN.checkAccessible(Java17Test, type, Modifier.PRIVATE, allow) : "$type $allow"
+ }
+ }
+
+ @Test
+ void privateMemberOfDescriptorOpenedJdkPackageIsAccessible() {
+ // jdk.unsupported opens sun.misc / sun.reflect to all modules; those
+ // packages are omitted from the Java 8 exported-to-open list, so the
+ // unnamed module may read private members even without allowIllegalAccess.
+ Class type = descriptorOpenedJdkType()
+ assumeTrue(type != null, 'no descriptor-open JDK type visible on this runtime')
+ [false, true].each { allow ->
+ assert PLUGIN.checkAccessible(Java17Test, type, Modifier.PUBLIC, allow) : "$type $allow"
+ assert PLUGIN.checkAccessible(Java17Test, type, Modifier.PRIVATE, allow) : "$type $allow"
+ }
+ }
+
+ /** First JDK class whose package is not exported to this (unnamed) module. */
+ private static Class concealedJdkType() {
+ for (String name : ['jdk.internal.misc.Unsafe', 'jdk.internal.access.SharedSecrets', 'sun.misc.Unsafe']) {
+ try {
+ Class c = Class.forName(name)
+ if (!c.module.isExported(c.packageName, Java17Test.module)) return c
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+ null
+ }
+
+ /** First public JDK class whose package is open to this module by the module descriptor. */
+ private static Class descriptorOpenedJdkType() {
+ for (String name : ['sun.misc.Unsafe', 'sun.reflect.ReflectionFactory']) {
+ try {
+ Class c = Class.forName(name)
+ if (c.module.isNamed()
+ && c.module.isExported(c.packageName, Java17Test.module)
+ && c.module.isOpen(c.packageName, Java17Test.module)) {
+ return c
+ }
+ } catch (ClassNotFoundException ignored) {
+ }
+ }
+ null
+ }
+}