In Spring HATEOAS, how do you build a self link to a controller method, and what does the resulting Link contain?
answer
- linkTo(methodOn(Ctrl.class).method(args))
- methodOn = recording proxy
- .withSelfRel() → rel 'self'
- href from current request base URL
- add to EntityModel/RepresentationModel
basics
~10 sUse WebMvcLinkBuilder: linkTo(methodOn(MyController.class).getItem(id)).withSelfRel(). It returns a Link with an href (the URL Spring built from the mapping) and the relation 'self'.
solid answer
~30 sSpring HATEOAS provides the static helpers WebMvcLinkBuilder.linkTo(...) and methodOn(...). You write linkTo(methodOn(ItemController.class).getItem(id)).withSelfRel(). methodOn returns a recording proxy that captures which method you 'called' and its arguments; linkTo reads that recorded call plus the controller's @RequestMapping/@GetMapping metadata to construct the URL, substituting path variables (like {id}) from the arguments. withSelfRel() stamps the relation name 'self' (IanaLinkRelations.SELF). The result is an immutable org.springframework.hateoas.Link holding an href and a rel. You typically add it to a RepresentationModel/EntityModel so it serializes into HAL as {"_links":{"self":{"href":"..."}}}. The href is absolute and derived from the current request's base URL, so you never hardcode paths.
code
java · 21 linesimport static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.linkTo;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.methodOn;
import org.springframework.hateoas.EntityModel;
import org.springframework.hateoas.Link;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/items")
class ItemController {
@GetMapping("/{id}")
EntityModel<Item> getItem(@PathVariable Long id) {
Item item = new Item(id, "Widget");
Link self = linkTo(methodOn(ItemController.class).getItem(id)).withSelfRel();
return EntityModel.of(item, self);
// HAL: {"id":1,"name":"Widget","_links":{"self":{"href":"http://host/items/1"}}}
}
}
record Item(Long id, String name) {}go deeper
Know the exact idiom linkTo(methodOn(Ctrl.class).method()).withSelfRel() and that it yields a Link with an href and rel 'self'.
Explain that methodOn is a recording proxy and linkTo reads mapping metadata plus request base URL to build the href.
Discuss path-variable substitution, HAL serialization under _links, and the request-context requirement.
Frame link building as decoupling clients from URL structure and enabling evolvable hypermedia APIs.
Spring HATEOAS turns your REST responses into hypermedia by attaching **links** — URLs plus a **relation** ("rel") that names what the link means (self, next, the orders collection, etc.). Instead of hardcoding URL strings, you build links from your controller mappings so URLs stay correct even if you change a @RequestMapping path. **The two key static methods** (from `org.springframework.hateoas.server.mvc.WebMvcLinkBuilder`, usually static-imported): - `methodOn(Class, args...)` returns a **proxy** of your controller. You then 'invoke' the target method on this proxy — e.g. `methodOn(ItemController.class).getItem(42L)`. Nothing real runs; the proxy simply **records** which method was called and with which arguments (implemented via `DummyInvocationUtils`). - `linkTo(...)` takes that recorded invocation and produces a `WebMvcLinkBuilder`. It inspects the controller's mapping annotations (`@RequestMapping` at class level, `@GetMapping`/`@RequestMapping` on the method), fills in `@PathVariable` placeholders like `{id}` from the recorded arguments, and resolves the **base URI** from the current HTTP request (scheme, host, port, context path via `ServletUriComponentsBuilder`). **Turning a builder into a Link:** the builder is not itself a `Link`. You call: - `.withSelfRel()` → a `Link` with rel `self`. - `.withRel("orders")` or `.withRel(IanaLinkRelations.NEXT)` → a `Link` with a named rel. A `org.springframework.hateoas.Link` is **immutable** and mainly holds an `href` (String) and a `LinkRelation`. **Where the link goes:** you add links to a model object — `EntityModel.of(item, selfLink)`, or a class extending `RepresentationModel<>` via `model.add(link)`. When serialized with the HAL media type (`application/hal+json`), links appear under `_links` keyed by their rel. **Why it matters:** the href is computed from live request context, so the same code yields correct absolute URLs in dev, staging, and prod without configuration. **Common gotcha:** `linkTo`/`methodOn` need an active request thread (they read `RequestContextHolder`); calling them outside a request (some async or plain unit-test paths) fails unless you provide a request context.
- Why use linkTo(methodOn(...)) instead of just writing the URL string "/items/" + id?It derives the URL from the controller's mapping and the live request base URL, so links stay correct when paths change or when the app runs under a different host/context path, and it fills path variables safely.
- What object type does withSelfRel() return, and is it mutable?It returns an immutable org.springframework.hateoas.Link. Methods like withRel produce new Link instances rather than mutating.
saying these in an interview costs you the question
- Thinking methodOn actually executes the controller method (it only records the invocation).
- Believing withSelfRel() returns a String URL rather than a Link object.
- Assuming linkTo hardcodes localhost instead of reading the current request base URL.