Hi devs,
I’d like us to generate every XWiki URL (pages, attachments, skins, webjars, tmp, users, exports…) through the Resource and URL modules, with the same per-format rules that already parse incoming URLs. XWikiURLFactory and its subclasses would become thin adapters over it, and could later be deprecated.
The full design is at https://design.xwiki.org/xwiki/bin/view/Proposal/URLSerialization
Why
- Parsing goes through the URL format, but generating doesn’t: there’s no serializer for pages and attachments, and the
urlnormalizer still returnsnull(XWIKI-17023). - The server URL logic exists twice in oldcore with different fallbacks, and XWIKI-24569 / PR #5855 would add a third copy behind a new
URLFactoryrole. - Serializers disagree on what they return: some add the context path, authentication doesn’t (its callers do), and user-resource returns an absolute URL from the old factory.
url.standard.hideViewAction, documented since 7.2M1, has no effect, because generation never readsStandardURLConfiguration. This proposal fixes it.
Proposal in short
URL generation becomes the exact inverse of parsing, in three stages:
- Resource (resource-api): what is addressed.
- URL format (url-scheme-*): how a reference is written in a path. Each (format, type) pair has a serializer and a resolver, tested for the round trip. The format returns the path from the webapp root, without the context path, plus the target wiki.
- Location (url-default, independent of the container): context path, server URL of the target wiki, and the three outputs (relative, absolute for the current request, canonical), through the
contextpath,urland newcanonicalurlnormalizers.
Callers don’t get a new role. They pick the kind of URL by picking the lookup:
ResourceReferenceSerializer<ResourceReference, ExtendedURL>: relative, with the context path (exists);ResourceReferenceSerializer<ResourceReference, URL>: absolute, for the current request (new);ResourceReferenceSerializer<ResourceReference, URL>with hintcanonical: absolute, using only the configuration (new). Reset password and emails use it.
Other notable points:
- Move
EntityResourceReference,EntityResourceAction,SkinsResourceReferenceandResourcesResourceReferencefrom resource-default to resource-api, so url-api stops depending on an implementation module. - Rename url-container to url-servlet, since its code is servlet-specific, and keep servlet code out of url-default behind one internal role.
- One server URL resolver in url-default, replacing the two copies in oldcore. PR #5855 would be closed in favor of this.
- Serializers that follow the new contract (no context path) get a distinct hint (
<format>/path). Existing extension serializers keep working unchanged. The old registrations of the platform serializers move to legacy, as was done forstandard/tmpin 14.7.
What could go wrong
- Code that calls the default serializer and then the
contextpathnormalizer for the authentication type would get the context path twice. Platform callers change in the same commit; extensions doing this need a release-notes entry. - Wikis that set
url.standard.hideViewAction=truewould start getting URLs without/view/(that’s the bug fix). - Webjars and tmp URLs containing a space would use
%20instead of+.
Questions
The design page lists 9 open questions. The ones I’d most like opinions on:
- Q5: stop reading the undocumented per-wiki
showviewaction/usedefaultactionpreferences (keeping thexwiki.cfgkeys as fallbacks)? - Q7:
canonical/canonicalurlas the hint names? - Q8: keep “relative if same host” in the oldcore adapter for now?
- Q9: a distinct hint for new-contract serializers, rather than detecting old ones heuristically?
WDYT?
Thanks
PS: This post was co-written with Claude Code.