Skip to content

Embed native image config#25883

Open
david-streamlio wants to merge 2 commits into
apache:masterfrom
david-streamlio:embed-native-image-config
Open

Embed native image config#25883
david-streamlio wants to merge 2 commits into
apache:masterfrom
david-streamlio:embed-native-image-config

Conversation

@david-streamlio
Copy link
Copy Markdown
Contributor

Main Issue: quarkusio/quarkus#48776

Motivation

Applications using pulsar-client-original in GraalVM native-image builds currently fail unless the consuming framework (Quarkus, Micronaut, Spring Native, etc.) provides its own reflection and class initialization metadata for Pulsar client internals. This forces every framework to independently reverse-engineer and maintain configuration that tracks Pulsar's internal class layout — and when it drifts, native builds break silently.

A concrete example: Quarkus's Pulsar extension registered org.apache.pulsar.client.util.WithSNISslEngineFactory for runtime initialization, but that class was removed in Pulsar 4.x. Because the configuration lived downstream instead of in the client itself, the breakage went unnoticed for a year (quarkusio/quarkus#48776).

Embedding the configuration directly in pulsar-client-original following
the GraalVM embedded configuration convention means the native-image tool picks it up automatically from the classpath, keeping the config in sync with the code that owns the classes.

Modifications

Added three GraalVM native-image configuration files under
pulsar-client/src/main/resources/META-INF/native-image/org.apache.pulsar/pulsar-client-original/:

  • reflect-config.json — Registers 20 classes for reflective access:
    the three ConfigurationData classes (deserialized by Jackson), all six
    Authentication implementations (instantiated by name via
    AuthenticationUtil.create()), the OAuth2 protocol model classes, schema
    internals (ProtoBufParsingInfo, ProtobufNativeSchemaData, KeyValue),
    DataURLStreamHandler, and SecretsSerializer.

  • native-image.properties — Marks eight classes for runtime
    initialization that would otherwise fail during native-image build due to
    eager static initialization of Netty allocators, thread pools, or HTTP
    clients: PulsarByteBufAllocator, Commands, Backoff, TokenClient,
    GenericProtobufNativeSchema, ConnectionPool,
    ControlledClusterFailover, and HttpClient.

  • resource-config.json — Includes the async-http-client default
    properties files that are loaded via classloader at runtime.

Added NativeImageConfigTest that validates:

  • All classes referenced in reflect-config.json exist on the classpath
  • All classes referenced in native-image.properties exist on the classpath
  • All Authentication implementations shipped with the client are registered
  • Both JSON config files are well-formed

This test catches configuration drift early — if a class is renamed, removed, or a new Authentication plugin is added without updating the config, the test fails with a descriptive message.

Note: the shaded pulsar-client JAR intentionally strips
META-INF/native-image/** in its shade plugin filters, which is correct since shading relocates packages and invalidates the original class names. Users building native images should depend on pulsar-client-original.

Verifying this change

This change added tests and can be verified as follows:

  • Added NativeImageConfigTest that validates all 20 reflection entries and
    8 runtime-initialized classes resolve on the classpath, and that all
    Authentication implementations are registered.
  • Every class in the configuration was verified against the Pulsar 4.2.1
    source tree.
  • The equivalent configuration (derived from Quarkus's
    SmallRyeReactiveMessagingPulsarProcessor) was validated by successfully
    compiling six native-image integration tests in the Quarkus
    integration-tests/reactive-messaging-pulsar module against Pulsar 4.2.1.

Does this pull request potentially affect one of the following parts:

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

Documentation

  • doc-not-needed

Add META-INF/native-image configuration files (reflect-config.json,
resource-config.json, native-image.properties) so that GraalVM's
native-image tool can build applications using the Pulsar client
without framework-specific configuration.

Includes a test (NativeImageConfigTest) that validates all referenced
classes exist on the classpath and all Authentication implementations
are registered, so the config does not drift silently as the codebase
evolves.

This eliminates the need for downstream frameworks (Quarkus, Micronaut,
Spring Native) to independently maintain reflection and class
initialization metadata for Pulsar client internals.
@david-streamlio david-streamlio requested a review from lhotari May 27, 2026 21:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant