skip to content

Path Patterns & Variables

How URLs are matched: the modern PathPattern parser versus legacy Ant matching, plus templated variables, regex constraints and wildcards. It comes up whenever a scenario has overlapping routes and you must say which one wins.

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

questions

5

How do you capture a dynamic segment from a URL in a Spring MVC controller, and how do you read its value?

level: juniorimportance: must knowfreq 85%

answer

  1. Curly braces {id} in mapping
  2. @PathVariable binds it
  3. -parameters flag lets you drop the name
  4. Bad type = 400, no match = 404
  5. Required by default

basics

~10 s

Put a placeholder in curly braces in the mapping, like /users/{id}, then bind it with @PathVariable on a method parameter. Spring extracts that URL segment and passes it into your method.

solid answer

~40 s

You declare a URI template variable in the mapping path using curly braces — e.g. @GetMapping("/users/{id}"). Then a method parameter annotated @PathVariable("id") receives the captured value, converted to the parameter type (String, Long, UUID, etc.) via Spring's type conversion. If the parameter name matches the template name and you compile with -parameters, you can drop the explicit name: @PathVariable Long id. Multiple variables are fine: /orders/{orderId}/items/{itemId}. By default a @PathVariable is required — a missing value yields an error. You can make it optional with required=false (giving null) or by using Optional<T>. A common gotcha: type conversion failure (e.g. non-numeric id for Long) produces a 400 Bad Request, not a 404.

code

java · 16 lines
java
@RestController
@RequestMapping("/api")
public class OrderController {

    @GetMapping("/orders/{orderId}/items/{itemId}")
    public Item getItem(@PathVariable Long orderId,
                        @PathVariable Long itemId) {
        return service.find(orderId, itemId);
    }

    // Grab all template variables at once
    @GetMapping("/users/{id}")
    public User getUser(@PathVariable Map<String, String> vars) {
        return service.byId(vars.get("id"));
    }
}

go deeper

for a junior

Must know the {id} + @PathVariable pairing and how to read the value. Core everyday MVC skill.

for a middle

Should also know the 400-vs-404 distinction and the -parameters name-matching rule.

for a senior

Frames path variables vs query params as a resource-modeling choice; knows conversion pipeline and Optional/required semantics.

for a principal

Discusses API-design conventions, type-safety, and how binding failures surface to clients consistently across the codebase.

## What a path (URI template) variable is A **URI template variable** (also called a path variable) is a named placeholder inside a request mapping path, written in curly braces: `{id}`. When a request URL matches the pattern, Spring extracts the text occupying that segment and makes it available to your handler method. ```java @RestController public class UserController { @GetMapping("/users/{id}") public User get(@PathVariable Long id) { ... } } ``` For `GET /users/42`, Spring captures `42`, converts it to `Long`, and passes it in. ## The @PathVariable annotation `@PathVariable` binds a method parameter to a URI template variable. Key points: - **Name resolution**: `@PathVariable("id")` names the template explicitly. If you compile Java with the `-parameters` flag (Spring Boot enables this), the annotation name can be omitted and the parameter name is used: `@PathVariable Long id`. Without `-parameters`, the parameter name is lost at runtime and you must supply the name. - **Type conversion**: The captured string is converted to the declared type using Spring's `ConversionService` / registered `Converter`s and `Formatter`s. Built-in support covers `String`, all numeric types, `boolean`, `UUID`, enums, and anything with a registered converter. A conversion failure (e.g. `abc` for a `Long`) throws `MethodArgumentTypeMismatchException`, which resolves to **HTTP 400 Bad Request**. - **Required by default**: A `@PathVariable` is mandatory. Because the variable is part of the URL pattern itself, a truly absent segment usually means the URL didn't match at all (404). You can mark it `required = false` or use `Optional<T>`; this mainly matters when the same variable is optional across composed patterns. ## Multiple variables and a Map ```java @GetMapping("/orders/{orderId}/items/{itemId}") public Item item(@PathVariable Long orderId, @PathVariable Long itemId) { ... } ``` You can also grab all of them at once: ```java @GetMapping("/orders/{orderId}/items/{itemId}") public Item item(@PathVariable Map<String, String> vars) { String orderId = vars.get("orderId"); } ``` ## Common gotchas - **400 vs 404**: A wrong *type* (non-numeric for `Long`) is a 400. A URL that matches no pattern is a 404. Don't confuse them. - **Dots and slashes in values**: By default, the path is split on `/`, so a variable can't span multiple segments unless you use a wildcard pattern. Values containing dots historically caused truncation with suffix pattern matching; with modern `PathPattern` and suffix matching disabled by default this is a non-issue. - **Encoding**: `@PathVariable` values are URL-decoded before binding. ## When to use Use path variables for **resource identifiers** that are part of the resource hierarchy (`/users/42`). Use query parameters (`@RequestParam`) for filters, sorting, and optional criteria (`/users?active=true`).

  • What HTTP status results if a client calls /users/abc and the handler declares @PathVariable Long id?
    400 Bad Request. Spring can't convert 'abc' to Long, throwing MethodArgumentTypeMismatchException, which the default handler maps to 400 — not a 404.
  • When can you omit the name in @PathVariable id?
    When the code is compiled with the -parameters flag so the parameter name survives at runtime, and that name matches the template variable. Spring Boot enables -parameters by default.

context

open as a page

How do you constrain a path variable to a specific format, e.g. only digits or a fixed pattern?

level: middleimportance: should knowfreq 55%

basics

~20 s

Add a regex after a colon inside the braces: {id:[0-9]+} matches only digits. Spring uses the regex to decide whether the URL matches that segment, so non-matching URLs fall through to other mappings or 404.

open as a page

Explain the wildcard tokens in Spring path patterns: ?, *, and **. How do they differ and where can each appear?

level: seniorimportance: should knowfreq 50%

basics

~20 s

? matches exactly one character within a segment. * matches zero or more characters within a single path segment (no slash). ** matches zero or more whole segments and, under PathPattern, must be the last element. You can capture ** with {*name}.

open as a page

Compare PathPatternParser with the legacy AntPathMatcher. Why did Spring switch defaults, and what behavioral differences should you know?

level: principalimportance: should knowfreq 40%

basics

~20 s

AntPathMatcher parses patterns as strings on every request; PathPatternParser pre-compiles each pattern once into a reusable PathPattern, so matching is much faster. PathPatternParser is the modern default and adds {*name} capture, but restricts ** to the pattern's end.

open as a page

What are matrix variables in Spring MVC, how do you bind them with @MatrixVariable, and what must be configured to use them?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

Matrix variables are semicolon-separated name=value pairs attached to a path segment, like /cars;color=red;year=2020. You bind them with @MatrixVariable. In Spring MVC they're stripped by default, so you must enable them by turning off URL-path removeSemicolonContent.

open as a page