Skip to content

Parse optional trailing query parameters off subjects (#49)#52

Merged
rossdanderson merged 1 commit into
mainfrom
issue-49
Jul 1, 2026
Merged

Parse optional trailing query parameters off subjects (#49)#52
rossdanderson merged 1 commit into
mainfrom
issue-49

Conversation

@rossdanderson

Copy link
Copy Markdown
Collaborator

Closes #49.

What & why

AntPatternNamespace had no notion of an optional trailing query string on a subject, which (a) polluted the last path variable when a subject carried a ?query, and (b) left consumers no way to read query parameters. This adds first-class parsing of an optional trailing ?a=b&c=d.

Changes

datasourcex-util

  • Strip an optional trailing ?query before match / extractPathVariables so path variables are never polluted (the bug fix).
  • Add extractQueryParameters(subject) — parses ?a=b&c=d into a map (empty when absent), via a shared pure parseQueryString helper (URL-decoding, empty values, last-wins on repeated keys).
  • URL-decode path variables too, for consistency with the Spring DataSourceMessageHandler (which already decodes destination variables).
  • Expose a shared CHARSET; DataSourceServerBootstrap.bootstrapCharset sources from it.

Reactive Bind DSL

  • Thread the parsed query map to all supplier shapes via a Request / ChannelRequest object (path, pathVariables, queryParameters[, receive]) instead of positional params — avoids the adjacent same-typed-map footgun and makes future field additions non-breaking.
  • RequestSupplier / ChannelRequestSupplier are receiver-style SAMs (operator fun Request.invoke()): Kotlin gets { this.path } ergonomics from a single overload (no ambiguity), Java implements a clean invoke(request).
  • Retain the previous positional shapes as @Deprecated PathVariablesSupplier / PathVariablesChannelSupplier overloads for source back-compat.

⚠️ Behavioural change (path-variable decoding)

Because path variables are now URL-decoded (matching the Spring handler):

  • + in a value becomes a space (e.g. /RATES/USD+SOFRUSD SOFR).
  • A value with a malformed/lone % (e.g. 100%) throws IllegalArgumentException.
  • Literal non-ASCII (CJK/Cyrillic/accented) is unaffected.
  • A query-less subject with +/% is therefore no longer byte-identical to before.

This was a deliberate call for consistency with the existing Spring destination-variable decoding.

Versioning

Additive to datasourcex-util. The reactive supplier interfaces are reshaped (deprecated overloads retained) → major bump. .api snapshots regenerated.

Testing

./gradlew --continue check green. AntPatternNamespaceTest covers pollution-fix, no/single/multiple query params, query on an exact pattern, path+query URL-decoding, empty values, and repeated keys; BindTest adds an end-to-end receiver-style + query-parameter delivery test.

Spring note

Investigated whether Spring @MessageMapping offers query parameters — it does not (only @DestinationVariable/@Header/@Headers/@Payload/Principal; no @RequestParam equivalent for messaging destinations), so this is a genuine framework extension.

AntPatternNamespace had no notion of an optional trailing query string,
which (a) polluted the last path variable when a subject carried a
`?query`, and (b) left consumers no way to read query parameters.

util:
- Strip an optional trailing `?query` before match/extractPathVariables
  so path variables are never polluted (fixes the bug).
- Add extractQueryParameters(subject): parses `?a=b&c=d` into a map
  (empty when absent), via a shared pure parseQueryString helper
  (URL-decoding, empty values, last-wins on repeated keys).
- URL-decode path variables too, for consistency with the Spring
  DataSourceMessageHandler which already decodes destination variables.
  NOTE: this changes query-less subjects like /X/EUR%2FUSD to yield
  EUR/USD instead of EUR%2FUSD.
- Expose a shared CHARSET constant; DataSourceServerBootstrap sources
  its bootstrapCharset from it.

reactive DSL:
- Thread the parsed query map to all supplier shapes via a Request /
  ChannelRequest object (path, pathVariables, queryParameters[, receive])
  instead of positional params, avoiding the same-typed adjacent-map
  footgun and making future additions non-breaking.
- RequestSupplier / ChannelRequestSupplier are receiver-style SAMs, so
  Kotlin gets `{ this.path }` ergonomics with no overload ambiguity while
  Java implements a clean `invoke(request)`.
- Retain the previous positional shapes as @deprecated PathVariablesSupplier
  / PathVariablesChannelSupplier overloads for source back-compat.

Public API: additive to util; the reactive supplier interfaces are
reshaped (deprecated overloads retained) — a major bump. .api snapshots
regenerated.
@rossdanderson rossdanderson merged commit 2c55200 into main Jul 1, 2026
6 checks passed
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.

AntPatternNamespace: parse optional trailing query parameters (and fix last-path-variable pollution)

1 participant