skip to content

What is the difference between Model, ModelMap, and ModelAndView, and how do controller model attributes reach the view?

level: juniorimportance: should knowfreq 55%

answer

  1. Model = interface, ModelMap = Map impl, ModelAndView = return object
  2. BindingAwareModelMap is what's injected
  3. attributes -> ModelAndViewContainer -> request attributes
  4. addAttribute(obj) auto-names by type
  5. Model is view-layer, not for REST

basics

~20 s

Model is an interface for adding named attributes to the view. ModelMap is a Map-based implementation of that idea. ModelAndView bundles the model AND the view name/object together as a return value. Attributes you add become variables the view template can render.

solid answer

~40 s

`Model` is the interface controllers usually declare as a parameter to expose attributes to the view (`model.addAttribute("user", u)`). `ModelMap` is a `LinkedHashMap`-based class implementing the same fluent add-attribute API; the concrete object Spring injects is `BindingAwareModelMap` (an `ExtendedModelMap`), which also implements `Model`. `ModelAndView` is different: it's a return-value object that packages both the model map and the view (a name resolved by a `ViewResolver`, or a `View` instance). Attributes travel in the `ModelAndViewContainer`; after the method returns, the `DispatcherServlet` exposes them to the chosen `View` for rendering (e.g. as request attributes for JSP/Thymeleaf). Prefer a `Model` parameter for readability; use `ModelAndView` when you want to set model and view in one returned object.

code

java · 18 lines
java
@Controller
class OrderController {

    // Style A: Model parameter (most common)
    @GetMapping("/orders/{id}")
    String show(@PathVariable Long id, Model model) {
        model.addAttribute("order", service.find(id)); // named explicitly
        return "orders/show"; // logical view name -> ViewResolver
    }

    // Style B: ModelAndView return (model + view in one object)
    @GetMapping("/orders")
    ModelAndView list() {
        ModelAndView mav = new ModelAndView("orders/list");
        mav.addObject("orders", service.all()); // auto/explicit naming
        return mav;
    }
}

go deeper

for a junior

Distinguish the three and know addAttribute exposes data to the view.

for a middle

Explain the shared BindingAwareModelMap, auto-naming, and the view-render copy to request attributes.

for a senior

Tie in @ModelAttribute methods/parameters and ModelMethodProcessor/MapMethodProcessor resolution.

for a principal

Advise on when Model is inappropriate (REST) and the redirect/flash boundary for model data.

### The three types - **`Model`** (`org.springframework.ui.Model`) — an interface with methods like `addAttribute(String, Object)`, `addAttribute(Object)` (auto-names by type), `addAllAttributes(...)`, `mergeAttributes(...)`, `containsAttribute(...)`. You declare it as a **method parameter**; Spring populates it and reads it back after invocation. - **`ModelMap`** (`org.springframework.ui.ModelMap`) — a concrete class extending `LinkedHashMap<String,Object>` that provides the same fluent `addAttribute` chaining. It is a `Map`, so it can be used where a map is expected. It does **not** implement `Model` by itself; the class that implements both is `ExtendedModelMap` (and its subclass `BindingAwareModelMap`, which is what Spring actually hands you). - **`ModelAndView`** (`org.springframework.web.servlet.ModelAndView`) — a **return type**, not a parameter. It holds a model map plus a *view*: either a logical **view name** (String, later run through the `ViewResolver` chain) or a concrete `View` object. Use it to return both in one object: `return new ModelAndView("orders", "order", order);`. ### How attributes flow to the view 1. Whatever you add (via a `Model`/`ModelMap` parameter, a returned `ModelAndView`, or an `@ModelAttribute`-annotated method) ends up in the **`ModelAndViewContainer`**. 2. When the handler returns a view name (or void with a `Model`), Spring resolves a `View` via `ViewResolver`s. 3. `View.render(model, request, response)` runs; for server-side templates the model entries are copied to **request attributes**, so a JSP/Thymeleaf/FreeMarker template can reference `${user}` etc. ### `@ModelAttribute` interactions - On a **method**: it runs before every handler in the controller and pre-populates the model (e.g. reference data for a form). - On a **parameter**: it binds request params onto an object and also adds it to the model under its attribute name — resolved by `ModelAttributeMethodProcessor`/`ServletModelAttributeMethodProcessor`. ### Which resolver injects a Model parameter `ModelMethodProcessor` supports `Model`; `MapMethodProcessor` supports raw `Map`/`ModelMap`. Both simply return the container's model, so all three parameter styles write to the *same* underlying map. ### Gotchas - The **injected object is mutable and shared** — all three parameter styles point at the same `BindingAwareModelMap`, so adding via `ModelMap` and via `Model` in the same method is additive, not conflicting. - `addAttribute(Object value)` **auto-generates the name** from the type (e.g. a `User` → `user`); a `null` or empty collection can throw or produce a surprising name, so prefer the explicit two-arg form. - Model attributes are **not** automatically added to a redirect URL — that's what `RedirectAttributes` is for. On a redirect, ordinary model attributes are appended as query parameters only if the redirect uses `RedirectView` expansion; flash attributes are the safe mechanism. - **`Model` is UI-layer**, tied to view rendering. For pure REST/`@ResponseBody` endpoints you typically don't use `Model` at all. ### When to use which - Declare a **`Model` parameter** for the common case (cleanest signature). - Return **`ModelAndView`** when branching logic must choose different views and set model data together. - Use **`ModelMap`** rarely — mainly when you need `Map` semantics or interop.

  • You call model.addAttribute(myUser) without a name. What key is used?
    Spring derives the name from the type via Conventions.getVariableName — a User becomes "user", a List<User> becomes "userList". Prefer the explicit two-arg form to avoid surprises and to survive obfuscation.

saying these in an interview costs you the question

  • Saying ModelAndView is a method parameter you inject
  • Claiming ModelMap implements Model (it's ExtendedModelMap/BindingAwareModelMap that does)
  • Thinking model attributes are automatically carried across a redirect

context