Skip to content

CAMEL-24900: camel-jcr - apply header filtering when mapping node properties to Exchange headers - #26748

Merged
davsclaus merged 3 commits into
apache:mainfrom
oscerd:fix/CAMEL-24900
Sep 28, 2026
Merged

davsclaus merged 3 commits into
apache:mainfrom
oscerd:fix/CAMEL-24900

Conversation

@oscerd

@oscerd oscerd commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

Motivation

The jcr producer's CamelJcrGetById operation mapped every property of the retrieved node onto the Exchange via message.setHeader(property.getName(), ...) without running the names through a HeaderFilterStrategy, and the insert path persisted all message headers (bar three JCR control keys) as node properties. Unlike most components, camel-jcr defined no HeaderFilterStrategy, so Camel internal header names (e.g. CamelHttpUri) were copied through unfiltered in both directions.

This continues the header-filtering alignment done for camel-coap (CAMEL-24655).

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

Changes

  • JcrEndpoint is now HeaderFilterStrategyAware, exposing a headerFilterStrategy endpoint option that defaults to DefaultHeaderFilterStrategy (filters names starting with Camel/camel, case-insensitively).
  • CamelJcrGetById runs each property name through applyFilterToExternalHeaders before setHeader; ordinary document properties are preserved.
  • The insert path runs each header through applyFilterToCamelHeaders, so Camel internal headers carried on the message are no longer persisted as node properties.
  • Adds JcrGetNodeByIdHeaderInjectionTest: a Camel-prefixed property name, in four casings, is not mapped onto the Exchange, while an ordinary document property still is.
  • Regenerates the catalog and endpoint-DSL metadata for the new option, and adds an upgrade-guide note (changed default).

Testing

mvn -f components/camel-jcr/pom.xml test — all 14 tests pass, including the new injection test and the existing insert / getById round-trip tests.


Claude Code on behalf of Andrea Cosentino (@oscerd)

🤖 Generated with Claude Code

…perties to Exchange headers

The JCR producer's CamelJcrGetById operation mapped every property of the
retrieved node onto the Exchange without a HeaderFilterStrategy, and the
insert path persisted all message headers (bar three JCR control keys) as
node properties. camel-jcr defined no HeaderFilterStrategy, so Camel internal
header names (e.g. CamelHttpUri) were copied through unfiltered in both
directions.

Make JcrEndpoint HeaderFilterStrategyAware with a default
DefaultHeaderFilterStrategy, which filters names starting with Camel/camel
case-insensitively. getById now runs each property name through
applyFilterToExternalHeaders before setHeader, and insert runs each header
through applyFilterToCamelHeaders; ordinary document properties are preserved.
Adds JcrGetNodeByIdHeaderInjectionTest and an upgrade-guide note.

Continues the header-filtering alignment done for camel-coap (CAMEL-24655).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
@oscerd
oscerd requested review from davsclaus and gnodet September 22, 2026 13:12
@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.

Two issues to address before merge — one missing test coverage for the INSERT path, one misleading consumer DSL API.

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

@oscerd oscerd added port/camel-4.22.x Bug needs porting to camel-4.22.x port/camel-4.18.x Bug needs porting to camel-4.18.x labels Sep 22, 2026

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

This is a well-executed instance of exactly the pattern the committer checklist in CLAUDE.md asks for, and the details that are easy to get wrong are right here. Specifically, I checked:

  • Filter directions are correct — applyFilterToCamelHeaders on the insert path (Camel → JCR) and applyFilterToExternalHeaders on getById (JCR → Camel). Getting these backwards is the usual bug in this family and they're the right way round.
  • The default actually bites — DefaultHeaderFilterStrategy initialises both inFilterStartsWith and outFilterStartsWith to {"Camel", "camel"} with caseInsensitive = true and filterOnMatch = true, so the four-casing test is testing something real rather than passing by accident.
  • No second inbound path was missed — JcrProducer:84 is the only setHeader call in the component's main source, so getById really is the whole surface.

All 14 tests pass on the branch. Comments below are a test gap and some tidying; nothing blocking.

Main point: the insert-path filtering is documented in the upgrade guide but has no test — see the inline comment.

This review does not replace CodeRabbit, Sourcery, or SonarCloud.

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

@github-actions

github-actions Bot commented Sep 22, 2026 •

Copy link
Copy Markdown
Contributor

🧪 CI tested the following changed modules:

  • catalog/camel-catalog
  • components/camel-jcr
  • docs
  • dsl/camel-endpointdsl

🔬 Scalpel shadow comparison — Scalpel: 9 of 693 tested, 24 compile-only — current: 9 all tested

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

Skip-tests mode would test 9 modules (4 direct + 8 downstream), skip tests for 24 (generated code, meta-modules)

Modules Scalpel would test (9)
  • camel-jbang-mcp ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-mcp ← downstream of org.apache.camel:camel-jbang-core
  • camel-jbang-plugin-route-parser ← downstream of org.apache.camel:camel-route-parser
  • camel-jbang-plugin-tui ← downstream of org.apache.camel:camel-catalog
  • camel-jbang-plugin-validate ← downstream of org.apache.camel:camel-yaml-dsl-validator
  • camel-jcr ← components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointConfigurer.java, components/camel-jcr/src/generated/java/org/apache/camel/component/jcr/JcrEndpointUriFactory.java, components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json, components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrEndpoint.java, components/camel-jcr/src/main/java/org/apache/camel/component/jcr/JcrProducer.java, components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrGetNodeByIdHeaderInjectionTest.java, components/camel-jcr/src/test/java/org/apache/camel/component/jcr/JcrInsertHeaderInjectionTest.java
  • camel-launcher-container ← downstream of org.apache.camel:camel-launcher
  • camel-yaml-dsl-validator ← downstream of org.apache.camel:camel-catalog
  • camel-yaml-dsl-validator-maven-plugin ← downstream of org.apache.camel:camel-yaml-dsl-validator
Modules with tests skipped (24)
  • apache-camel
  • camel-allcomponents
  • camel-catalog-console
  • camel-catalog-maven
  • camel-catalog-suggest
  • camel-componentdsl
  • 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
  • dummy-component

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

All tested modules (36 modules, 5m 34s total)

Total reactor time: 5m 34s

Module Duration Status
Camel :: Launcher 53.0s SUCCESS
Camel :: JBang :: MCP 39.4s SUCCESS
Camel :: Component DSL 34.7s SUCCESS
Camel :: JBang :: Plugin :: TUI 30.2s SUCCESS
Camel :: Catalog :: Camel Catalog 22.4s SUCCESS
Camel :: JCR 20.5s SUCCESS
Camel :: YAML DSL 18.4s SUCCESS
Camel :: Docs 14.7s SUCCESS
Camel :: JBang :: Plugin :: Kubernetes 14.4s SUCCESS
Camel :: Kamelet Main 9.9s SUCCESS
Camel :: YAML DSL :: Validator 9.3s SUCCESS
Camel :: YAML DSL :: Deserializers 9.2s SUCCESS
Camel :: Catalog :: Camel Route Parser 8.8s SUCCESS
Camel :: JBang :: Plugin :: Testing 7.8s SUCCESS
Camel :: Catalog :: Camel Report Maven Plugin 6.8s SUCCESS
Camel :: JBang :: Plugin :: Validate 5.1s SUCCESS
Camel :: All Components Sync point 4.6s SUCCESS
Camel :: YAML DSL :: Maven Plugins 3.6s SUCCESS
Camel :: YAML DSL :: Validator Maven Plugin 3.2s SUCCESS
Camel :: Catalog :: Maven 2.5s SUCCESS
Camel :: Catalog :: Suggest (deprecated) 2.0s SUCCESS
Camel :: Assembly 1.7s SUCCESS
Camel :: JBang :: Plugin :: Edit 1.6s SUCCESS
Camel :: Catalog :: Dummy Component 1.4s SUCCESS
Camel :: Coverage 1.3s SUCCESS
Camel :: JBang :: Plugin :: Generate 1.2s SUCCESS
Camel :: JBang :: Integration tests 1.1s SUCCESS
Camel :: Endpoint DSL :: Support 1.0s SUCCESS
Camel :: JBang :: Main 1.0s SUCCESS
Camel :: Catalog :: Console 0.9s SUCCESS
Camel :: JBang :: Plugin :: MCP 0.7s SUCCESS
Camel :: Launcher :: Container 0.7s SUCCESS
Camel :: JBang :: Plugin :: Route Parser 0.6s SUCCESS
Camel :: Endpoint DSL n/a
Camel :: Integration Tests n/a
Camel :: JBang :: Core n/a

Top 20 slowest modules:

  • Camel :: Launcher (53.0s)
  • Camel :: JBang :: MCP (39.4s)
  • Camel :: Component DSL (34.7s)
  • Camel :: JBang :: Plugin :: TUI (30.2s)
  • Camel :: Catalog :: Camel Catalog (22.4s)
  • Camel :: JCR (20.5s)
  • Camel :: YAML DSL (18.4s)
  • Camel :: Docs (14.7s)
  • Camel :: JBang :: Plugin :: Kubernetes (14.4s)
  • Camel :: Kamelet Main (9.9s)
  • Camel :: YAML DSL :: Validator (9.3s)
  • Camel :: YAML DSL :: Deserializers (9.2s)
  • Camel :: Catalog :: Camel Route Parser (8.8s)
  • Camel :: JBang :: Plugin :: Testing (7.8s)
  • Camel :: Catalog :: Camel Report Maven Plugin (6.8s)
  • Camel :: JBang :: Plugin :: Validate (5.1s)
  • Camel :: All Components Sync point (4.6s)
  • Camel :: YAML DSL :: Maven Plugins (3.6s)
  • Camel :: YAML DSL :: Validator Maven Plugin (3.2s)
  • Camel :: Catalog :: Maven (2.5s)

⚙️ View full build and test results

- Add JcrInsertHeaderInjectionTest covering the insert-path filter: a
  Camel-prefixed header (four casings) is not persisted as a node property,
  while an ordinary header still is.
- Scope the headerFilterStrategy option to "producer,filter". It is only
  used by the producer, so the previously generated consumer DSL overloads
  (a dead API) are removed.
- Initialise headerFilterStrategy at its declaration to avoid a benign data
  race in the lazy getter, which is now a plain accessor.
- Document why filterComponentHeaders is retained: it strips the JCR control
  keys unconditionally, independent of a custom HeaderFilterStrategy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>

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

Re-reviewed 0e8c49a (the follow-up since my review on 22 Sep). All four points are addressed, and the two judgement calls went the way I'd have chosen.

Addressed

  • Insert-path test — JcrInsertHeaderInjectionTest closes the gap that was my main point, and it tests something real: filterComponentHeaders only strips the three JCR control keys, so nothing but the HeaderFilterStrategy can be making CamelHttpUri disappear. Mirroring the four casings from the getById test is the right symmetry, and asserting my.contents.property is still stored keeps it honest about not over-filtering.
  • Lazy init in the getter — gone, field initialised at the declaration, getter is now a plain accessor. Race removed.
  • filterComponentHeaders — kept with a comment explaining exactly the custom-strategy case I raised. That was the alternative I said was defensible, and the comment means it no longer reads as dead code.
  • Dead null checks in JcrProducer — see the note below; they are no longer dead, which is fine.

Two notes, neither blocking:

🟡 The catalog still doesn't tell anyone that filtering is on by default. This was the second half of my JcrEndpoint comment and the field initialiser can't fix it — the package plugin only emits defaultValue for literal constants, so an object-typed option never gets one. That leaves the upgrade guide as the only place the new default is written down; a user reading the component docs sees an option that looks unset. Worth folding into the description on the @UriParam, e.g. "... By default a DefaultHeaderFilterStrategy is used, which filters headers starting with Camel or camel." It's a regen, so only worth doing if you're touching the branch anyway.

🔵 The null guards changed meaning rather than becoming dead. With the lazy init gone, setHeaderFilterStrategy(null) now sticks instead of being healed by the next getHeaderFilterStrategy() call, so the != null / == null checks in process() are live again — and an explicit null silently disables the filtering this PR adds. No NPE, and treating null as "opt out entirely" is coherent with supplying a permissive custom strategy, so I'm not asking for a change. Flagging it only because it's the opposite of what my original nit assumed.

The label narrowing to producer,filter is correct and costs nothing — I checked main and headerFilterStrategy isn't an endpoint option on jcr at all today, so dropping the consumer builder methods removes nothing that was ever released.

From my side this is ready; I've left it as a comment rather than an approval so the sign-off is a human one.

Claude Code on behalf of davsclaus

This review does not replace CodeRabbit, Sourcery, or SonarCloud.

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

Resolve upgrade-guide conflict in camel-4x-upgrade-guide-4_23.adoc by keeping
both the camel-jcr and camel-mustache/camel-chunk sections.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>

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

Both issues from the previous review are addressed — approving.

Resolved:

  • ✅ Insert-path test — JcrInsertHeaderInjectionTest closes the coverage gap: four casing variants of CamelHttpUri are sent on the insert exchange, the stored node is read back, and node.hasProperty(variant) is asserted false while my.contents.property is still present. Mirrors JcrGetNodeByIdHeaderInjectionTest symmetrically.
  • ✅ @UriParam label — changed to "producer,filter". The regenerated DSL factory no longer emits headerFilterStrategy() on JcrEndpointConsumerBuilder; the catalog JSON records "label": "producer,filter" as expected.

One minor item not addressed (non-blocking, already noted by davsclaus):

  • 🟡 The @UriParam description field still reads "To use a custom org.apache.camel.spi.HeaderFilterStrategy to filter header to and from Camel message." — it doesn't tell a user reading the component reference that DefaultHeaderFilterStrategy (filtering Camel/camel-prefixed headers) is active by default. Since this is the whole behavioural change this PR introduces, a user scanning the option table has no hint that filtering is on unless they read the 4.23 upgrade guide. Worth folding into the description on a follow-up touch, e.g. "... By default, a DefaultHeaderFilterStrategy is used, which filters headers whose names start with 'Camel' or 'camel'."

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

@oscerd
oscerd requested a review from davsclaus September 23, 2026 17:39
@oscerd

oscerd commented Sep 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks both. Addressed the round in 0e8c49a:

  • Added JcrInsertHeaderInjectionTest for the insert-path filter (the coverage gap you both flagged).
  • Scoped the option to producer,filter — the consumer DSL overloads are gone.
  • Eager-initialised headerFilterStrategy (removes the lazy-getter race). One correction inline: it does not add a catalog defaultValue, since the option is object-typed.
  • Kept filterComponentHeaders (now with a comment) and the producer null-guards, with rationale in the threads.

Also merged main (c678202) to resolve an upgrade-guide conflict with the newly-landed camel-mustache/camel-chunk entry — both sections retained. CI is green.

Ready for another look.

Claude Code on behalf of Andrea Cosentino (@oscerd)

@oscerd

oscerd commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the thorough re-review @davsclaus. On the two non-blocking notes:

  • 🟡 default not shown in the catalog — agreed the object-typed option can't carry a defaultValue. The new default is documented in the 4.23 upgrade guide (the canonical place for a changed default). Folding the same sentence into the @UriParam description is a good idea, but it triggers a full catalog/DSL regen and the shared local ~/.m2 is currently mixed with newer-main components, so I'm holding it as a trivial follow-up rather than churn this otherwise-ready branch — happy to add it before merge if you'd rather it also live in the component docs.
  • 🔵 null guards — agreed, and intended: with the eager init an explicit setHeaderFilterStrategy(null) now sticks and disables filtering entirely, which is coherent with supplying a permissive custom strategy. Left as-is.

Claude Code on behalf of Andrea Cosentino (@oscerd)

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

Merge-only update since my last look. The jcr changes are unchanged and the upgrade-guide entry still renders correctly. The catalog-description wording (saying DefaultHeaderFilterStrategy is used by default) is still a nice-to-have, not a blocker. LGTM.

Claude Code on behalf of davsclaus

@davsclaus davsclaus added this to the 4.23.0 milestone Sep 28, 2026
@davsclaus davsclaus added the bug Something isn't working label Sep 28, 2026
@gnodet

gnodet commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

🔄 Backport Bot

This bugfix targets main and may need porting to:

  • camel-4.22.x

Add a port/<branch> label to automatically create a backport PR for that branch.

Backport PRs will be created automatically on merge (once a port label is added). Comment /port to create them immediately.

ℹ️ If you push additional commits after /port, use /port again to update the port PRs.

@davsclaus
davsclaus merged commit 0606943 into apache:main Sep 28, 2026
7 checks passed
@gnodet

gnodet commented Sep 28, 2026

Copy link
Copy Markdown
Contributor

🔄 Backport Bot

Conflicts (🤖 agent dispatched to resolve):

  • ⚠️ camel-4.22.x — Cherry-pick conflict in: docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc
  • ⚠️ camel-4.18.x — Cherry-pick conflict in: catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/components/jcr.json, components/camel-jcr/src/generated/resources/META-INF/org/apache/camel/component/jcr/jcr.json, docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc, dsl/camel-endpointdsl/src/generated/java/org/apache/camel/builder/endpoint/dsl/JcrEndpointBuilderFactory.java

ℹ️ If you push additional commits after /port, use /port again to update the port PRs.

@gnodet

gnodet commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

🔄 Backport Bot

Port PRs:

⚠️ Port to camel-4.22.x (#27043) has differences from the merged version:

  • docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_23.adoc

@gnodet gnodet removed port/camel-4.22.x Bug needs porting to camel-4.22.x port/camel-4.18.x Bug needs porting to camel-4.18.x labels Sep 29, 2026
oscerd added a commit that referenced this pull request Sep 29, 2026
…ng when mapping node properties to Exchange headers (#27043)

The JCR producer applies a HeaderFilterStrategy when mapping between JCR node
properties and Exchange headers (default DefaultHeaderFilterStrategy, filtering
Camel/camel case-insensitively), so a node property cannot inject a Camel-internal
header and Camel-internal headers are not persisted as node properties.

Backport of #26748 to camel-4.22.x. The upgrade-guide entry lives on main only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
oscerd added a commit that referenced this pull request Sep 29, 2026
…ng when mapping node properties to Exchange headers (#27047)

Backport of #26748 to camel-4.18.x.

On this release line DefaultHeaderFilterStrategy does not filter Camel/camel
headers by default (that default arrived in CAMEL-23543, on 4.21.x and later),
so the JCR endpoint configures the filter explicitly to keep the same behaviour.
The upgrade-guide entry lives on main only and is not included here.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Signed-off-by: Andrea Cosentino <ancosen@gmail.com>
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.

5 participants