Skip to content

CAMEL-24164: camel-jaxb - Fix CamelJaxbPartClass header state pollution#24813

Merged
davsclaus merged 1 commit into
apache:mainfrom
Croway:CAMEL-24164
Jul 17, 2026
Merged

CAMEL-24164: camel-jaxb - Fix CamelJaxbPartClass header state pollution#24813
davsclaus merged 1 commit into
apache:mainfrom
Croway:CAMEL-24164

Conversation

@Croway

@Croway Croway commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Claude Code on behalf of Croway

The JaxbDataFormat.unmarshal() and toElement() methods write the header-derived CamelJaxbPartClass value directly into the shared instance field this.partClass. Since a DataFormat is shared across all exchanges in a route step, this causes:

  • Stickiness: once any exchange carries the header, partClass remains non-null permanently — all subsequent exchanges without the header silently unmarshal/marshal using the leaked class.
  • Data race: concurrent exchanges with different headers cross-contaminate.

The fix uses a local variable (effectivePartClass) instead of mutating the instance field, matching the pattern already used by Jackson, CBOR, Gson, and Jsonb data formats.

The bug was introduced in 2017 (CAMEL-5723, commit 03519184b36a) and carried through the 2024 refactoring (commit f0b4bb237331).

Changes

  • JaxbDataFormat.java: Replace this.partClass = ... with local effectivePartClass in both unmarshal() and toElement().
  • New test JaxbPartClassHeaderStatePollutionTest.java: Two test cases (unmarshal + marshal) that send Exchange 1 with header, then Exchange 2 without, asserting no state leaks.

Test plan

  • New test JaxbPartClassHeaderStatePollutionTest covers both unmarshal and marshal paths
  • All 113 existing camel-jaxb tests pass (mvn verify in components/camel-jaxb)
  • Verified that existing JaxbDataFormatPartClassHeaderTest and JaxbDataFormatPartClassTest still pass (header-driven and configured partClass paths)

🤖 Generated with Claude Code

…on in JaxbDataFormat

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@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 gnodet 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.

Claude Code on behalf of gnodet

LGTM — important concurrency/state-pollution fix.

The bug: JaxbDataFormat is shared across all exchanges in a route step. Both unmarshal() and toElement() write the header-derived CamelJaxbPartClass value directly into the instance field this.partClass. This causes:

  1. Stickiness — once any exchange carries the header, partClass stays non-null forever, silently using the leaked class for all subsequent exchanges without the header.
  2. Data race — concurrent exchanges with different headers cross-contaminate through the shared field.

The fix: Introduces a local effectivePartClass variable initialized from this.partClass, overridden from the header when present. The instance field is never mutated. This matches the established pattern used by Jackson, CBOR, Gson, and Jsonb data formats.

Note: partNamespace is already safe — it's read into a local via getPartNamespace() and the header override mutates the method parameter partNamespaceOnDataFormat, not the instance field.

The test: Excellent coverage — sends Exchange 1 with CamelJaxbPartClass header, then Exchange 2 without, asserting no state leaks in both unmarshal and marshal paths. The assertions are specific (assertInstanceOf(PurchaseOrder.class, ...) / assertFalse(payload2.contains("<address:address"))) — directly proving the absence of pollution.

Bug has been present since 2017 (CAMEL-5723). Nice catch.

@github-actions

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • components/camel-jaxb

ℹ️ 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: 59 tested, 29 compile-only — current: 59 all tested

Maveniverse Scalpel detected 88 affected modules (current approach: 59).

⚠️ Modules only in Scalpel (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

Skip-tests mode would test 59 modules (1 direct + 58 downstream), skip tests for 29 (generated code, meta-modules)

Modules Scalpel would test (59)
  • camel-a2a
  • camel-as2
  • camel-atmosphere-websocket
  • camel-clickup
  • camel-consul
  • camel-cxf-rest
  • camel-cxf-soap
  • camel-cxf-spring-rest
  • camel-cxf-spring-soap
  • camel-cxf-spring-transport
  • camel-cxf-transport
  • camel-java-joor-dsl
  • camel-jaxb
  • camel-jbang-mcp
  • camel-jbang-plugin-mcp
  • camel-jbang-plugin-route-parser
  • camel-jbang-plugin-tui
  • camel-jbang-plugin-validate
  • camel-jetty
  • camel-jetty-common
  • camel-jsonpath
  • camel-knative-http
  • camel-launcher-container
  • camel-lra
  • camel-micrometer-observability
  • camel-micrometer-prometheus
  • camel-netty-http
  • camel-oauth
  • camel-observability-services
  • camel-openapi-validator
  • camel-opentelemetry
  • camel-opentelemetry2
  • camel-platform-http-main
  • camel-platform-http-vertx
  • camel-quickfix
  • camel-rest-openapi
  • camel-restdsl-openapi-plugin
  • camel-servlet
  • camel-slack
  • camel-soap
  • camel-spring-ws
  • camel-stax
  • camel-telegram
  • camel-telemetry
  • camel-telemetry-dev
  • camel-test-main-junit5
  • camel-test-main-junit6
  • camel-undertow
  • camel-undertow-spring-security
  • camel-vertx-http
  • camel-webhook
  • camel-whatsapp
  • camel-xml-io-dsl
  • camel-xml-jaxb-dsl
  • camel-xml-jaxb-dsl-test-definition
  • camel-xml-jaxb-dsl-test-spring
  • camel-yaml-dsl-validator
  • camel-yaml-dsl-validator-maven-plugin
  • camel-zookeeper
Modules with tests skipped (29)
  • apache-camel
  • camel-allcomponents
  • camel-catalog
  • camel-catalog-console
  • camel-catalog-lucene
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • camel-csimple-maven-plugin
  • camel-endpointdsl
  • camel-endpointdsl-support
  • camel-itest
  • camel-jbang-core
  • camel-jbang-it
  • camel-jbang-main
  • camel-jbang-plugin-edit
  • camel-jbang-plugin-generate
  • camel-jbang-plugin-kubernetes
  • camel-jbang-plugin-test
  • camel-kamelet-main
  • camel-launcher
  • camel-report-maven-plugin
  • camel-route-parser
  • camel-yaml-dsl
  • camel-yaml-dsl-deserializers
  • camel-yaml-dsl-maven-plugin
  • coverage
  • docs
  • dummy-component

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

Build reactor — dependencies compiled but only changed modules were tested (88 modules)
  • Camel :: AI :: A2A
  • Camel :: AS2 :: Component
  • Camel :: All Components Sync point
  • Camel :: Assembly
  • Camel :: Atmosphere WebSocket Servlet
  • Camel :: CXF :: REST
  • Camel :: CXF :: REST :: Spring
  • Camel :: CXF :: SOAP
  • Camel :: CXF :: SOAP :: Spring
  • Camel :: CXF :: Transport
  • Camel :: CXF :: Transport :: Spring
  • Camel :: Catalog :: CSimple Maven Plugin (deprecated)
  • Camel :: Catalog :: Camel Catalog
  • Camel :: Catalog :: Camel Report Maven Plugin
  • Camel :: Catalog :: Camel Route Parser
  • Camel :: Catalog :: Console
  • Camel :: Catalog :: Dummy Component
  • Camel :: Catalog :: Lucene (deprecated)
  • Camel :: Catalog :: Maven
  • Camel :: Catalog :: Suggest
  • Camel :: ClickUp
  • Camel :: Common Telemetry
  • Camel :: Component DSL
  • Camel :: Consul
  • Camel :: Coverage
  • Camel :: Docs
  • Camel :: Endpoint DSL
  • Camel :: Endpoint DSL :: Support
  • Camel :: Integration Tests
  • Camel :: JAXB
  • Camel :: JBang :: Core
  • Camel :: JBang :: Integration tests
  • Camel :: JBang :: MCP
  • Camel :: JBang :: Main
  • Camel :: JBang :: Plugin :: Edit
  • Camel :: JBang :: Plugin :: Generate
  • Camel :: JBang :: Plugin :: Kubernetes
  • Camel :: JBang :: Plugin :: MCP
  • Camel :: JBang :: Plugin :: Route Parser
  • Camel :: JBang :: Plugin :: TUI
  • Camel :: JBang :: Plugin :: Testing
  • Camel :: JBang :: Plugin :: Validate
  • Camel :: JSon Path
  • Camel :: Java DSL with jOOR
  • Camel :: Jetty
  • Camel :: Jetty :: Common
  • Camel :: Kamelet Main
  • Camel :: Knative HTTP
  • Camel :: Launcher
  • Camel :: Launcher :: Container
  • Camel :: Long-Running-Action
  • Camel :: Maven Plugins :: OpenApi REST DSL Generator
  • Camel :: Micrometer :: Observability 2
  • Camel :: Micrometer :: Prometheus
  • Camel :: Netty HTTP
  • Camel :: OAuth
  • Camel :: Observability Services
  • Camel :: OpenAPI :: Validator
  • Camel :: OpenTelemetry (deprecated)
  • Camel :: Opentelemetry 2
  • Camel :: Platform HTTP :: Main
  • Camel :: Platform HTTP :: Vert.x
  • Camel :: QuickFIX/J
  • Camel :: REST OpenApi
  • Camel :: SOAP
  • Camel :: Servlet
  • Camel :: Slack
  • Camel :: Spring Web Services
  • Camel :: StAX
  • Camel :: Telegram
  • Camel :: Telemetry :: Dev
  • Camel :: Test :: Main :: JUnit5
  • Camel :: Test :: Main :: JUnit6
  • Camel :: Undertow
  • Camel :: Undertow Spring Security
  • Camel :: Vert.x :: HTTP
  • Camel :: Webhook
  • Camel :: Whatsapp
  • Camel :: XML DSL Jaxb :: Test :: Definition
  • Camel :: XML DSL Jaxb :: Test :: Spring
  • Camel :: XML DSL with camel-xml-io
  • Camel :: XML DSL with camel-xml-jaxb
  • Camel :: YAML DSL
  • Camel :: YAML DSL :: Deserializers
  • Camel :: YAML DSL :: Maven Plugins
  • Camel :: YAML DSL :: Validator
  • Camel :: YAML DSL :: Validator Maven Plugin
  • Camel :: Zookeeper

⚙️ View full build and test results

@oscerd oscerd 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.

LGTM — real cross-exchange contamination fix. Mutating the shared this.partClass field per request meant a CamelJaxbPartClass header set for one exchange stuck around for the next (and raced under concurrency). Replacing it with a local effectivePartClass threaded through both toElement/marshal and the unmarshal path is logically equivalent across all configured×header combinations (header still takes precedence, full-vs-partial selection preserved) and eliminates the stickiness. The two-exchange isolation test (header on exchange 1, none on exchange 2, asserting exchange 2's payload isn't partial) targets exactly the deterministic manifestation. Clean.

Reviewed with Claude Code on behalf of Andrea Cosentino. 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.22.0 milestone Jul 17, 2026
@davsclaus davsclaus added the bug Something isn't working label Jul 17, 2026
@davsclaus
davsclaus merged commit 17c2419 into apache:main Jul 17, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working components

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants