From ba87cdaed6fff5ba4be29d261faa0373fad2116e Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 19 Aug 2026 20:50:18 +0000 Subject: [PATCH 1/8] fix(gax): register Conscrypt SSLContext SPI classes for GraalVM reflection --- .../nativeimage/GoogleJsonClientFeature.java | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 18f839547888..24d3b9c86278 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -31,6 +31,7 @@ package com.google.api.gax.nativeimage; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection; import org.graalvm.nativeimage.hosted.Feature; import org.jspecify.annotations.NullMarked; @@ -51,9 +52,31 @@ final class GoogleJsonClientFeature implements Feature { public void beforeAnalysis(BeforeAnalysisAccess access) { loadApiClient(access); loadHttpClient(access); + loadConscrypt(access); loadMiscClasses(access); } + /** + * Registers Conscrypt SSLContext and Security Provider SPI implementation classes (and their + * nested protocol subclasses) for GraalVM reflection when Conscrypt is present on the classpath. + * + *

When Conscrypt is configured as the security provider for HTTP/JSON transports, Java's JCA + * framework reflectively instantiates provider implementation classes (e.g. {@code + * OpenSSLContextImpl$TLSv13}) via String lookup in {@code SSLContext.getInstance("TLS", + * provider)}. In GraalVM Native Image builds, these reflectively looked-up SPI classes are + * stripped by static analysis unless explicitly registered for reflection, leading to {@code + * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. + */ + private void loadConscrypt(BeforeAnalysisAccess access) { + Class conscryptClass = access.findClassByName("org.conscrypt.Conscrypt"); + if (conscryptClass != null) { + registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLContextImpl"); + registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLProvider"); + registerClassHierarchyForReflection(access, "org.conscrypt.KeyManagerFactoryImpl"); + registerClassHierarchyForReflection(access, "org.conscrypt.TrustManagerFactoryImpl"); + } + } + private void loadApiClient(BeforeAnalysisAccess access) { // For com.google.api-client:google-api-client Class googleApiClientClass = access.findClassByName(GOOGLE_API_CLIENT_CLASS); From 1275954509c4860d5af1348de934912091f97a0e Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 19 Aug 2026 21:59:07 +0000 Subject: [PATCH 2/8] fix(native-image): register Conscrypt JNI classes and native library resources for GraalVM --- .../gax/nativeimage/GoogleJsonClientFeature.java | 13 +++++++++++-- .../api/gax/nativeimage/NativeImageUtils.java | 13 +++++++++++++ .../com.google.api/gax/resource-config.json | 3 ++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 24d3b9c86278..bdec56974bc5 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -30,6 +30,7 @@ package com.google.api.gax.nativeimage; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForJni; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection; @@ -58,14 +59,17 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { /** * Registers Conscrypt SSLContext and Security Provider SPI implementation classes (and their - * nested protocol subclasses) for GraalVM reflection when Conscrypt is present on the classpath. + * nested protocol subclasses) for GraalVM reflection, as well as Conscrypt native JNI classes + * and native C shared library resources when Conscrypt is present on the classpath. * *

When Conscrypt is configured as the security provider for HTTP/JSON transports, Java's JCA * framework reflectively instantiates provider implementation classes (e.g. {@code * OpenSSLContextImpl$TLSv13}) via String lookup in {@code SSLContext.getInstance("TLS", * provider)}. In GraalVM Native Image builds, these reflectively looked-up SPI classes are * stripped by static analysis unless explicitly registered for reflection, leading to {@code - * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. + * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. Additionally, native + * JNI methods in {@code NativeCrypto} and native shared library resources must be registered for + * GraalVM JNI linkage. */ private void loadConscrypt(BeforeAnalysisAccess access) { Class conscryptClass = access.findClassByName("org.conscrypt.Conscrypt"); @@ -74,6 +78,11 @@ private void loadConscrypt(BeforeAnalysisAccess access) { registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLProvider"); registerClassHierarchyForReflection(access, "org.conscrypt.KeyManagerFactoryImpl"); registerClassHierarchyForReflection(access, "org.conscrypt.TrustManagerFactoryImpl"); + + // Register Conscrypt native JNI bridge classes + registerClassForJni(access, "org.conscrypt.NativeCrypto"); + registerClassForJni(access, "org.conscrypt.NativeCryptoJni"); + registerClassForJni(access, "org.conscrypt.OpenSSLBioSession"); } } diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index 3365daa3aee9..bf0af6ee6e14 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -98,6 +98,19 @@ public static void registerClassForReflection(FeatureAccess access, String name) } } + /** Registers an entire class for JNI use. */ + public static void registerClassForJni(FeatureAccess access, String name) { + Class clazz = access.findClassByName(name); + if (clazz != null) { + org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz); + org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredConstructors()); + org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredFields()); + org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredMethods()); + } else { + LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); + } + } + /** * Registers the transitive class hierarchy of the provided {@code className} for reflection. * diff --git a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json index bc40a95d55ef..b9b5abbba06d 100644 --- a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json +++ b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json @@ -4,6 +4,7 @@ {"pattern":"\\Qdependencies.properties\\E"}, {"pattern":"\\Qcom/google/api/client/googleapis/google-api-client.properties\\E"}, {"pattern":"\\Qcom/google/api/client/googleapis/google.p12\\E"}, - {"pattern":"\\Qcom/google/api/client/http/google-http-client.properties\\E"}], + {"pattern":"\\Qcom/google/api/client/http/google-http-client.properties\\E"}, + {"pattern":".*libconscrypt_openjdk_jni.*"}], "bundles":[] } From 45f25181b1df2a03abd35adff0b92c00f23067d5 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Wed, 19 Aug 2026 22:05:47 +0000 Subject: [PATCH 3/8] style: use imported RuntimeJNIAccess instead of fully qualified name --- .../com/google/api/gax/nativeimage/NativeImageUtils.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index bf0af6ee6e14..d8a22565b311 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -36,6 +36,7 @@ import java.util.logging.Level; import java.util.logging.Logger; import org.graalvm.nativeimage.hosted.Feature.FeatureAccess; +import org.graalvm.nativeimage.hosted.RuntimeJNIAccess; import org.graalvm.nativeimage.hosted.RuntimeReflection; import org.jspecify.annotations.NullMarked; @@ -102,10 +103,10 @@ public static void registerClassForReflection(FeatureAccess access, String name) public static void registerClassForJni(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { - org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz); - org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredConstructors()); - org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredFields()); - org.graalvm.nativeimage.hosted.RuntimeJNIAccess.register(clazz.getDeclaredMethods()); + RuntimeJNIAccess.register(clazz); + RuntimeJNIAccess.register(clazz.getDeclaredConstructors()); + RuntimeJNIAccess.register(clazz.getDeclaredFields()); + RuntimeJNIAccess.register(clazz.getDeclaredMethods()); } else { LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); } From 0a3ffb9aa515f154d83d2d8e766fc429af5a01b8 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 20 Aug 2026 00:21:56 +0000 Subject: [PATCH 4/8] fix(native-image): initialize org.conscrypt at run-time instead of build-time --- .../native-image/com.google.api/gax/native-image.properties | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/native-image.properties b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/native-image.properties index 5d11a38791f8..a31e2ab9b761 100644 --- a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/native-image.properties +++ b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/native-image.properties @@ -1,6 +1,6 @@ Args = --enable-url-protocols=https,http \ ---initialize-at-build-time=org.conscrypt,\ - org.junit.platform.engine.TestTag,\ +--initialize-at-run-time=org.conscrypt \ +--initialize-at-build-time=org.junit.platform.engine.TestTag,\ com.google.api.gax.core.GaxProperties,\ com.google.common.base.Platform,\ com.google.common.base.Platform$JdkPatternCompiler,\ From 54b025a308c6c811552d9cafede8cdc7ab1a1d96 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 20 Aug 2026 01:02:17 +0000 Subject: [PATCH 5/8] fix(native-image): register NativeCrypto hierarchy and platform-agnostic conscrypt native library resource pattern --- .../google/api/gax/nativeimage/GoogleJsonClientFeature.java | 6 +++++- .../native-image/com.google.api/gax/resource-config.json | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index bdec56974bc5..5cc84795873a 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -79,7 +79,11 @@ private void loadConscrypt(BeforeAnalysisAccess access) { registerClassHierarchyForReflection(access, "org.conscrypt.KeyManagerFactoryImpl"); registerClassHierarchyForReflection(access, "org.conscrypt.TrustManagerFactoryImpl"); - // Register Conscrypt native JNI bridge classes + // Register Conscrypt native JNI bridge classes and hierarchy + registerClassHierarchyForReflection(access, "org.conscrypt.NativeCrypto"); + registerClassHierarchyForReflection(access, "org.conscrypt.NativeCryptoJni"); + registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLBioSession"); + registerClassForJni(access, "org.conscrypt.NativeCrypto"); registerClassForJni(access, "org.conscrypt.NativeCryptoJni"); registerClassForJni(access, "org.conscrypt.OpenSSLBioSession"); diff --git a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json index b9b5abbba06d..604cb8f06919 100644 --- a/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json +++ b/sdk-platform-java/gax-java/gax/src/main/resources/META-INF/native-image/com.google.api/gax/resource-config.json @@ -5,6 +5,6 @@ {"pattern":"\\Qcom/google/api/client/googleapis/google-api-client.properties\\E"}, {"pattern":"\\Qcom/google/api/client/googleapis/google.p12\\E"}, {"pattern":"\\Qcom/google/api/client/http/google-http-client.properties\\E"}, - {"pattern":".*libconscrypt_openjdk_jni.*"}], + {"pattern":".*conscrypt_openjdk_jni.*"}], "bundles":[] } From 463e915570b5aa9abfc368297aec5d9e73bc6147 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 20 Aug 2026 01:43:19 +0000 Subject: [PATCH 6/8] fix(native-image): register Conscrypt and JDK classes for JNI access in GraalVM --- .../nativeimage/GoogleJsonClientFeature.java | 28 +++++++++++++++---- .../api/gax/nativeimage/NativeImageUtils.java | 20 +++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 5cc84795873a..1ec0ed4b0ef9 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -32,6 +32,7 @@ import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForJni; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection; +import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForJni; import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection; import org.graalvm.nativeimage.hosted.Feature; @@ -68,7 +69,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { * provider)}. In GraalVM Native Image builds, these reflectively looked-up SPI classes are * stripped by static analysis unless explicitly registered for reflection, leading to {@code * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. Additionally, native - * JNI methods in {@code NativeCrypto} and native shared library resources must be registered for + * JNI methods and JDK classes accessed by Conscrypt's native C library must be registered for * GraalVM JNI linkage. */ private void loadConscrypt(BeforeAnalysisAccess access) { @@ -82,11 +83,26 @@ private void loadConscrypt(BeforeAnalysisAccess access) { // Register Conscrypt native JNI bridge classes and hierarchy registerClassHierarchyForReflection(access, "org.conscrypt.NativeCrypto"); registerClassHierarchyForReflection(access, "org.conscrypt.NativeCryptoJni"); - registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLBioSession"); - - registerClassForJni(access, "org.conscrypt.NativeCrypto"); - registerClassForJni(access, "org.conscrypt.NativeCryptoJni"); - registerClassForJni(access, "org.conscrypt.OpenSSLBioSession"); + registerClassHierarchyForReflection(access, "org.conscrypt.CryptoUpcalls"); + registerClassHierarchyForReflection(access, "org.conscrypt.NativeRef"); + registerClassHierarchyForReflection(access, "org.conscrypt.OpenSSLBIOInputStream"); + + registerClassHierarchyForJni(access, "org.conscrypt.NativeCrypto"); + registerClassHierarchyForJni(access, "org.conscrypt.NativeCryptoJni"); + registerClassHierarchyForJni(access, "org.conscrypt.CryptoUpcalls"); + registerClassHierarchyForJni(access, "org.conscrypt.NativeRef"); + registerClassHierarchyForJni(access, "org.conscrypt.OpenSSLBIOInputStream"); + + // Register standard JDK classes accessed via JNI by Conscrypt native C code + registerClassHierarchyForJni(access, "java.util.Calendar"); + registerClassHierarchyForJni(access, "java.io.InputStream"); + registerClassHierarchyForJni(access, "java.io.OutputStream"); + registerClassHierarchyForJni(access, "java.io.FileDescriptor"); + registerClassHierarchyForJni(access, "java.lang.Integer"); + registerClassHierarchyForJni(access, "java.lang.String"); + registerClassHierarchyForJni(access, "java.lang.Object"); + registerClassHierarchyForJni(access, "java.nio.Buffer"); + registerClassHierarchyForJni(access, "java.nio.ByteBuffer"); } } diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index d8a22565b311..eff832fd8608 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -112,6 +112,26 @@ public static void registerClassForJni(FeatureAccess access, String name) { } } + /** + * Registers the transitive class hierarchy of the provided {@code className} for JNI use. + * + *

The transitive class hierarchy contains the class itself and its transitive set of + * *non-private* nested subclasses. + */ + public static void registerClassHierarchyForJni(FeatureAccess access, String className) { + Class clazz = access.findClassByName(className); + if (clazz != null) { + registerClassForJni(access, className); + for (Class nestedClass : clazz.getDeclaredClasses()) { + if (!Modifier.isPrivate(nestedClass.getModifiers())) { + registerClassHierarchyForJni(access, nestedClass.getName()); + } + } + } else { + LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, className); + } + } + /** * Registers the transitive class hierarchy of the provided {@code className} for reflection. * From 4d23e070a1ce7b663cf15ee72b19270dfa0a5ac8 Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 20 Aug 2026 15:24:38 +0000 Subject: [PATCH 7/8] fix(native-image): register array types and key interfaces for Conscrypt JNI in GraalVM --- .../nativeimage/GoogleJsonClientFeature.java | 9 ++++++- .../api/gax/nativeimage/NativeImageUtils.java | 26 +++++++++++++------ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 1ec0ed4b0ef9..5e49e91c0d68 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -93,7 +93,12 @@ private void loadConscrypt(BeforeAnalysisAccess access) { registerClassHierarchyForJni(access, "org.conscrypt.NativeRef"); registerClassHierarchyForJni(access, "org.conscrypt.OpenSSLBIOInputStream"); - // Register standard JDK classes accessed via JNI by Conscrypt native C code + // Register array types and JDK classes accessed via JNI by Conscrypt native C code + registerClassForJni(Object[].class); + registerClassForJni(byte[].class); + registerClassForJni(byte[][].class); + registerClassForJni(int[].class); + registerClassHierarchyForJni(access, "java.util.Calendar"); registerClassHierarchyForJni(access, "java.io.InputStream"); registerClassHierarchyForJni(access, "java.io.OutputStream"); @@ -103,6 +108,8 @@ private void loadConscrypt(BeforeAnalysisAccess access) { registerClassHierarchyForJni(access, "java.lang.Object"); registerClassHierarchyForJni(access, "java.nio.Buffer"); registerClassHierarchyForJni(access, "java.nio.ByteBuffer"); + registerClassHierarchyForJni(access, "java.security.PrivateKey"); + registerClassHierarchyForJni(access, "java.security.Key"); } } diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java index eff832fd8608..70c277e3e681 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java @@ -86,27 +86,37 @@ public static void registerConstructorsForReflection(FeatureAccess access, Strin } } + /** Registers an entire class for reflection use. */ + public static void registerClassForReflection(Class clazz) { + RuntimeReflection.register(clazz); + RuntimeReflection.register(clazz.getDeclaredConstructors()); + RuntimeReflection.register(clazz.getDeclaredFields()); + RuntimeReflection.register(clazz.getDeclaredMethods()); + } + /** Registers an entire class for reflection use. */ public static void registerClassForReflection(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { - RuntimeReflection.register(clazz); - RuntimeReflection.register(clazz.getDeclaredConstructors()); - RuntimeReflection.register(clazz.getDeclaredFields()); - RuntimeReflection.register(clazz.getDeclaredMethods()); + registerClassForReflection(clazz); } else { LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); } } + /** Registers an entire class for JNI use. */ + public static void registerClassForJni(Class clazz) { + RuntimeJNIAccess.register(clazz); + RuntimeJNIAccess.register(clazz.getDeclaredConstructors()); + RuntimeJNIAccess.register(clazz.getDeclaredFields()); + RuntimeJNIAccess.register(clazz.getDeclaredMethods()); + } + /** Registers an entire class for JNI use. */ public static void registerClassForJni(FeatureAccess access, String name) { Class clazz = access.findClassByName(name); if (clazz != null) { - RuntimeJNIAccess.register(clazz); - RuntimeJNIAccess.register(clazz.getDeclaredConstructors()); - RuntimeJNIAccess.register(clazz.getDeclaredFields()); - RuntimeJNIAccess.register(clazz.getDeclaredMethods()); + registerClassForJni(clazz); } else { LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name); } From 71cb621a80e269341e16c4e8a371252671757d1c Mon Sep 17 00:00:00 2001 From: Lawrence Qiu Date: Thu, 20 Aug 2026 15:41:50 +0000 Subject: [PATCH 8/8] style: format GoogleJsonClientFeature with google-java-format --- .../api/gax/nativeimage/GoogleJsonClientFeature.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java index 5e49e91c0d68..ed2f8b4c0eea 100644 --- a/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java +++ b/sdk-platform-java/gax-java/gax/src/main/java/com/google/api/gax/nativeimage/GoogleJsonClientFeature.java @@ -60,17 +60,17 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { /** * Registers Conscrypt SSLContext and Security Provider SPI implementation classes (and their - * nested protocol subclasses) for GraalVM reflection, as well as Conscrypt native JNI classes - * and native C shared library resources when Conscrypt is present on the classpath. + * nested protocol subclasses) for GraalVM reflection, as well as Conscrypt native JNI classes and + * native C shared library resources when Conscrypt is present on the classpath. * *

When Conscrypt is configured as the security provider for HTTP/JSON transports, Java's JCA * framework reflectively instantiates provider implementation classes (e.g. {@code * OpenSSLContextImpl$TLSv13}) via String lookup in {@code SSLContext.getInstance("TLS", * provider)}. In GraalVM Native Image builds, these reflectively looked-up SPI classes are * stripped by static analysis unless explicitly registered for reflection, leading to {@code - * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. Additionally, native - * JNI methods and JDK classes accessed by Conscrypt's native C library must be registered for - * GraalVM JNI linkage. + * ClassNotFoundException} / {@code NoSuchAlgorithmException} at runtime. Additionally, native JNI + * methods and JDK classes accessed by Conscrypt's native C library must be registered for GraalVM + * JNI linkage. */ private void loadConscrypt(BeforeAnalysisAccess access) { Class conscryptClass = access.findClassByName("org.conscrypt.Conscrypt");