Skip to content

feat: add RouteParent annotation and RouteHierarchy walker class#24451

Closed
web-padawan wants to merge 3 commits into
mainfrom
feature/route-hierarchy
Closed

feat: add RouteParent annotation and RouteHierarchy walker class#24451
web-padawan wants to merge 3 commits into
mainfrom
feature/route-hierarchy

Conversation

@web-padawan

Copy link
Copy Markdown
Member

Description

Combines following PRs to get the feature snapshot:

Type of change

  • Feature

web-padawan and others added 2 commits May 26, 2026 11:23
Introduces com.vaadin.flow.router.RouteParent for declaring the
conceptual parent of a @route view. Consumed by external navigation
components (e.g. breadcrumbs) that need to walk route ancestry
without inferring it from URL prefixes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Introduces com.vaadin.flow.router.RouteHierarchy with resolveAncestors
and resolveParent. Consumes @RouteParent first, falls back to
URL-prefix walking via RouteConfiguration#getTemplate /
#getRoute. Cycle-safe via a visited set.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown

Test Results

1 183 files   -   238  1 183 suites   - 238   1h 16m 21s ⏱️ - 2m 34s
7 180 tests  - 2 832  7 131 ✅  - 2 813  47 💤  - 21  2 ❌ +2 
7 652 runs   - 2 832  7 602 ✅  - 2 813  48 💤  - 21  2 ❌ +2 

For more details on these failures, see this check.

Results for commit 015373a. ± Comparison against base commit df55c8c.

♻️ This comment has been updated with latest results.

@web-padawan

web-padawan commented May 27, 2026

Copy link
Copy Markdown
Member Author

🤖 comment below is generated by Claude based on use-cases analysis 🤖

API feedback from building real consumers

I built a standalone use-case module (7 views: breadcrumbs, an up-one-level button, and a sitemap) driven entirely by RouteHierarchy. The walker itself works well — but every consumer had to re-derive the same things through a ~120-line MissingAPI shim, because the walker returns bare Class<…> objects while consumers need renderable trail entries (class + parameters + label).

Suggested changes (prioritized)

1. Parameter-aware overload — add (highest value).
The walker returns ancestor classes but says nothing about which of the current RouteParameters each ancestor's template needs. Passing the full set to an ancestor's RouterLink/getUrl throws; the correct approach forces apps to re-parse :name segments (incl. :id(regex), :id?) — parsing Flow core already owns. This is a footgun, not a convenience.

public record RouteHierarchyEntry(
        Class<? extends Component> routeClass, RouteParameters parameters) {}

List<RouteHierarchyEntry> resolveAncestors(Class<…>, RouteParameters, RouteConfiguration);
Optional<RouteHierarchyEntry> resolveParent(Class<…>, RouteParameters, RouteConfiguration);

I'd return projected RouteParameters, not pre-built URL strings — RouterLink wants params (client-side nav), and the URL is one getUrl(...) away when you actually need it. This also removes any need for a per-ancestor label callback: with params on each entry, apps map entries → labels themselves.

2. Title helpers — add if cheap.
@PageTitle reflection was the single most-reused shim (breadcrumb, sitemap, up-link all do it).

Optional<String> titleOf(Class<? extends Component>);  // @PageTitle
Optional<String> titleOf(Component);                   // HasDynamicTitle, else @PageTitle

The class-name fallback stays app-side — Flow doesn't bless humanization as title policy. The Component overload covers the dynamic leaf title without threading an instance into the walker's chain logic.

Note

resolveAncestors returns [] for a non-@Route leaf, so consumers must special-case "just show the current page." Worth documenting in the Javadoc.

Full write-up with file/line evidence available on request. Happy to prototype the RouteHierarchyEntry overload if the direction looks right.

Introduces RouteHierarchy.Entry (route class + projected RouteParameters)
and parameter-aware overloads of resolveAncestors and resolveParent. For
each ancestor, the returned Entry carries only the parameters whose
name appears as a :name segment in that ancestor's route template, so
the result can be fed directly to RouterLink / getUrl without leaking
deeper parameters the ancestor does not declare.

Refs #24541.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 8, 2026

Copy link
Copy Markdown

@web-padawan

Copy link
Copy Markdown
Member Author

Closing in favor of #24550

@github-project-automation github-project-automation Bot moved this from 🔎Iteration reviews to Done in Vaadin Flow | Hilla | Kits ongoing work Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

Development

Successfully merging this pull request may close these issues.

2 participants