diff --git a/.github/workflows/downstream.yaml b/.github/workflows/downstream.yaml
index fa05f8029..b521e571d 100644
--- a/.github/workflows/downstream.yaml
+++ b/.github/workflows/downstream.yaml
@@ -134,9 +134,11 @@ jobs:
- workflows
steps:
- uses: actions/checkout@v2
- - uses: actions/setup-java@v1
+ - uses: actions/setup-java@v3
with:
+ distribution: zulu
java-version: ${{matrix.java}}
- run: java -version
+ - run: sudo apt-get update -y
- run: sudo apt-get install libxml2-utils
- run: .kokoro/downstream-client-library-check.sh ${{matrix.repo}}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 6f163dad2..1007b960e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,18 @@
# Changelog
+## [2.14.0](https://github.com/googleapis/gax-java/compare/v2.13.0...v2.14.0) (2022-04-01)
+
+
+### Features
+
+* relocate Netty Native Image configurations from java-core to gax ([#1638](https://github.com/googleapis/gax-java/issues/1638)) ([aafded4](https://github.com/googleapis/gax-java/commit/aafded4a0b779c68d0d5702b722672a0f86ccdd1))
+* relocate protobuf configurations from java-core to gax-java ([#1641](https://github.com/googleapis/gax-java/issues/1641)) ([01d395f](https://github.com/googleapis/gax-java/commit/01d395f486ccd7c364c03ccdfcfbf83b900192c3))
+
+
+### Bug Fixes
+
+* update the runtime dependency grpc-java xds to googleapis ([#1643](https://github.com/googleapis/gax-java/issues/1643)) ([b8d9e30](https://github.com/googleapis/gax-java/commit/b8d9e30c3e2209bcd4cc0f808dfdf0a0608aa466))
+
## [2.13.0](https://github.com/googleapis/gax-java/compare/v2.12.2...v2.13.0) (2022-03-25)
diff --git a/build.gradle b/build.gradle
index 2ff889577..02dde1018 100644
--- a/build.gradle
+++ b/build.gradle
@@ -13,7 +13,7 @@ plugins {
}
// TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync)
-project.version = "2.13.0" // {x-version-update:gax:current}
+project.version = "2.14.0" // {x-version-update:gax:current}
allprojects {
group = 'com.google.api'
@@ -39,7 +39,7 @@ ext {
'maven.io_grpc_grpc_protobuf': "io.grpc:grpc-protobuf:${libraries['version.io_grpc']}",
'maven.io_grpc_grpc_netty_shaded': "io.grpc:grpc-netty-shaded:${libraries['version.io_grpc']}",
'maven.io_grpc_grpc_alts': "io.grpc:grpc-alts:${libraries['version.io_grpc']}",
- 'maven.io_grpc_grpc_xds': "io.grpc:grpc-xds:${libraries['version.io_grpc']}",
+ 'maven.io_grpc_grpc_googleapis': "io.grpc:grpc-googleapis:${libraries['version.io_grpc']}",
'maven.com_google_protobuf': "com.google.protobuf:protobuf-java:${libraries['version.com_google_protobuf']}",
'maven.com_google_protobuf_java_util': "com.google.protobuf:protobuf-java-util:${libraries['version.com_google_protobuf']}")
}
@@ -322,4 +322,4 @@ sonarqube {
property 'sonar.organization', 'googleapis'
property 'sonar.host.url', 'https://sonarcloud.io'
}
-}
\ No newline at end of file
+}
diff --git a/dependencies.properties b/dependencies.properties
index d38f94ab2..7e432daa3 100644
--- a/dependencies.properties
+++ b/dependencies.properties
@@ -8,16 +8,16 @@
# Versions of oneself
# {x-version-update-start:gax:current}
-version.gax=2.13.0
+version.gax=2.14.0
# {x-version-update-end}
# {x-version-update-start:gax:current}
-version.gax_grpc=2.13.0
+version.gax_grpc=2.14.0
# {x-version-update-end}
# {x-version-update-start:gax:current}
-version.gax_bom=2.13.0
+version.gax_bom=2.14.0
# {x-version-update-end}
# {x-version-update-start:gax-httpjson:current}
-version.gax_httpjson=0.98.0
+version.gax_httpjson=0.99.0
# {x-version-update-end}
# Versions for dependencies which actual artifacts differ between Bazel and Gradle.
@@ -70,6 +70,8 @@ maven.com_google_http_client_google_http_client=com.google.http-client:google-ht
maven.com_google_http_client_google_http_client_gson=com.google.http-client:google-http-client-gson:1.41.5
maven.org_codehaus_mojo_animal_sniffer_annotations=org.codehaus.mojo:animal-sniffer-annotations:1.18
maven.javax_annotation_javax_annotation_api=javax.annotation:javax.annotation-api:1.3.2
+maven.org_graalvm_nativeimage_svm=org.graalvm.nativeimage:svm:22.0.0.2
+maven.org_graalvm_sdk=org.graalvm.sdk:graal-sdk:22.0.0.2
# Testing maven artifacts
maven.junit_junit=junit:junit:4.13.2
diff --git a/gax-bom/build.gradle b/gax-bom/build.gradle
index 49d8016aa..1dbcded2d 100644
--- a/gax-bom/build.gradle
+++ b/gax-bom/build.gradle
@@ -5,7 +5,7 @@ plugins {
archivesBaseName = 'gax-bom'
-project.version = "2.13.0" // {x-version-update:gax-bom:current}
+project.version = "2.14.0" // {x-version-update:gax-bom:current}
def mavenJavaDir = "$buildDir/publications/mavenJava"
def mavenJavaBomOutputFile = file(mavenJavaDir + '/pom-default.xml')
diff --git a/gax-bom/pom.xml b/gax-bom/pom.xml
index cb10a67db..e861f615c 100644
--- a/gax-bom/pom.xml
+++ b/gax-bom/pom.xml
@@ -3,7 +3,7 @@
4.0.0
com.google.api
gax-bom
- 2.13.0
+ 2.14.0
pom
GAX (Google Api eXtensions) for Java
Google Api eXtensions for Java
@@ -33,34 +33,34 @@
com.google.api
gax
- 2.13.0
+ 2.14.0
com.google.api
gax
- 2.13.0
+ 2.14.0
testlib
com.google.api
gax-grpc
- 2.13.0
+ 2.14.0
com.google.api
gax-grpc
- 2.13.0
+ 2.14.0
testlib
com.google.api
gax-httpjson
- 0.98.0
+ 0.99.0
com.google.api
gax-httpjson
- 0.98.0
+ 0.99.0
testlib
diff --git a/gax-grpc/BUILD.bazel b/gax-grpc/BUILD.bazel
index 3a177f4ab..5ae856c4f 100644
--- a/gax-grpc/BUILD.bazel
+++ b/gax-grpc/BUILD.bazel
@@ -31,6 +31,8 @@ _COMPILE_DEPS = [
"@io_netty_netty_tcnative_boringssl_static//jar",
"@javax_annotation_javax_annotation_api//jar",
"//gax:gax",
+ "@org_graalvm_nativeimage_svm//jar",
+ "@org_graalvm_sdk//jar"
]
_TEST_COMPILE_DEPS = [
diff --git a/gax-grpc/build.gradle b/gax-grpc/build.gradle
index 84d3464cd..a8d3df04b 100644
--- a/gax-grpc/build.gradle
+++ b/gax-grpc/build.gradle
@@ -1,7 +1,7 @@
archivesBaseName = 'gax-grpc'
// TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync)
-project.version = "2.13.0" // {x-version-update:gax-grpc:current}
+project.version = "2.14.0" // {x-version-update:gax-grpc:current}
dependencies {
api(project(':gax'),
@@ -20,9 +20,11 @@ dependencies {
libraries['maven.io_grpc_grpc_protobuf'],
libraries['maven.io_grpc_grpc_stub'])
- runtimeOnly libraries['maven.io_grpc_grpc_xds']
+ runtimeOnly libraries['maven.io_grpc_grpc_googleapis']
- compileOnly libraries['maven.com_google_auto_value_auto_value']
+ compileOnly(libraries['maven.com_google_auto_value_auto_value'],
+ libraries['maven.org_graalvm_sdk'],
+ libraries['maven.org_graalvm_nativeimage_svm'])
testImplementation( project(':gax').sourceSets.test.output,
libraries['maven.junit_junit'],
diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java
new file mode 100644
index 000000000..1e1167e09
--- /dev/null
+++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/GrpcNettyFeature.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.api.gax.grpc.nativeimage;
+
+import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassForReflection;
+import static com.google.api.gax.nativeimage.NativeImageUtils.registerClassHierarchyForReflection;
+import static com.google.api.gax.nativeimage.NativeImageUtils.registerForReflectiveInstantiation;
+import static com.google.api.gax.nativeimage.NativeImageUtils.registerForUnsafeFieldAccess;
+
+import com.oracle.svm.core.annotate.AutomaticFeature;
+import org.graalvm.nativeimage.hosted.Feature;
+
+/** Configures Native Image settings for the grpc-netty-shaded dependency. */
+@AutomaticFeature
+final class GrpcNettyFeature implements Feature {
+
+ private static final String GRPC_NETTY_SHADED_CLASS =
+ "io.grpc.netty.shaded.io.grpc.netty.NettyServer";
+
+ private static final String GOOGLE_AUTH_CLASS =
+ "com.google.auth.oauth2.ServiceAccountCredentials";
+
+ private static final String NETTY_SHADED_PACKAGE =
+ "io.grpc.netty.shaded.io.netty.util.internal.shaded.";
+
+ @Override
+ public void beforeAnalysis(BeforeAnalysisAccess access) {
+ loadGoogleAuthClasses(access);
+ loadGrpcNettyClasses(access);
+ loadMiscClasses(access);
+ }
+
+ private static void loadGoogleAuthClasses(BeforeAnalysisAccess access) {
+ // For com.google.auth:google-auth-library-oauth2-http
+ Class> authClass = access.findClassByName(GOOGLE_AUTH_CLASS);
+ if (authClass != null) {
+ registerClassHierarchyForReflection(access, GOOGLE_AUTH_CLASS);
+ registerClassHierarchyForReflection(
+ access, "com.google.auth.oauth2.ServiceAccountJwtAccessCredentials");
+ }
+ }
+
+ private static void loadGrpcNettyClasses(BeforeAnalysisAccess access) {
+ // For io.grpc:grpc-netty-shaded
+ Class> nettyShadedClass = access.findClassByName(GRPC_NETTY_SHADED_CLASS);
+ if (nettyShadedClass != null) {
+ // Misc. classes used by grpc-netty-shaded
+ registerForReflectiveInstantiation(
+ access, "io.grpc.netty.shaded.io.netty.channel.socket.nio.NioSocketChannel");
+ registerClassForReflection(
+ access, "io.grpc.netty.shaded.io.netty.util.internal.NativeLibraryUtil");
+ registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.util.ReferenceCountUtil");
+ registerClassForReflection(
+ access, "io.grpc.netty.shaded.io.netty.buffer.AbstractByteBufAllocator");
+
+ // Epoll Libraries
+ registerClassForReflection(access, "io.grpc.netty.shaded.io.netty.channel.epoll.Epoll");
+ registerClassForReflection(
+ access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollChannelOption");
+ registerClassForReflection(
+ access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollEventLoopGroup");
+ registerForReflectiveInstantiation(
+ access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollServerSocketChannel");
+ registerForReflectiveInstantiation(
+ access, "io.grpc.netty.shaded.io.netty.channel.epoll.EpollSocketChannel");
+
+ // Unsafe field accesses
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerIndexField",
+ "producerIndex");
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueProducerLimitField",
+ "producerLimit");
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.MpscArrayQueueConsumerIndexField",
+ "consumerIndex");
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
+ "producerIndex");
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
+ "producerLimit");
+ registerForUnsafeFieldAccess(
+ access,
+ NETTY_SHADED_PACKAGE + "org.jctools.queues.BaseMpscLinkedArrayQueueConsumerFields",
+ "consumerIndex");
+ }
+ }
+
+ /** Miscellaneous classes that need to be registered coming from various JARs. */
+ private static void loadMiscClasses(BeforeAnalysisAccess access) {
+ registerClassHierarchyForReflection(access, "com.google.protobuf.DescriptorProtos");
+ registerClassForReflection(access, "com.google.api.FieldBehavior");
+
+ registerForUnsafeFieldAccess(access, "javax.net.ssl.SSLContext", "contextSpi");
+ registerClassForReflection(access, "java.lang.management.ManagementFactory");
+ registerClassForReflection(access, "java.lang.management.RuntimeMXBean");
+ }
+}
diff --git a/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/ProtobufMessageFeature.java b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/ProtobufMessageFeature.java
new file mode 100644
index 000000000..0b65e8c7f
--- /dev/null
+++ b/gax-grpc/src/main/java/com/google/api/gax/grpc/nativeimage/ProtobufMessageFeature.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.api.gax.grpc.nativeimage;
+
+import com.google.api.gax.nativeimage.NativeImageUtils;
+import com.oracle.svm.core.annotate.AutomaticFeature;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.List;
+import org.graalvm.nativeimage.hosted.Feature;
+import org.graalvm.nativeimage.hosted.RuntimeReflection;
+
+/**
+ * A optional feature which registers reflective usages of the GRPC Protobuf libraries.
+ *
+ *
This feature is only needed if you need to access proto objects reflectively (such as
+ * printing/logging proto objects).
+ */
+@AutomaticFeature
+final class ProtobufMessageFeature implements Feature {
+
+ // Proto classes to check on the classpath.
+ private static final String PROTO_MESSAGE_CLASS = "com.google.protobuf.GeneratedMessageV3";
+ private static final String PROTO_ENUM_CLASS = "com.google.protobuf.ProtocolMessageEnum";
+ private static final String ENUM_VAL_DESCRIPTOR_CLASS =
+ "com.google.protobuf.Descriptors$EnumValueDescriptor";
+
+ // Prefixes of methods accessed reflectively by
+ // com.google.protobuf.GeneratedMessageV3$ReflectionInvoker
+ private static final List METHOD_ACCESSOR_PREFIXES =
+ Arrays.asList("get", "set", "has", "add", "clear", "newBuilder");
+
+ @Override
+ public void beforeAnalysis(BeforeAnalysisAccess access) {
+ Class> protoMessageClass = access.findClassByName(PROTO_MESSAGE_CLASS);
+ if (protoMessageClass != null) {
+ Method internalAccessorMethod =
+ NativeImageUtils.getMethodOrFail(protoMessageClass, "internalGetFieldAccessorTable");
+
+ // Finds every class whose `internalGetFieldAccessorTable()` is reached and registers it.
+ // `internalGetFieldAccessorTable()` is used downstream to access the class reflectively.
+ access.registerMethodOverrideReachabilityHandler(
+ (duringAccess, method) -> {
+ registerFieldAccessors(method.getDeclaringClass());
+ registerFieldAccessors(getBuilderClass(method.getDeclaringClass()));
+ },
+ internalAccessorMethod);
+ }
+
+ Class> protoEnumClass = access.findClassByName(PROTO_ENUM_CLASS);
+ if (protoEnumClass != null) {
+ // Finds every reachable proto enum class and registers specific methods for reflection.
+ access.registerSubtypeReachabilityHandler(
+ (duringAccess, subtypeClass) -> {
+ if (!PROTO_ENUM_CLASS.equals(subtypeClass.getName())) {
+ Method method =
+ NativeImageUtils.getMethodOrFail(
+ subtypeClass,
+ "valueOf",
+ duringAccess.findClassByName(ENUM_VAL_DESCRIPTOR_CLASS));
+ RuntimeReflection.register(method);
+
+ method = NativeImageUtils.getMethodOrFail(subtypeClass, "getValueDescriptor");
+ RuntimeReflection.register(method);
+ }
+ },
+ protoEnumClass);
+ }
+ }
+
+ /** Given a proto class, registers the public accessor methods for the provided proto class. */
+ private static void registerFieldAccessors(Class> protoClass) {
+ for (Method method : protoClass.getMethods()) {
+ boolean hasAccessorPrefix =
+ METHOD_ACCESSOR_PREFIXES.stream().anyMatch(prefix -> method.getName().startsWith(prefix));
+ if (hasAccessorPrefix) {
+ RuntimeReflection.register(method);
+ }
+ }
+ }
+
+ /** Given a proto class, returns the Builder nested class. */
+ private static Class> getBuilderClass(Class> protoClass) {
+ for (Class> clazz : protoClass.getClasses()) {
+ if (clazz.getName().endsWith("Builder")) {
+ return clazz;
+ }
+ }
+ return null;
+ }
+}
diff --git a/gax-httpjson/build.gradle b/gax-httpjson/build.gradle
index c80ebfc73..b52dee58f 100644
--- a/gax-httpjson/build.gradle
+++ b/gax-httpjson/build.gradle
@@ -1,7 +1,7 @@
archivesBaseName = 'gax-httpjson'
// TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync)
-project.version = "0.98.0" // {x-version-update:gax-httpjson:current}
+project.version = "0.99.0" // {x-version-update:gax-httpjson:current}
dependencies {
api(project(':gax'),
diff --git a/gax/BUILD.bazel b/gax/BUILD.bazel
index b9dd9a067..f35f3fc99 100644
--- a/gax/BUILD.bazel
+++ b/gax/BUILD.bazel
@@ -24,6 +24,8 @@ _COMPILE_DEPS = [
"@com_google_code_gson_gson//jar",
"@com_google_guava_failureaccess//jar",
"@javax_annotation_javax_annotation_api//jar",
+ "@org_graalvm_nativeimage_svm//jar",
+ "@org_graalvm_sdk//jar"
]
_TEST_COMPILE_DEPS = [
diff --git a/gax/build.gradle b/gax/build.gradle
index fc6fbb545..cdd5d63bd 100644
--- a/gax/build.gradle
+++ b/gax/build.gradle
@@ -1,7 +1,7 @@
archivesBaseName = "gax"
// TODO: Populate this from dependencies.properties version property (for proper Gradle-Bazel sync)
-project.version = "2.13.0" // {x-version-update:gax:current}
+project.version = "2.14.0" // {x-version-update:gax:current}
dependencies {
api(libraries['maven.com_google_api_api_common'],
@@ -13,7 +13,9 @@ dependencies {
libraries['maven.com_google_guava_guava'],
libraries['maven.io_opencensus_opencensus_api'])
- compileOnly libraries['maven.com_google_auto_value_auto_value']
+ compileOnly(libraries['maven.com_google_auto_value_auto_value'],
+ libraries['maven.org_graalvm_sdk'],
+ libraries['maven.org_graalvm_nativeimage_svm'])
testImplementation(libraries['maven.junit_junit'],
libraries['maven.org_mockito_mockito_core'],
diff --git a/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java
new file mode 100644
index 000000000..603d26e3c
--- /dev/null
+++ b/gax/src/main/java/com/google/api/gax/nativeimage/NativeImageUtils.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2022 Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.google.api.gax.nativeimage;
+
+import com.google.api.core.InternalApi;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.graalvm.nativeimage.hosted.Feature.FeatureAccess;
+import org.graalvm.nativeimage.hosted.RuntimeReflection;
+
+/** Internal class offering helper methods for registering methods/classes for reflection. */
+@InternalApi
+public class NativeImageUtils {
+
+ private static final Logger LOGGER = Logger.getLogger(NativeImageUtils.class.getName());
+ private static final String CLASS_REFLECTION_ERROR_MESSAGE =
+ "Failed to find {0} on the classpath for reflection.";
+
+ private NativeImageUtils() {}
+
+ /** Returns the method of a class or fails if it is not present. */
+ public static Method getMethodOrFail(Class> clazz, String methodName, Class>... params) {
+ try {
+ return clazz.getDeclaredMethod(methodName, params);
+ } catch (NoSuchMethodException e) {
+ throw new IllegalStateException(
+ String.format("Failed to find method %s for class %s", methodName, clazz.getName()), e);
+ }
+ }
+
+ /** Registers a class for reflective construction via its default constructor. */
+ public static void registerForReflectiveInstantiation(FeatureAccess access, String className) {
+ Class> clazz = access.findClassByName(className);
+ if (clazz != null) {
+ RuntimeReflection.register(clazz);
+ RuntimeReflection.registerForReflectiveInstantiation(clazz);
+ } else {
+ LOGGER.log(
+ Level.WARNING,
+ "Failed to find {0} on the classpath for reflective instantiation.",
+ className);
+ }
+ }
+
+ /** Registers all constructors of a class for reflection. */
+ public static void registerConstructorsForReflection(FeatureAccess access, String name) {
+ Class> clazz = access.findClassByName(name);
+ if (clazz != null) {
+ RuntimeReflection.register(clazz);
+ RuntimeReflection.register(clazz.getDeclaredConstructors());
+ } else {
+ LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name);
+ }
+ }
+
+ /** 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());
+ } else {
+ LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, name);
+ }
+ }
+
+ /**
+ * Registers the transitive class hierarchy of the provided {@code className} for reflection.
+ *
+ * The transitive class hierarchy contains the class itself and its transitive set of
+ * *non-private* nested subclasses.
+ */
+ public static void registerClassHierarchyForReflection(FeatureAccess access, String className) {
+ Class> clazz = access.findClassByName(className);
+ if (clazz != null) {
+ registerClassForReflection(access, className);
+ for (Class> nestedClass : clazz.getDeclaredClasses()) {
+ if (!Modifier.isPrivate(nestedClass.getModifiers())) {
+ registerClassHierarchyForReflection(access, nestedClass.getName());
+ }
+ }
+ } else {
+ LOGGER.log(Level.WARNING, CLASS_REFLECTION_ERROR_MESSAGE, className);
+ }
+ }
+
+ /** Registers a class for unsafe reflective field access. */
+ public static void registerForUnsafeFieldAccess(
+ FeatureAccess access, String className, String... fields) {
+ Class> clazz = access.findClassByName(className);
+ if (clazz != null) {
+ RuntimeReflection.register(clazz);
+ for (String fieldName : fields) {
+ try {
+ RuntimeReflection.register(clazz.getDeclaredField(fieldName));
+ } catch (NoSuchFieldException ex) {
+ LOGGER.warning("Failed to register field " + fieldName + " for class " + className);
+ LOGGER.warning(ex.getMessage());
+ }
+ }
+ } else {
+ LOGGER.log(
+ Level.WARNING,
+ "Failed to find {0} on the classpath for unsafe fields access registration.",
+ className);
+ }
+ }
+}
diff --git a/versions.txt b/versions.txt
index 53e849d63..41301da08 100644
--- a/versions.txt
+++ b/versions.txt
@@ -1,7 +1,7 @@
# Format:
# module:released-version:current-version
-gax:2.13.0:2.13.0
-gax-bom:2.13.0:2.13.0
-gax-grpc:2.13.0:2.13.0
-gax-httpjson:0.98.0:0.98.0
+gax:2.14.0:2.14.0
+gax-bom:2.14.0:2.14.0
+gax-grpc:2.14.0:2.14.0
+gax-httpjson:0.99.0:0.99.0