Skip to content

CAMEL-26343: camel-aws - set the AWS SDK HTTP client explicitly instead of the classpath lookup - #28563

Merged
davsclaus merged 4 commits into
apache:mainfrom
oscerd:fix/CAMEL-26343
Oct 29, 2026
Merged

davsclaus merged 4 commits into
apache:mainfrom
oscerd:fix/CAMEL-26343

Conversation

@oscerd

@oscerd oscerd commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Jira: https://issues.apache.org/jira/browse/CAMEL-26343

Problem

Since CAMEL-23866 (4.22.0), AwsClientBuilderUtil sets an HTTP client on the AWS SDK client builder only when a proxy or trustAllCertificates is configured. Otherwise the AWS SDK looks the HTTP client up with ServiceLoader. ClasspathSdkHttpServiceProvider loads every registered SdkHttpService before ranking them, so one registration that cannot be loaded fails the whole lookup with ServiceConfigurationError, even though the Apache5SdkHttpService that Camel ships is there.

This breaks the AWS connectors of Camel Kafka Connector 4.22.0 on confluentinc/cp-kafka-connect:8.2.4 (apache/camel-kafka-connector#1849). The worker classpath has its own AWS SDK with the classic apache-client. The plugin class loader also returns the worker's META-INF/services files, so ApacheSdkHttpService, which the plugin no longer ships, is loaded from the worker: software.amazon.awssdk.http.apache.ApacheSdkHttpService not a subtype.

Change

  • When no proxy is configured, AwsClientBuilderUtil.buildClient sets Apache5HttpClient.builder() and buildAsyncClient sets NettyNioAsyncHttpClient.builder(). These are the implementations the SDK lookup selects from Camel's dependencies. The SDK builds them with the same service defaults (buildWithDefaults) and closes them with the client, as it does for the client it looks up, so a working setup behaves as before.
  • When the AWS SDK setting software.amazon.awssdk.http.service.impl (or software.amazon.awssdk.http.async.service.impl) names an implementation, Camel still leaves the choice to the SDK.
  • The proxy and trustAllCertificates paths are unchanged.
  • Upgrade-guide notes in camel-4x-upgrade-guide-4_24.adoc, and in the 4.22.3 section of camel-4x-upgrade-guide-4_22.adoc for the backport, for users who replaced apache5-client / netty-nio-client with another HTTP client. Both notes are scoped to the AWS SDK clients the components create for their endpoints (the clients built through AwsClientBuilderUtil): SDK clients that other camel-aws code builds directly, such as the Secrets Manager and Parameter Store properties functions or the KCL consumer, still use the SDK lookup. The notes stay on main; the backport takes only the code and test changes.

Tests

AwsClientBuilderUtilTest registers, in its test resources, a class that is not an HTTP client as an SdkHttpService and an SdkAsyncHttpService. This reproduces the Kafka Connect failure in a plain unit test:

  • sdkLookupFailsOnTheForeignRegistration: a plain SDK builder fails with ServiceConfigurationError ... not a subtype, so the setup reproduces the bug.
  • buildClientDoesNotUseTheSdkLookup / buildAsyncClientDoesNotUseTheSdkLookup: clients built through AwsClientBuilderUtil are created. Without the fix, both fail with the reported error.
  • sdkSettingLeavesTheChoiceToTheSdk / sdkAsyncSettingLeavesTheChoiceToTheSdk: with the SDK system property for synchronous (or asynchronous) clients set, the SDK's own choice applies.

The tests build STS clients, so software.amazon.awssdk:sts is added as a test dependency of camel-aws-common, which had no AWS service module on its test classpath.

Validation:

  • camel-aws-common: all 8 tests pass (5 in AwsClientBuilderUtilTest), also after the rebase on the current main. On main without the fix, the two client tests fail with the reported error.
  • mvn verify -f components/camel-aws/pom.xml on the first revision: the unit tests of all 35 camel-aws modules pass (3476 tests, 0 failures, 0 errors, 180 skipped).

Backport

Draft backport to camel-4.22.x (AWS SDK 2.50.2, identical AwsClientBuilderUtil): #28564. It carries the code and test commit; the async setting test (sdkAsyncSettingLeavesTheChoiceToTheSdk), added here later, is still to be ported to it. The 4.22.3 upgrade note stays in this PR, on main. All 35 camel-aws modules' unit tests also pass on that branch.

Claude Code on behalf of Andrea Cosentino

🤖 Generated with Claude Code

@github-actions

Copy link
Copy Markdown
Contributor

🌟 Thank you for your contribution to the Apache Camel project! 🌟
🤖 CI automation will test this PR automatically.

🐫 Apache Camel Committers, please review the following items:

  • First-time contributors require MANUAL approval for the GitHub Actions to run
  • You can use the command /component-test (camel-)component-name1 (camel-)component-name2.. to request a test from the test bot although they are normally detected and executed by CI.
  • You can label PRs using skip-tests and test-dependents to fine-tune the checks executed by this PR.
  • Build and test logs are available in the summary page. Only Apache Camel committers have access to the summary.

⚠️ Be careful when sharing logs. Review their contents before sharing them publicly.

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is well-targeted: explicitly setting Apache5HttpClient/NettyNioAsyncHttpClient instead of triggering the SDK's ServiceLoader scan avoids the classpath pollution problem at its root. The META-INF/services fake-registration test setup is a clean way to reproduce the Kafka Connect failure as a plain unit test. useDefaultHttpClient's Optional.isEmpty() logic is correct — SdkSystemSetting.getStringValue() returns Optional<String> with no default for SYNC_HTTP_SERVICE_IMPL/ASYNC_HTTP_SERVICE_IMPL, so isEmpty() correctly identifies "setting not configured."

One gap: the async escape hatch (ASYNC_HTTP_SERVICE_IMPL) has no test exercising the override path (see inline).

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-aws/camel-aws-common
  • docs

ℹ️ Dependent modules were not tested because the total number of affected modules exceeded the threshold (50). Use the test-dependents label to force testing all dependents.


🔬 Scalpel shadow comparison — Scalpel: 42 of 708 tested, 2 compile-only — current: 42 all tested

Maveniverse Scalpel detected 42 affected modules (current approach: 42).

Skip-tests mode would test 42 modules (2 direct + 0 downstream), skip tests for 2 (generated code, meta-modules)

Modules Scalpel would test (42)
  • camel-aws-bedrock ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws-cloudtrail ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws-common ← components/camel-aws/camel-aws-common/src/main/java/org/apache/camel/component/aws/common/AwsClientBuilderUtil.java, components/camel-aws/camel-aws-common/src/test/java/org/apache/camel/component/aws/common/AwsClientBuilderUtilTest.java, components/camel-aws/camel-aws-common/src/test/resources/META-INF/services/software.amazon.awssdk.http.SdkHttpService, components/camel-aws/camel-aws-common/src/test/resources/META-INF/services/software.amazon.awssdk.http.async.SdkAsyncHttpService, own pom components/camel-aws/camel-aws-common/pom.xml changed
  • camel-aws-config ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws-parameter-store ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws-secrets-manager ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws-security-hub ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-athena ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-comprehend ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-cw ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-ddb ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-ec2 ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-ecs ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-eks ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-eventbridge ← depends on affected reactor module org.apache.camel:camel-aws2-sqs
  • camel-aws2-iam ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-kinesis ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-kms ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-lambda ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-mq ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-msk ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-polly ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-redshift ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-rekognition ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-s3 ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-s3-vectors ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-ses ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-sns ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-sqs ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-step-functions ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-sts ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-textract ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-timestream ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-transcribe ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-aws2-translate ← depends on affected reactor module org.apache.camel:camel-aws-common
  • camel-jbang-mcp ← depends on affected reactor module org.apache.camel:camel-yaml-dsl
  • camel-jbang-plugin-mcp ← depends on affected reactor module org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-tui ← depends on affected reactor module org.apache.camel:camel-yaml-dsl-validator
  • camel-jbang-plugin-validate ← depends on affected reactor module org.apache.camel:camel-yaml-dsl-validator
  • camel-launcher-container ← depends on affected reactor module org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← depends on affected reactor module org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← depends on affected reactor module org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (2)
  • camel-itest
  • camel-yaml-dsl-deserializers

ℹ️ Shadow mode — Scalpel observes but does not affect test execution. Learn more

Build reactor — dependencies compiled but only changed modules were tested (2 modules, 18.9s total)

Total reactor time: 18.9s

Module Duration Status
Camel :: Docs 10.9s SUCCESS
Camel :: AWS :: Common 8.0s SUCCESS

Top 20 slowest modules:

  • Camel :: Docs (10.9s)
  • Camel :: AWS :: Common (8.0s)

⚙️ View full build and test results

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR

Comment: the fix is right. Setting Apache5HttpClient / NettyNioAsyncHttpClient through httpClientBuilder() keeps what the SDK lookup did (the SDK still applies the service defaults with buildWithDefaults, so Kinesis HTTP/2 and the like keep working, and closes the client with the AWS client), and it no longer depends on every SdkHttpService registration on the classpath being loadable.

Blockers

  • None

Other findings: 1 non-blocking (upgrade guide wording vs. clients built outside AwsClientBuilderUtil), 1 suggestion — see inline.

Thanks for the careful write-up and for a test that reproduces the Kafka Connect failure as a plain unit test with a foreign service registration; that makes the fix easy to verify.

I checked the 39 production callers of AwsClientBuilderUtil: none sets its own httpClient(...) in the service-specific callback, so the SDK's "httpClient and httpClientBuilder can't both be configured" check does not trip on the new default.

This review does not replace specialized review tools or static analysis.

Claude Code on behalf of davsclaus

This review was generated by an AI agent and may contain inaccuracies. Please verify all suggestions before applying.

Comment thread docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc Outdated
@oscerd

oscerd commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review feedback:

  • Added sdkAsyncSettingLeavesTheChoiceToTheSdk in AwsClientBuilderUtilTest asserting that setting ASYNC_HTTP_SERVICE_IMPL delegates client choice to the AWS SDK.
  • Clarified the upgrade guide note in camel-4x-upgrade-guide-4_24.adoc to specify that the explicit HTTP client configuration applies to the SDK clients components create for their endpoints.

Claude Code on behalf of oscerd

Comment thread docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc Outdated

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TL;DR

Verdict: Thanks for the quick turnaround: the async test is in, and the 4.24 note now scopes the change to the clients built for endpoints. Two small things are left before merge.

Blockers

  • The branch conflicts with main in camel-4x-upgrade-guide-4_22.adoc (new 4.22.3 notes landed there), so CI has not run on bfdafdb; a rebase will trigger it.

Other findings: 1 non-blocking (the 4.22.3 note still says "they create", see the open gnodet-bot suggestion), 1 nit.

Status of my earlier points:

  • Upgrade note scope: partially. Fixed in the 4.24 note; the same sentence in the 4.22.3 note (camel-4x-upgrade-guide-4_22.adoc:326) still needs "for their endpoints".
  • Async test: fixed. sdkAsyncSettingLeavesTheChoiceToTheSdk exercises the ASYNC_HTTP_SERVICE_IMPL branch, and the SDK error message does contain the class name.

Nit: the edited 4.24 line is 124 characters; reflowing it to the 120 columns of the rest of the guide would keep it tidy.


Reviewed with Claude Code on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

oscerd and others added 4 commits October 28, 2026 19:07
…ad of the classpath lookup

AwsClientBuilderUtil set an HTTP client on the SDK client builder only
with a proxy or trustAllCertificates. Otherwise the AWS SDK looked the
client up with ServiceLoader, and that lookup fails as a whole when one
registration cannot be loaded, as when a Kafka Connect plugin sees the
apache-client registration of the worker's own AWS SDK
("ApacheSdkHttpService not a subtype").

Set Apache5HttpClient (sync) and NettyNioAsyncHttpClient (async), the
implementations the lookup selects from Camel's dependencies, unless the
AWS SDK setting software.amazon.awssdk.http.service.impl (or
software.amazon.awssdk.http.async.service.impl) names one.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
…nd clarify upgrade note

- Add sdkAsyncSettingLeavesTheChoiceToTheSdk in AwsClientBuilderUtilTest
- Clarify upgrade guide note to specify clients created for endpoints

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
…ated for endpoints

The 4.22.3 note now says, as the 4.24 note does, that the camel-aws components set the HTTP client
of the AWS SDK clients they create for their endpoints. The first paragraph of both notes is
reflowed to 120 columns.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@github-actions github-actions Bot removed the lts label Oct 28, 2026
@oscerd

oscerd commented Oct 28, 2026

Copy link
Copy Markdown
Contributor Author

@davsclaus thanks for the second look. Your points:

  1. Conflict with main (blocker): rebased on the current main. The conflict was the 4.22.3 notes that landed at the same place in camel-4x-upgrade-guide-4_22.adoc (camel-wordpress, camel-lra, camel-jbang plugin add). They are all kept, and the camel-aws note stays where it was, between the camel-vertx-websocket and camel-wordpress notes. The code and test commits are replayed unchanged, and the camel-aws-common tests pass after the rebase (8 tests, 0 failures). CI now runs on the new head.
  2. Upgrade note scope: the 4.22.3 note now says "the AWS SDK clients they create for their endpoints" too, in "CAMEL-26343: upgrade guide - scope the 4.22.3 note to the clients created for endpoints" (the gnodet-bot suggestion). This PR has no 4.18.x note: the backport goes to camel-4.22.x only ([backport camel-4.22.x] CAMEL-26343: camel-aws - set the AWS SDK HTTP client explicitly instead of the classpath lookup #28564).
  3. Nit, 124-character line: in the same commit, the first paragraph of both notes is reflowed to 120 columns. That also fixes a 121-character line in the same paragraph.

The PR description is updated to match (the async setting test, 8 tests, the scope of the notes).

Claude Code on behalf of oscerd

@oscerd
oscerd requested a review from davsclaus October 28, 2026 18:12

@gnodet-bot gnodet-bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following up on my earlier review — all findings have been addressed.

  • Async escape-hatch test (sdkAsyncSettingLeavesTheChoiceToTheSdk) — ✅ added and correct.
  • 4.24 upgrade note scope ("for their endpoints") — ✅ fixed in prior commit.
  • 4.22.3 upgrade note scope ("for their endpoints") — ✅ fixed in this push (commit acd5e11f).
  • Line reflow to 120 columns — ✅ both notes now stay within the limit.
  • Merge conflict on camel-4x-upgrade-guide-4_22.adoc — ✅ resolved by rebase.

The fix and tests are solid. useDefaultHttpClient() correctly gates on SdkSystemSetting so users who named a custom HTTP client via the system property are unaffected. The ForeignHttpService test setup cleanly reproduces the Kafka Connect failure as a plain unit test, and sdkLookupFailsOnTheForeignRegistration confirms the bug is observable without the fix.

LGTM.

This review was generated by an AI agent, Hermès on behalf of @gnodet.

@davsclaus davsclaus left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the changes since my last review: the points I raised are addressed, and CI is green on the current head.

Reviewed with Claude Code on behalf of davsclaus. This review was generated by an AI agent and may contain inaccuracies; please verify all suggestions before applying.

@davsclaus davsclaus added this to the 4.24.0 milestone Oct 29, 2026
@davsclaus davsclaus added the bug Something isn't working label Oct 29, 2026
@davsclaus
davsclaus merged commit d8f59b3 into apache:main Oct 29, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants