Skip to content
This repository has been archived by the owner on Dec 3, 2023. It is now read-only.

Commit

Permalink
feat(java): Add native-image support classes to java-core module (#637)
Browse files Browse the repository at this point in the history
Introduce native-image support in a new module native-image-support.

Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
  • Loading branch information
dzou and gcf-owl-bot[bot] committed Jan 18, 2022
1 parent 32e64fd commit 154bc18
Show file tree
Hide file tree
Showing 17 changed files with 1,097 additions and 1 deletion.
5 changes: 5 additions & 0 deletions google-cloud-core-bom/pom.xml
Expand Up @@ -75,6 +75,11 @@
<artifactId>google-cloud-core-http</artifactId>
<version>2.3.6-SNAPSHOT</version><!-- {x-version-update:google-cloud-core:current} -->
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>native-image-support</artifactId>
<version>0.11.0-SNAPSHOT</version><!-- {x-version-update:native-image-support:current} -->
</dependency>
</dependencies>
</dependencyManagement>

Expand Down
47 changes: 47 additions & 0 deletions native-image-support/pom.xml
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<name>Google Cloud Native Image Support</name>
<groupId>com.google.cloud</groupId>
<artifactId>native-image-support</artifactId>
<version>0.11.0-SNAPSHOT</version><!-- {x-version-update:native-image-support:current} -->
<packaging>jar</packaging>

<parent>
<artifactId>google-cloud-core-parent</artifactId>
<groupId>com.google.cloud</groupId>
<version>2.3.6-SNAPSHOT</version> <!-- {x-version-update:google-cloud-core:current} -->
</parent>

<description>
Core gRPC module for the google-cloud.
</description>

<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>

<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.graalvm.nativeimage</groupId>
<artifactId>svm</artifactId>
<scope>provided</scope>
</dependency>

<dependency>
<groupId>org.graalvm.sdk</groupId>
<artifactId>graal-sdk</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,99 @@
/*
* Copyright 2022 Google LLC
*
* Licensed 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
*
* https://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 com.google.cloud.nativeimage.features;

import static com.google.cloud.nativeimage.features.NativeImageUtils.registerClassForReflection;

import com.oracle.svm.core.annotate.AutomaticFeature;
import com.oracle.svm.core.configure.ResourcesRegistry;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;

/** Configures Native Image settings for the Google JSON Client. */
@AutomaticFeature
final class GoogleJsonClientFeature implements Feature {

private static final String GOOGLE_API_CLIENT_CLASS =
"com.google.api.client.googleapis.services.json.AbstractGoogleJsonClient";

private static final String GOOGLE_API_CLIENT_REQUEST_CLASS =
"com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest";

private static final String GENERIC_JSON_CLASS = "com.google.api.client.json.GenericJson";

@Override
public void beforeAnalysis(BeforeAnalysisAccess access) {
loadApiClient(access);
loadHttpClient(access);
loadMiscClasses(access);
}

private void loadApiClient(BeforeAnalysisAccess access) {
// For com.google.api-client:google-api-client
Class<?> googleApiClientClass = access.findClassByName(GOOGLE_API_CLIENT_CLASS);

if (googleApiClientClass != null) {
// All reachable instances of the AbstractGoogleJsonClient must be registered.
access.registerSubtypeReachabilityHandler(
(duringAccess, subtype) -> registerClassForReflection(access, subtype.getName()),
googleApiClientClass);

// All reachable instances of the AbstractGoogleJsonClientRequest must be registered.
access.registerSubtypeReachabilityHandler(
(duringAccess, subtype) -> registerClassForReflection(access, subtype.getName()),
access.findClassByName(GOOGLE_API_CLIENT_REQUEST_CLASS));

// Resources
ResourcesRegistry resourcesRegistry = ImageSingletons.lookup(ResourcesRegistry.class);
resourcesRegistry.addResources(
"\\Qcom/google/api/client/googleapis/google-api-client.properties\\E");
resourcesRegistry.addResources("\\Qcom/google/api/client/googleapis/google.p12\\E");
resourcesRegistry.addResources(
"\\Qcom/google/api/client/http/google-http-client.properties\\E");
}
}

private void loadHttpClient(BeforeAnalysisAccess access) {
// For com.google.http-client:google-http-client
Class<?> genericJsonClass = access.findClassByName(GENERIC_JSON_CLASS);

if (genericJsonClass != null) {
// All reachable instances of GenericJson must be registered.
access.registerSubtypeReachabilityHandler(
(duringAccess, subtype) -> registerClassForReflection(access, subtype.getName()),
genericJsonClass);

registerClassForReflection(access, "com.google.api.client.util.GenericData");
registerClassForReflection(access, "com.google.api.client.json.webtoken.JsonWebToken");
registerClassForReflection(access, "com.google.api.client.json.webtoken.JsonWebToken$Header");
registerClassForReflection(
access, "com.google.api.client.json.webtoken.JsonWebToken$Payload");
registerClassForReflection(
access, "com.google.api.client.json.webtoken.JsonWebSignature$Header");
registerClassForReflection(access, "com.google.api.client.json.webtoken.JsonWebSignature");
registerClassForReflection(access, "com.google.api.client.http.UrlEncodedContent");
registerClassForReflection(access, "com.google.api.client.http.GenericUrl");
registerClassForReflection(access, "com.google.api.client.http.HttpRequest");
registerClassForReflection(access, "com.google.api.client.http.HttpHeaders");
}
}

private void loadMiscClasses(BeforeAnalysisAccess access) {
registerClassForReflection(access, "com.google.common.util.concurrent.AbstractFuture");
registerClassForReflection(access, "com.google.common.util.concurrent.AbstractFuture$Waiter");
}
}
@@ -0,0 +1,122 @@
/*
* Copyright 2022 Google LLC
*
* Licensed 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
*
* https://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 com.google.cloud.nativeimage.features;

import static com.google.cloud.nativeimage.features.NativeImageUtils.registerClassForReflection;
import static com.google.cloud.nativeimage.features.NativeImageUtils.registerClassHierarchyForReflection;
import static com.google.cloud.nativeimage.features.NativeImageUtils.registerForReflectiveInstantiation;
import static com.google.cloud.nativeimage.features.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";

@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, "com.google.auth.oauth2.ServiceAccountCredentials");
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,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "org.jctools.queues.MpscArrayQueueProducerIndexField",
"producerIndex");
registerForUnsafeFieldAccess(
access,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "org.jctools.queues.MpscArrayQueueProducerLimitField",
"producerLimit");
registerForUnsafeFieldAccess(
access,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "org.jctools.queues.MpscArrayQueueConsumerIndexField",
"consumerIndex");
registerForUnsafeFieldAccess(
access,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "org.jctools.queues.BaseMpscLinkedArrayQueueProducerFields",
"producerIndex");
registerForUnsafeFieldAccess(
access,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "org.jctools.queues.BaseMpscLinkedArrayQueueColdProducerFields",
"producerLimit");
registerForUnsafeFieldAccess(
access,
"io.grpc.netty.shaded.io.netty.util.internal.shaded."
+ "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");
}
}

0 comments on commit 154bc18

Please sign in to comment.