What is RepresentationModel and EntityModel<T> in Spring HATEOAS, and why would you use EntityModel instead of adding links directly to your DTO?
answer
- RepresentationModel = base link-carrier
- EntityModel.of(content, links) wraps single item
- content unwrapped in HAL + _links block
- extend vs wrap: coupling trade-off
- linkTo(methodOn(...)).withSelfRel()
basics
~10 sRepresentationModel is the base class that carries hypermedia links. EntityModel<T> wraps a single domain object plus its links, so you can attach links without changing or extending your original DTO class.
solid answer
~40 sSpring HATEOAS models a response as a payload plus hypermedia links. `RepresentationModel<T>` is the base type that holds a list of `Link` objects and exposes `add(...)`, `getLinks()`, `getLink(rel)`. You can extend it to bake links into your own DTO, but that couples the DTO to HATEOAS. `EntityModel<T>` avoids that: it is a ready-made `RepresentationModel` whose `content` is your untouched domain object. You create it with `EntityModel.of(order, linkTo(...).withSelfRel())`. In HAL JSON it serializes the object's fields at the top level alongside a `_links` block. Use `EntityModel` when you want to keep DTOs plain and add links at the controller/assembler layer; extend `RepresentationModel` only when the resource is a first-class hypermedia type you fully own.
code
java · 11 linesimport org.springframework.hateoas.EntityModel;
import static org.springframework.hateoas.server.mvc.WebMvcLinkBuilder.*;
@GetMapping("/orders/{id}")
public EntityModel<Order> one(@PathVariable Long id) {
Order order = repository.findById(id).orElseThrow();
return EntityModel.of(order,
linkTo(methodOn(OrderController.class).one(id)).withSelfRel(),
linkTo(methodOn(OrderController.class).all()).withRel("orders"));
}
// HAL output: { "id":42, "total":9.99, "_links": { "self": {"href":"/orders/42"}, "orders": {"href":"/orders"} } }go deeper
Know EntityModel wraps one object + links and RepresentationModel is the base link carrier.
Explain the extend-vs-wrap coupling trade-off and HAL unwrapping of content.
Discuss assembler-layer link building and keeping DTOs HATEOAS-free.
Weigh dedicated resource types vs generic wrappers across an API's evolution and client contract stability.
**Hypermedia / HATEOAS context.** HATEOAS (Hypermedia As The Engine Of Application State) is a REST constraint where responses include *links* telling the client what it can do next, instead of clients hardcoding URLs. Spring HATEOAS is the library that helps you build these link-carrying responses. **`RepresentationModel<T>`** is the foundational base class. It is essentially "a thing that can carry a collection of `org.springframework.hateoas.Link` objects." Its API: - `add(Link)` / `add(Iterable<Link>)` — attach links; returns the model (self-referential generic `T`, a CRTP pattern, so calls chain and return the subclass type). - `getLinks()`, `getLink(String rel)` / `getRequiredLink(rel)` — read links. - `hasLink(rel)`, `removeLinks()`. You use it in two ways: 1. **Extend it** to make your own DTO hypermedia-aware: `class OrderModel extends RepresentationModel<OrderModel> { ... fields ... }`. The DTO's fields serialize at the top level plus a `_links` block. Downside: your DTO now depends on Spring HATEOAS. 2. **Use a prebuilt wrapper** — `EntityModel<T>`. **`EntityModel<T>`** extends `RepresentationModel<EntityModel<T>>` and adds a single `content` property of type `T`. It lets you attach links to *any* object without touching that object's class. Factory methods: - `EntityModel.of(T content)` - `EntityModel.of(T content, Link... links)` - `EntityModel.of(T content, Iterable<Link>)` (Older code used the deprecated `new Resource<>(...)`; the modern factory is `EntityModel.of(...)`.) **Serialization (HAL).** With the default HAL media type (`application/hal+json`), an `EntityModel<Order>` renders the Order's JSON fields at the top level and adds a `_links` object keyed by relation (rel) name, e.g. `"self": { "href": "/orders/42" }`. The `content` wrapper itself is *unwrapped* — clients see the order fields directly, not nested under `content`. **Building links.** Links usually come from `WebMvcLinkBuilder.linkTo(...)` / `methodOn(...)`, e.g. `linkTo(methodOn(OrderController.class).one(id)).withSelfRel()`. The `.withSelfRel()` / `.withRel("customer")` sets the relation name. **When to use which.** - Plain DTO + `EntityModel.of(...)` at the controller/assembler layer → keeps domain/DTO classes free of HATEOAS. This is the common, recommended default. - Extend `RepresentationModel` when the type *is* a dedicated resource representation you own and want strongly typed (e.g. a purpose-built API model), or when you need extra behavior. **Gotchas.** - Don't confuse `EntityModel` (single item) with `CollectionModel` (many). - `EntityModel.of(...)` is the current factory; `new EntityModel<>(...)` constructor is not the intended API and `Resource`/`Resources` are the old renamed types. - The generic on `RepresentationModel<T extends RepresentationModel<T>>` is self-referential purely so `add()` returns your concrete subtype for fluent chaining — it is not the content type.
- What does the self-referential generic `RepresentationModel<T extends RepresentationModel<T>>` buy you?It makes `add(...)` and similar mutators return the concrete subtype `T` rather than the base class, so fluent chaining preserves your type — the CRTP (curiously recurring template pattern).
- How does an EntityModel<Order> look different in HAL JSON from just returning the Order?The Order fields appear at the top level exactly the same, but an extra `_links` object is added. The `content` wrapper itself is not visible — it is unwrapped.
saying these in an interview costs you the question
- Thinking EntityModel nests the payload under a "content" key in HAL (it is unwrapped)
- Believing you must extend RepresentationModel to add links (EntityModel avoids that)
- Confusing EntityModel (single) with CollectionModel (many)