skip to content

URI Building (UriComponentsBuilder)

UriComponentsBuilder assembles URIs with correct encoding and template expansion instead of string concatenation. Interviewers care because hand-built URLs are where encoding bugs and open redirects come from.

part ofSpring Frameworkoverview, primer and where to startread it →
on this pageshow

questions

5

What is UriComponentsBuilder and why use it instead of string concatenation to build URLs?

level: juniorimportance: must knowfreq 32%

answer

  1. fluent immutable builder for URIs
  2. no string concat -> correct encoding
  3. scheme/host/path/queryParam/fragment
  4. {placeholders} + buildAndExpand
  5. build() -> immutable UriComponents

basics

~20 s

UriComponentsBuilder is a Spring helper that builds a URI piece by piece — scheme, host, path, query params — and handles proper encoding for you. It avoids bugs from manually gluing strings and forgetting to escape special characters.

solid answer

~40 s

UriComponentsBuilder is Spring's fluent, immutable builder for constructing URIs safely. You set parts with methods like scheme(), host(), port(), path(), queryParam(), and fragment(), then call build() to get an immutable UriComponents, and toUriString() or toUri() for the result. It supports URI templates with {placeholders} that you fill via buildAndExpand(...) or expand(...), and it applies correct percent-encoding so values with spaces, ampersands, or non-ASCII characters don't break the URL or open injection issues. Compared with string concatenation, it prevents classic mistakes: missing slashes, un-encoded query values, double question marks, and malformed queries. Common entry points are UriComponentsBuilder.fromUriString(...), fromPath(...), and the request-aware subclass ServletUriComponentsBuilder. It's the idiomatic way to generate links and Location headers in Spring MVC.

code

java · 13 lines
java
import org.springframework.web.util.UriComponentsBuilder;

// Build: /users/42?tag=spring%20mvc
String uri = UriComponentsBuilder
        .fromPath("/users/{id}")
        .queryParam("tag", "spring mvc")   // space gets percent-encoded
        .buildAndExpand(42)                 // fills {id}
        .toUriString();

// A prebuilt UriComponents is immutable and reusable:
var template = UriComponentsBuilder.fromUriString("https://api.example.com/users/{id}").build();
String u1 = template.expand(1).toUriString();
String u2 = template.expand(2).toUriString();

go deeper

for a junior

Know it builds URIs safely with proper encoding and offers a fluent scheme/host/path/queryParam API instead of concatenating strings.

for a middle

Know the template-variable flow (path('/x/{id}') + buildAndExpand) and that build() yields an immutable, reusable UriComponents.

for a senior

Distinguish build() vs build(true) vs buildAndExpand, and know RestTemplate/WebClient use the same URI-template machinery under the hood.

for a principal

Frame it as the single sanctioned URL-construction primitive to standardize on, eliminating ad-hoc concatenation and its encoding/injection risks across the codebase.

## What it is `UriComponentsBuilder` (package `org.springframework.web.util`) is Spring's fluent, **immutable** builder for assembling a URI from its individual components rather than by concatenating strings. Building a URI by hand — e.g. `"http://" + host + "/users?name=" + name` — is fragile: you forget slashes, you forget to percent-encode the query value, a `name` containing `&` or a space silently produces a broken or ambiguous URL, and you risk URL-injection. ## Core API You obtain a builder from a static factory and then chain component setters: - `UriComponentsBuilder.newInstance()` — empty builder. - `UriComponentsBuilder.fromUriString("http://host/path?q=1")` — parse an existing URI string. - `UriComponentsBuilder.fromPath("/users")` — start from a path. - `UriComponentsBuilder.fromHttpUrl(...)` / `fromUri(URI)` — other entry points. Component setters (each returns the same mutable builder for chaining): `scheme("https")`, `host("example.com")`, `port(8080)`, `path("/users")`, `pathSegment("a","b")`, `queryParam("name", value)`, `queryParams(MultiValueMap)`, `fragment("section")`, `userInfo(...)`. Terminal calls: - `build()` -> returns an immutable `UriComponents`. - `build(true)` -> declares that the components you supplied are **already encoded** (don't re-encode). - `buildAndExpand(Object... values)` / `buildAndExpand(Map)` -> build and fill `{placeholders}` in one step. - `toUriString()` -> the `String` form; `toUri()` -> a `java.net.URI`. ## URI templates Any component can contain template variables in braces: `.path("/users/{id}")`. You supply the value later via `buildAndExpand(42)` or `build().expand(42)`. Spring substitutes and encodes the value. This separation (template now, values later) is what makes encoding correct and reusable. ## Immutability gotcha `UriComponents` (the result of `build()`) is immutable and reusable — safe to cache and expand repeatedly with different variables. The builder itself is mutable; don't share one across threads. ## When to use it Any time you generate a URL server-side: `Location` headers after a POST, links in emails/responses, calling another service with `RestTemplate`/`WebClient` (both accept URI templates and use this machinery internally), or building redirect targets. The request-aware subclass `ServletUriComponentsBuilder` derives scheme/host/port/context from the current HTTP request. ## Quick example `UriComponentsBuilder.fromPath("/users/{id}").queryParam("active", true).buildAndExpand(42).toUriString()` -> `/users/42?active=true`. ## Common mistakes it prevents - Un-encoded query values (space -> `%20`, `&` inside a value -> `%26`). - Missing/duplicate `/` when joining base and path. - Malformed query strings (`?` vs `&`). - Reusing a base URL string in many places with copy-paste errors.

  • What is the difference between build() and buildAndExpand()?
    build() returns a UriComponents that may still contain {placeholders}; buildAndExpand(values) additionally substitutes those template variables with the given values (and encodes them) in one call. You can also do build().expand(values) separately.
  • Is a UriComponentsBuilder thread-safe?
    No. The builder is mutable and not thread-safe. The UriComponents object returned by build() is immutable, so that result can be safely shared and expanded repeatedly.

saying these in an interview costs you the question

  • Claiming string concatenation is fine as long as you 'remember to encode' — you rarely do, and reserved chars differ per component.
  • Thinking UriComponents (result of build()) is mutable — it is immutable.
  • Believing UriComponentsBuilder automatically knows the current request's host — only ServletUriComponentsBuilder does.

context

open as a page

How do you build an absolute Location URL from the current request, e.g. for a 201 Created response?

level: middleimportance: must knowfreq 38%

basics

~10 s

Use ServletUriComponentsBuilder.fromCurrentRequest() (or fromCurrentContextPath()), append the new resource path, expand the id, and call toUri(). It reads the current request's scheme, host, and port so you don't hardcode them.

open as a page

How does encoding interact with URI template expansion in UriComponentsBuilder, and why does the order matter?

level: seniorimportance: should knowfreq 28%

basics

~20 s

You must encode after (or as part of) expansion, because the values you substitute may contain reserved characters like & or /. The safest approach is UriComponentsBuilder.encode() with EncodingMode.TEMPLATE_AND_VALUES, which encodes the template literals and then strictly encodes each expanded variable.

open as a page

What is MvcUriComponentsBuilder.fromMethodCall / fromMethodName and why is it useful?

level: seniorimportance: should knowfreq 18%

basics

~10 s

MvcUriComponentsBuilder builds URLs by pointing at a controller method instead of typing its path. fromMethodCall(on(Ctrl.class).getUser(id)) reads the method's @GetMapping and reconstructs the URL, so if you change the mapping the link updates automatically.

open as a page

When generating absolute URLs behind a reverse proxy, how do forwarded headers affect ServletUriComponentsBuilder, and what are the security implications?

level: principalimportance: should knowfreq 16%

basics

~20 s

Behind a proxy the app sees the internal host, so generated URLs are wrong unless it reads Forwarded / X-Forwarded-* headers. Registering Spring's ForwardedHeaderFilter makes ServletUriComponentsBuilder use them. But those headers are client-controllable, so only trust them behind a trusted proxy to avoid host-header/link poisoning.

open as a page