skip to content

Representation Models

EntityModel, CollectionModel and PagedModel wrap your payloads so links can travel alongside the data. The basic vocabulary for any hypermedia answer.

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

explore

questions

4

What is RepresentationModel and EntityModel<T> in Spring HATEOAS, and why would you use EntityModel instead of adding links directly to your DTO?

level: juniorimportance: must knowfreq 70%

answer

  1. RepresentationModel = base link-carrier
  2. EntityModel.of(content, links) wraps single item
  3. content unwrapped in HAL + _links block
  4. extend vs wrap: coupling trade-off
  5. linkTo(methodOn(...)).withSelfRel()

basics

~10 s

RepresentationModel 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 s

Spring 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 lines
java
import 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

for a junior

Know EntityModel wraps one object + links and RepresentationModel is the base link carrier.

for a middle

Explain the extend-vs-wrap coupling trade-off and HAL unwrapping of content.

for a senior

Discuss assembler-layer link building and keeping DTOs HATEOAS-free.

for a principal

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)

context

open as a page

What is CollectionModel<T> and how does it differ from returning a plain list? What does its HAL output look like?

level: middleimportance: should knowfreq 55%

basics

~10 s

CollectionModel<T> wraps a collection of items so the whole collection can carry its own hypermedia links (like a self link). In HAL the items go under _embedded and collection-level links under _links.

open as a page

What is PagedModel<T>, how does it differ from CollectionModel, and how do you build one from a Spring Data Page?

level: seniorimportance: should knowfreq 50%

basics

~10 s

PagedModel<T> is a CollectionModel that also carries page metadata (size, totalElements, totalPages, number) and navigation links (first/prev/next/last). You usually build it from a Spring Data Page using PagedResourcesAssembler.toModel(page, assembler).

open as a page

Design decision: when should you extend RepresentationModel<T> for your own type versus wrapping domain objects in EntityModel<T>/CollectionModel<T>? What are the trade-offs?

level: principalimportance: nice to knowfreq 30%

basics

~20 s

Extend RepresentationModel when you own a dedicated, strongly-typed API model and want compile-time fields plus links in one class. Wrap with EntityModel/CollectionModel to keep domain/DTO classes free of HATEOAS and add links only at the edge.

open as a page