Skip to content

Commit 88e44f1

Browse files
committed
Support compatibility mode in GraalVM
1 parent ffb728f commit 88e44f1

12 files changed

Lines changed: 87 additions & 100 deletions

File tree

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeature.java

Lines changed: 10 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@
4242
package org.graalvm.junit.platform;
4343

4444
import org.graalvm.junit.platform.config.core.PluginConfigProvider;
45-
import org.graalvm.nativeimage.ImageSingletons;
4645
import org.graalvm.nativeimage.hosted.Feature;
4746
import org.graalvm.nativeimage.hosted.RuntimeClassInitialization;
4847
import org.graalvm.nativeimage.hosted.RuntimeReflection;
49-
5048
import org.junit.platform.engine.DiscoverySelector;
5149
import org.junit.platform.engine.discovery.DiscoverySelectors;
5250
import org.junit.platform.engine.discovery.UniqueIdSelector;
@@ -77,28 +75,16 @@
7775
@SuppressWarnings("unused")
7876
public final class JUnitPlatformFeature implements Feature {
7977

80-
public final boolean debug = System.getProperty("debug") != null;
81-
private static final NativeImageConfigurationImpl nativeImageConfigImpl = new NativeImageConfigurationImpl();
8278
private final ServiceLoader<PluginConfigProvider> extensionConfigProviders = ServiceLoader.load(PluginConfigProvider.class);
8379

84-
public static void debug(String format, Object... args) {
85-
if (debug()) {
86-
System.out.printf("[Debug] " + format + "%n", args);
87-
}
88-
}
89-
9080
@Override
9181
public void afterRegistration(AfterRegistrationAccess access) {
92-
extensionConfigProviders.forEach(p -> p.initialize(access.getApplicationClassLoader(), nativeImageConfigImpl));
93-
}
94-
95-
private static boolean debug() {
96-
return ImageSingletons.lookup(JUnitPlatformFeature.class).debug;
82+
extensionConfigProviders.forEach(p -> p.initialize(access.getApplicationClassLoader()));
9783
}
9884

9985
@Override
10086
public void duringSetup(DuringSetupAccess access) {
101-
forEachProvider(p -> p.onLoad(nativeImageConfigImpl));
87+
forEachProvider(PluginConfigProvider::onLoad);
10288
}
10389

10490
@Override
@@ -141,7 +127,8 @@ private List<? extends DiscoverySelector> getSelectors() {
141127
return selectors;
142128
}
143129
} catch (Exception ex) {
144-
debug("Failed to read UIDs from UniqueIdTrackingListener output files: " + ex.getMessage());
130+
String format = "Failed to read UIDs from UniqueIdTrackingListener output files: " + ex.getMessage();
131+
JUnitPlatformFeatureUtils.debug(format);
145132
}
146133

147134
throw new RuntimeException("Cannot compute test selectors from test ids.");
@@ -156,9 +143,9 @@ private void registerTestClassesForReflection(List<? extends DiscoverySelector>
156143
.build();
157144

158145
TestClassRegistrar testClassRegistrar = new TestClassRegistrar(clazz -> {
159-
debug("Registering test class for reflection: %s", clazz.getName());
160-
nativeImageConfigImpl.registerAllClassMembersForReflection(clazz);
161-
forEachProvider(p -> p.onTestClassRegistered(clazz, nativeImageConfigImpl));
146+
JUnitPlatformFeatureUtils.debug("Registering test class for reflection: %s", clazz.getName());
147+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(clazz);
148+
forEachProvider(p -> p.onTestClassRegistered(clazz));
162149
});
163150

164151
Launcher launcher = LauncherFactory.create();
@@ -195,8 +182,8 @@ private static Stream<Path> findFiles(Path dir, String prefix) throws IOExceptio
195182
return Stream.empty();
196183
}
197184
return Files.find(dir, Integer.MAX_VALUE,
198-
(path, basicFileAttributes) -> (basicFileAttributes.isRegularFile()
199-
&& path.getFileName().toString().startsWith(prefix)));
185+
(path, basicFileAttributes) -> (basicFileAttributes.isRegularFile()
186+
&& path.getFileName().toString().startsWith(prefix)));
200187
}
201188

202189
private static void registerClassesForHamcrestSupport(BeforeAnalysisAccess access) {
@@ -239,4 +226,5 @@ private static void initializeClassesForJDK21OrEarlier() {
239226
throw new RuntimeException("Failed to process build time initializations for JDK 21 or earlier");
240227
}
241228
}
229+
242230
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/NativeImageConfigurationImpl.java renamed to common/junit-platform-native/src/main/java/org/graalvm/junit/platform/JUnitPlatformFeatureUtils.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2026, 2026, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* The Universal Permissive License (UPL), Version 1.0
@@ -38,29 +38,29 @@
3838
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
3939
* SOFTWARE.
4040
*/
41-
4241
package org.graalvm.junit.platform;
4342

44-
import org.graalvm.junit.platform.config.core.NativeImageConfiguration;
43+
import org.graalvm.nativeimage.ImageInfo;
4544
import org.graalvm.nativeimage.hosted.RuntimeReflection;
4645

47-
import java.lang.reflect.Executable;
48-
import java.lang.reflect.Field;
49-
50-
class NativeImageConfigurationImpl implements NativeImageConfiguration {
51-
52-
@Override
53-
public void registerForReflection(Class<?>... classes) {
54-
RuntimeReflection.register(classes);
55-
}
46+
public class JUnitPlatformFeatureUtils {
47+
public static final boolean debug = System.getProperty("org.graalvm.junit.platform.debug") != null;
5648

57-
@Override
58-
public void registerForReflection(Executable... methods) {
59-
RuntimeReflection.register(methods);
49+
public static void debug(String format, Object... args) {
50+
if (JUnitPlatformFeatureUtils.debug) {
51+
System.out.printf("[Debug] " + format + "%n", args);
52+
}
6053
}
6154

62-
@Override
63-
public void registerForReflection(Field... fields) {
64-
RuntimeReflection.register(fields);
55+
public static void registerAllClassMembersForReflection(Class<?>... classes) {
56+
if (ImageInfo.inImageBuildtimeCode()) {
57+
for (Class<?> clazz : classes) {
58+
JUnitPlatformFeatureUtils.debug("[Native Image Configuration] Registering for reflection: %s", clazz.getName());
59+
RuntimeReflection.register(clazz);
60+
RuntimeReflection.register(clazz.getDeclaredConstructors());
61+
RuntimeReflection.register(clazz.getDeclaredMethods());
62+
RuntimeReflection.register(clazz.getDeclaredFields());
63+
}
64+
}
6565
}
6666
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/core/NativeImageConfiguration.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
package org.graalvm.junit.platform.config.core;
4343

44-
import org.graalvm.junit.platform.JUnitPlatformFeature;
44+
import org.graalvm.junit.platform.JUnitPlatformFeatureUtils;
4545
import org.graalvm.junit.platform.config.util.Utils;
4646

4747
import java.lang.reflect.Executable;
@@ -61,7 +61,7 @@ default void registerAllClassMembersForReflection(String... classNames) {
6161

6262
default void registerAllClassMembersForReflection(Class<?>... classes) {
6363
for (Class<?> clazz : classes) {
64-
JUnitPlatformFeature.debug("[Native Image Configuration] Registering for reflection: %s", clazz.getName());
64+
JUnitPlatformFeatureUtils.debug("[Native Image Configuration] Registering for reflection: %s", clazz.getName());
6565
registerForReflection(clazz);
6666
registerForReflection(clazz.getDeclaredConstructors());
6767
registerForReflection(clazz.getDeclaredMethods());

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/core/PluginConfigProvider.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -47,16 +47,13 @@
4747
public abstract class PluginConfigProvider {
4848

4949
protected ClassLoader applicationClassLoader;
50-
protected NativeImageConfiguration nativeImageConfigImpl;
5150

51+
public abstract void onLoad();
5252

53-
public abstract void onLoad(NativeImageConfiguration config);
53+
public abstract void onTestClassRegistered(Class<?> testClass);
5454

55-
public abstract void onTestClassRegistered(Class<?> testClass, NativeImageConfiguration registry);
56-
57-
public final void initialize(ClassLoader classLoader, NativeImageConfiguration nic) {
55+
public final void initialize(ClassLoader classLoader) {
5856
applicationClassLoader = classLoader;
59-
nativeImageConfigImpl = nic;
6057
}
6158

6259
@SuppressWarnings("unchecked")

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/jupiter/JupiterConfigProvider.java

Lines changed: 25 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,10 @@
4141

4242
package org.graalvm.junit.platform.config.jupiter;
4343

44-
import org.graalvm.junit.platform.config.core.NativeImageConfiguration;
44+
import org.graalvm.junit.platform.JUnitPlatformFeatureUtils;
4545
import org.graalvm.junit.platform.config.core.PluginConfigProvider;
4646
import org.graalvm.junit.platform.config.util.AnnotationUtils;
47+
import org.graalvm.junit.platform.config.util.Utils;
4748
import org.junit.jupiter.api.DisplayNameGeneration;
4849
import org.junit.jupiter.api.IndicativeSentencesGeneration;
4950
import org.junit.jupiter.api.TestMethodOrder;
@@ -61,56 +62,53 @@
6162
import java.util.ArrayList;
6263
import java.util.List;
6364

64-
import static org.graalvm.junit.platform.JUnitPlatformFeature.debug;
65+
import static org.graalvm.junit.platform.JUnitPlatformFeatureUtils.debug;
6566

6667
public class JupiterConfigProvider extends PluginConfigProvider {
6768

6869
@Override
69-
public void onLoad(NativeImageConfiguration config) {
70+
public void onLoad() {
7071
/* Provide support for Timeout annotation */
71-
config.registerAllClassMembersForReflection(
72-
"org.junit.jupiter.engine.extension.TimeoutExtension$ExecutorResource",
73-
"org.junit.jupiter.engine.extension.TimeoutInvocationFactory$SingleThreadExecutorResource"
74-
);
72+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(Utils.toClasses("org.junit.jupiter.engine.extension.TimeoutExtension$ExecutorResource", "org.junit.jupiter.engine.extension.TimeoutInvocationFactory$SingleThreadExecutorResource"));
7573
}
7674

7775
@Override
78-
public void onTestClassRegistered(Class<?> testClass, NativeImageConfiguration registry) {
76+
public void onTestClassRegistered(Class<?> testClass) {
7977
/* Provide support for various annotations */
8078

8179
/* Annotations from org.junit.jupiter.api */
8280
try {
83-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, TestMethodOrder.class, TestMethodOrder::value);
84-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, ExtendWith.class, ExtendWith::value);
85-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, DisplayNameGeneration.class, DisplayNameGeneration::value);
86-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, IndicativeSentencesGeneration.class, IndicativeSentencesGeneration::generator);
87-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, EnabledIf.class, JupiterConfigProvider::handleEnabledIf);
88-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, DisabledIf.class, JupiterConfigProvider::handleDisabledIf);
81+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, TestMethodOrder.class, TestMethodOrder::value);
82+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, ExtendWith.class, ExtendWith::value);
83+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, DisplayNameGeneration.class, DisplayNameGeneration::value);
84+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, IndicativeSentencesGeneration.class, IndicativeSentencesGeneration::generator);
85+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, EnabledIf.class, JupiterConfigProvider::handleEnabledIf);
86+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, DisabledIf.class, JupiterConfigProvider::handleDisabledIf);
8987
} catch (NoClassDefFoundError e) {
9088
debug("Cannot register annotations %s from 'org.junit.jupiter.api'. " +
91-
"Please verify that you have dependency that includes 'org.junit.jupiter.api' if you want to use these annotations.",
92-
List.of("TestMethodOrder", "ExtendWith", "DisplayNameGeneration", "IndicativeSentencesGeneration", "EnabledIf", "DisabledIf"));
89+
"Please verify that you have dependency that includes 'org.junit.jupiter.api' if you want to use these annotations.",
90+
List.of("TestMethodOrder", "ExtendWith", "DisplayNameGeneration", "IndicativeSentencesGeneration", "EnabledIf", "DisabledIf"));
9391
}
9492

9593
/* Annotations from org.junit.jupiter.params */
9694
try {
97-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, ArgumentsSource.class, ArgumentsSource::value);
98-
AnnotationUtils.forEachAnnotatedMethodParameter(testClass, ConvertWith.class, annotation -> registry.registerAllClassMembersForReflection(annotation.value()));
99-
AnnotationUtils.forEachAnnotatedMethodParameter(testClass, AggregateWith.class, annotation -> registry.registerAllClassMembersForReflection(annotation.value()));
100-
AnnotationUtils.forEachAnnotatedMethod(testClass, EnumSource.class, (m, annotation) -> handleEnumSource(m, annotation, registry));
101-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, MethodSource.class, JupiterConfigProvider::handleMethodSource);
95+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, ArgumentsSource.class, ArgumentsSource::value);
96+
AnnotationUtils.forEachAnnotatedMethodParameter(testClass, ConvertWith.class, annotation -> JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(annotation.value()));
97+
AnnotationUtils.forEachAnnotatedMethodParameter(testClass, AggregateWith.class, annotation -> JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(annotation.value()));
98+
AnnotationUtils.forEachAnnotatedMethod(testClass, EnumSource.class, (m, annotation) -> handleEnumSource(m, annotation));
99+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, MethodSource.class, JupiterConfigProvider::handleMethodSource);
102100

103101
// special case because the class might not be available because the annotation was introduced in JUnit 5.13
104102
try {
105-
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, registry, FieldSource.class, JupiterConfigProvider::handleFieldSource);
103+
AnnotationUtils.registerClassesFromAnnotationForReflection(testClass, FieldSource.class, JupiterConfigProvider::handleFieldSource);
106104
} catch (NoClassDefFoundError e) {
107105
debug("Cannot register @FieldSource annotation from org.junit.jupiter.params. " +
108106
"Please verify that you have this dependency (with version greater than JUnit 5.13) if you want to use this annotation.");
109107
}
110108
} catch (NoClassDefFoundError e) {
111109
debug("Cannot register annotations %s from 'org.junit.jupiter.params'. " +
112-
"Please verify that you have dependency that includes 'org.junit.jupiter.params' if you want to use these annotations.",
113-
List.of("ArgumentsSource", "ConvertWith", "AggregateWith", "EnumSource", "MethodSource", "FieldSource"));
110+
"Please verify that you have dependency that includes 'org.junit.jupiter.params' if you want to use these annotations.",
111+
List.of("ArgumentsSource", "ConvertWith", "AggregateWith", "EnumSource", "MethodSource", "FieldSource"));
114112
}
115113

116114
}
@@ -155,15 +153,15 @@ private static Class<?>[] handleMethodReference(String... methodNames) {
155153
return classList.toArray(new Class<?>[0]);
156154
}
157155

158-
public static void handleEnumSource(Method method, EnumSource source, NativeImageConfiguration registry) {
159-
registry.registerAllClassMembersForReflection(source.value());
156+
public static void handleEnumSource(Method method, EnumSource source) {
157+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(source.value());
160158
if (method.getParameterCount() > 0) {
161159
Class<?>[] parameterTypes = method.getParameterTypes();
162160
/* EnumSource annotated methods without an enum in the annotation value must have the enum as the first parameter. */
163161
Class<?> enumParameterType = parameterTypes[0];
164162
if (enumParameterType.isEnum()) {
165163
debug("Registering method enum parameter for reflection. Method: %s Parameter: %s", method, parameterTypes[0]);
166-
registry.registerAllClassMembersForReflection(enumParameterType);
164+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(enumParameterType);
167165
} else {
168166
debug("First parameter of method not an enum - skipping. Method: %s", method);
169167
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/platform/PlatformConfigProvider.java

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,21 @@
4141

4242
package org.graalvm.junit.platform.config.platform;
4343

44-
import org.graalvm.junit.platform.config.core.NativeImageConfiguration;
4544
import org.graalvm.junit.platform.config.core.PluginConfigProvider;
45+
import org.graalvm.nativeimage.ImageInfo;
4646
import org.graalvm.nativeimage.hosted.RuntimeSerialization;
4747
import org.junit.platform.launcher.TestIdentifier;
4848

4949
public class PlatformConfigProvider extends PluginConfigProvider {
5050

5151
@Override
52-
public void onLoad(NativeImageConfiguration config) {
53-
RuntimeSerialization.register(TestIdentifier.class.getDeclaredClasses());
52+
public void onLoad() {
53+
if (ImageInfo.inImageBuildtimeCode()) {
54+
RuntimeSerialization.register(TestIdentifier.class.getDeclaredClasses());
55+
}
5456
}
5557

5658
@Override
57-
public void onTestClassRegistered(Class<?> testClass, NativeImageConfiguration registry) {
59+
public void onTestClassRegistered(Class<?> testClass) {
5860
}
5961
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/util/AnnotationUtils.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
package org.graalvm.junit.platform.config.util;
4343

44-
import org.graalvm.junit.platform.config.core.NativeImageConfiguration;
44+
import org.graalvm.junit.platform.JUnitPlatformFeatureUtils;
4545
import org.junit.platform.commons.support.AnnotationSupport;
4646

4747
import java.lang.annotation.Annotation;
@@ -112,17 +112,17 @@ public interface ClassProvider<T extends Annotation> extends Function<T, Class<?
112112
public interface ClassArrayProvider<T extends Annotation> extends Function<T, Class<?>[]> {
113113
}
114114

115-
public static <T extends Annotation> void registerClassesFromAnnotationForReflection(Class<?> testClass, NativeImageConfiguration config, Class<T> annotation, ClassArrayProvider<T> classProvider) {
115+
public static <T extends Annotation> void registerClassesFromAnnotationForReflection(Class<?> testClass, Class<T> annotation, ClassArrayProvider<T> classProvider) {
116116
forEachAnnotationOnClassMembers(testClass, annotation, a -> {
117117
Class<?>[] reflectivelyAccessedClasses = classProvider.apply(a);
118-
config.registerAllClassMembersForReflection(reflectivelyAccessedClasses);
118+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(reflectivelyAccessedClasses);
119119
});
120120
}
121121

122-
public static <T extends Annotation> void registerClassesFromAnnotationForReflection(Class<?> testClass, NativeImageConfiguration config, Class<T> annotation, ClassProvider<T> classProvider) {
122+
public static <T extends Annotation> void registerClassesFromAnnotationForReflection(Class<?> testClass, Class<T> annotation, ClassProvider<T> classProvider) {
123123
forEachAnnotationOnClassMembers(testClass, annotation, a -> {
124124
Class<?> reflectivelyAccessedClass = classProvider.apply(a);
125-
config.registerAllClassMembersForReflection(reflectivelyAccessedClass);
125+
JUnitPlatformFeatureUtils.registerAllClassMembersForReflection(reflectivelyAccessedClass);
126126
});
127127
}
128128
}

common/junit-platform-native/src/main/java/org/graalvm/junit/platform/config/util/Utils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@
4141

4242
package org.graalvm.junit.platform.config.util;
4343

44-
import org.graalvm.junit.platform.JUnitPlatformFeature;
44+
import org.graalvm.junit.platform.JUnitPlatformFeatureUtils;
4545

4646
import java.util.Arrays;
4747

@@ -52,7 +52,7 @@ public static Class<?>[] toClasses(String... classNames) {
5252
try {
5353
clazz = Class.forName(className);
5454
} catch (ClassNotFoundException e) {
55-
JUnitPlatformFeature.debug("[Native Image Configuration] Failed to resolve: %s Reason: %s", className, e);
55+
JUnitPlatformFeatureUtils.debug("[Native Image Configuration] Failed to resolve: %s Reason: %s", className, e);
5656
}
5757
return clazz;
5858
}).filter(c -> c != null).toArray(Class[]::new);

0 commit comments

Comments
 (0)