Skip to content

Native compilation with GraalVM #23642

@ValTheBoss

Description

@ValTheBoss

There is an issue when using native compilation with GraalVM. I'm trying to use the Admin SDK API Client Library for directory operations.

Environment details

  • Admin SDK API Client Library, version directory_v1-rev20240924-2.0.0
  • Java Temurin 21
  • Native compilation of a Spring Boot 3.3.4 app using by default at this time :
    • paketo-buildpacks/ca-certificates 3.8.6
    • paketo-buildpacks/bellsoft-liberica 10.9.0
    • paketo-buildpacks/syft 2.1.0
    • paketo-buildpacks/executable-jar 6.11.3
    • paketo-buildpacks/spring-boot 5.31.2
    • paketo-buildpacks/native-image 5.14.4

Steps to reproduce

Fresh Spring Boot 3.3.4 project.

Maven configuration

<dependency>
  <groupId>com.google.apis</groupId>
  <artifactId>google-api-services-admin-directory</artifactId>
  <version>directory_v1-rev20240924-2.0.0</version>
</dependency>
...
<plugin>
  <groupId>org.graalvm.buildtools</groupId>
  <artifactId>native-maven-plugin</artifactId>
</plugin>

Build Directory service

private Directory buildDirectoryService(@Nonnull final String gcpKey, @Nonnull final String serviceAccountUser) throws IOException, GeneralSecurityException {
    final ServiceAccountCredentials sourceCredentials =
        ServiceAccountCredentials.fromStream(...)
        .toBuilder()
        .setServiceAccountUser(serviceAccountUser)
        .setScopes(ImmutableSet.of(
            DirectoryScopes.ADMIN_DIRECTORY_GROUP_READONLY,
            DirectoryScopes.ADMIN_DIRECTORY_USER_READONLY
        ))
        .build();

    return new Directory.Builder(Utils.getDefaultTransport(), Utils.getDefaultJsonFactory(), new HttpCredentialsAdapter(sourceCredentials))
        .setApplicationName("MY_APP")
        .build();
  }

Add reflection hints for ErrorInfo.class

@Configuration
@ImportRuntimeHints(NativeImageHints.class)
class NativeImageHints implements RuntimeHintsRegistrar {
  @Override
  public void registerHints(RuntimeHints hints, ClassLoader classLoader) {
    hints.reflection().registerType(ErrorInfo.class, (type) -> type.withConstructor(Collections.emptyList(), ExecutableMode.INVOKE));
  }
}

Directory api call

final Users batch = directory
            .users()
            .list()
            .setMaxResults(100)
            .setDomain("my-domain.com")
            .execute();

Build and run image

mvn clean spring-boot:build-image -e --no-transfer-progress -P native -D skipTests=true
docker run -p 8080:8080 my-app:0.0.1-SNAPSHOT

Result of directory execute()

2024-10-14T12:44:13.891Z  INFO 1 --- [my-app] [nio-8080-exec-1] c.google.api.client.http.HttpTransport   : {
  "error": {
    "code": 400,
    "message": "Bad Request",
    "errors": [
      {
        "message": "Bad Request",
        "domain": "global",
        "reason": "badRequest"
      }
    ]
  }
}

Reason
If I launch the app in DEBUG logging mode, I can see that the URL for the API query is not properly prepared :

curl -v --compressed 
-H 'Accept-Encoding: gzip' 
-H 'Authorization: <Not Logged>' 
-H 'User-Agent: MY_APP Google-API-Java-Client/2.7.0 Google-HTTP-Java-Client/1.45.0 (gzip)' 
-H 'x-goog-api-client: gl-java/21.0.4-graalvm gdcl/2.7.0 linux/6.8.0' -- 'https://admin.googleapis.com/admin/directory/v1/users'

instead of

curl -v --compressed 
-H 'Accept-Encoding: gzip' 
-H 'Authorization: <Not Logged>' 
-H 'User-Agent: MY_APP Google-API-Java-Client/2.7.0 Google-HTTP-Java-Client/1.45.0 (gzip)' 
-H 'x-goog-api-client: gl-java/21.0.4-graalvm gdcl/2.7.0 linux/6.8.0' -- 'https://admin.googleapis.com/admin/directory/v1/users?domain=my-domain.com&maxResults=100'

Metadata

Metadata

Assignees

No one assigned

    Labels

    priority: p3Desirable enhancement or fix. May not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions