Skip to content

Seed URL mappings index with runtime fallback#15956

Open
jamesfredley wants to merge 1 commit into
8.0.xfrom
feat/url-mapping-precompute-seed
Open

Seed URL mappings index with runtime fallback#15956
jamesfredley wants to merge 1 commit into
8.0.xfrom
feat/url-mapping-precompute-seed

Conversation

@jamesfredley

Copy link
Copy Markdown
Contributor

Description

What was found

Problem Impact
URL mappings are resolved at runtime with linear/holder matching Startup and request routing cost stays higher than needed
No build-time index SPI for mappings Future precomputation work has no safe landing path
Google Doc 4.2 listed this as 8.1+ architecture Needs a starter that preserves runtime fallback

What changed

Area Change
Index properties Add UrlMappingsIndexProperties for optional META-INF/grails/url-mappings-index.properties
Runtime holder Hook DefaultUrlMappingsHolder to prefer index data when present
Fallback Existing runtime mapping behavior remains when no index exists
Docs / tests Upgrade note + fallback-path unit coverage

Out of scope / follow-up

Topic Status
Full trie/routing precomputation 8.1+
Reverse-routing table generation Follow-up
AST transform writing the index at compile time Follow-up

Related MD topics

Source Topic
Google Doc 4.2 URL mapping pre-computation
Status map Not covered / defer -> starter now

Contributor Checklist

Issue and Scope

  • Starter PR for future architecture; no acknowledged issue required for discussion.
  • Runtime behavior preserved without an index.
  • Single focused seed change.
  • Targets 8.0.x as an experimental starter for 8.1 work.

Code Quality

  • Tests cover the fallback path.
  • Focused module tests run locally.
  • No mass reformatting.
  • Generative AI starting point; labeled.

Licensing and Attribution

  • Apache License 2.0.
  • Contributor rights confirmed.
  • ai-generated-starting-point label applied.

Documentation

  • Upgrade note added.
  • PR description explains scope.

Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]

Add UrlMappingsIndexProperties and load path with fallback to runtime UrlMappingsHolder behavior.

Assisted-by: Sisyphus:xai/grok-4.5 [gpt-coding]

Copilot AI 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.

Pull request overview

This PR introduces an initial SPI “landing pad” for future build-time URL-mappings indexing by reserving a descriptor location and exposing its presence to the runtime URL mappings holder, while preserving the existing runtime URL-matching behavior. It also adds an upgrade-note doc page and a unit test validating the “no index present” fallback path.

Changes:

  • Added UrlMappingsIndexProperties to load optional META-INF/grails/url-mappings-index.properties from the classpath.
  • Wired DefaultUrlMappingsHolder to load/expose the descriptor and emit a debug message when it’s present.
  • Added upgrade documentation and a unit test for the missing-descriptor fallback behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsIndexProperties.java New classpath descriptor loader for future URL mappings index metadata.
grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/DefaultUrlMappingsHolder.java Loads and exposes the descriptor; logs when present while keeping runtime routing behavior.
grails-web-url-mappings/src/test/groovy/org/grails/web/mapping/UrlMappingsIndexPropertiesSpec.groovy Adds fallback-path coverage when the descriptor is absent.
grails-doc/src/en/guide/upgrading/urlMappingsPrecompute.adoc Documents the reserved descriptor location and current runtime behavior.
grails-doc/src/en/guide/toc.yml Adds the new upgrade note page to the guide TOC.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +45 to +61
public static UrlMappingsIndexProperties load(ClassLoader classLoader) {
ClassLoader loader = classLoader == null ? Thread.currentThread().getContextClassLoader() : classLoader;
if (loader == null) {
return EMPTY;
}
try (InputStream inputStream = loader.getResourceAsStream(LOCATION)) {
if (inputStream == null) {
return EMPTY;
}
Properties properties = new Properties();
properties.load(inputStream);
return new UrlMappingsIndexProperties(true, properties);
}
catch (IOException e) {
throw new IllegalStateException("Unable to load " + LOCATION, e);
}
}
@bito-code-review

Copy link
Copy Markdown

The current implementation of UrlMappingsIndexProperties.load(ClassLoader) prioritizes the provided classloader over the thread context classloader (TCCL), which can prevent discovery of application-packaged resources. Additionally, Properties.load(InputStream) can throw IllegalArgumentException for malformed content, which is not currently handled.

To address these issues, it is recommended to:

  1. Update the load method to check the TCCL first, falling back to the provided classloader if necessary.
  2. Wrap both IOException and IllegalArgumentException in a consistent exception type (e.g., IllegalStateException) to ensure robust error handling.

grails-web-url-mappings/src/main/groovy/org/grails/web/mapping/UrlMappingsIndexProperties.java

public static UrlMappingsIndexProperties load(ClassLoader classLoader) {
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        if (loader == null) {
            loader = classLoader;
        }
        if (loader == null) {
            return EMPTY;
        }
        try (InputStream inputStream = loader.getResourceAsStream(LOCATION)) {
            if (inputStream == null) {
                return EMPTY;
            }
            Properties properties = new Properties();
            properties.load(inputStream);
            return new UrlMappingsIndexProperties(true, properties);
        }
        catch (IOException | IllegalArgumentException e) {
            throw new IllegalStateException("Unable to load " + LOCATION, e);
        }
    }

@codecov

codecov Bot commented Jul 10, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 37.03704% with 17 lines in your changes missing coverage. Please review.
✅ Project coverage is 49.5383%. Comparing base (b00e83e) to head (97b5cc9).
⚠️ Report is 8 commits behind head on 8.0.x.

Files with missing lines Patch % Lines
...grails/web/mapping/UrlMappingsIndexProperties.java 34.7826% 11 Missing and 4 partials ⚠️
...g/grails/web/mapping/DefaultUrlMappingsHolder.java 50.0000% 1 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##                8.0.x     #15956        +/-   ##
==================================================
- Coverage     49.5403%   49.5383%   -0.0020%     
- Complexity      16922      16926         +4     
==================================================
  Files            1999       2000         +1     
  Lines           93754      93780        +26     
  Branches        16420      16423         +3     
==================================================
+ Hits            46446      46457        +11     
- Misses          40145      40156        +11     
- Partials         7163       7167         +4     
Files with missing lines Coverage Δ
...g/grails/web/mapping/DefaultUrlMappingsHolder.java 69.0021% <50.0000%> (-0.1628%) ⬇️
...grails/web/mapping/UrlMappingsIndexProperties.java 34.7826% <34.7826%> (ø)

... and 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Jul 10, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 97b5cc9
▶️ Tests: 12015 executed
⚪️ Checks: 61/61 completed


Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

2 participants