What is UriComponentsBuilder and why use it instead of string concatenation to build URLs?
answer
- fluent immutable builder for URIs
- no string concat -> correct encoding
- scheme/host/path/queryParam/fragment
- {placeholders} + buildAndExpand
- build() -> immutable UriComponents
basics
~20 sUriComponentsBuilder 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 sUriComponentsBuilder 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 linesimport 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
Know it builds URIs safely with proper encoding and offers a fluent scheme/host/path/queryParam API instead of concatenating strings.
Know the template-variable flow (path('/x/{id}') + buildAndExpand) and that build() yields an immutable, reusable UriComponents.
Distinguish build() vs build(true) vs buildAndExpand, and know RestTemplate/WebClient use the same URI-template machinery under the hood.
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.