In REST Assured, what does as(ScaffoldInspection.class, ObjectMapperType.GSON) do that as(ScaffoldInspection.class) does not?
answer
- two arguments, one decision skipped
- the response header is never read
- absent mapper throws, never falls back
- erasure is untouched by naming a mapper
basics
~20 sREST Assured's two-argument as() names the reader outright, so the response Content-Type is never consulted; the one-argument form derives the mapper from that header instead. A named mapper missing from the classpath throws IllegalArgumentException rather than falling back.
solid answer
~40 s`extract().as(ScaffoldInspection.class)` asks REST Assured to work out the reader from the response's `Content-Type`: a body labelled `application/json` reaches a JSON mapper, one labelled `application/xml` an XML mapper, and anything containing neither substring fails. The two-argument overload `as(ScaffoldInspection.class, ObjectMapperType.GSON)` short-circuits that — internally REST Assured passes no content type at all into the mapping step, so the header is never read and the named mapper is used whatever the server labelled the body. Two consequences follow. If the named mapper is not on the classpath you get `IllegalArgumentException` naming it; there is no silent fallback to a different one. And if a default `ObjectMapper` instance has been installed globally on `ObjectMapperConfig`, that instance still wins over the type you named. Use the two-argument form to pin a reader deliberately, not as a habit.
code
java · 13 linesimport io.restassured.mapper.ObjectMapperType;
import static io.restassured.RestAssured.given;
// two JSON mappers are on the classpath; pin the one this DTO is annotated for
ScaffoldInspection inspection = given()
.header("X-Site", "SITE-4417")
.when()
.get("/inspections/INSP-2024-0917")
.then()
.statusCode(200)
.extract()
.as(ScaffoldInspection.class, ObjectMapperType.GSON);go deeper
Know the two shapes and what separates them: one argument means the response Content-Type picks the reader, two arguments means you did. Remember that the named mapper must actually be on the classpath.
Explain that the overload passes no content type into the mapping step at all, so the header is skipped rather than overridden, and that erasure is untouched — as(List.class, GSON) still yields maps.
Argue for the default. A content-type failure is signal that a service is mislabelling responses; pinning a mapper at every call site hides that, so justify each use as a classpath or annotation-coupling decision.
Set the house rule. Decide whether the suite pins mappers at all, or standardises on one mapper in the build and lets content-type selection do the work, and make that choice visible so it is not relitigated per test.
REST Assured's read-side `as(...)` has two everyday shapes, and the difference between them is not which mapper runs but *who decides* which mapper runs. ## What the one-argument form does `extract().as(ScaffoldInspection.class)` on `GET /inspections/INSP-2024-0917` asks the library to derive a reader. REST Assured resolves the response's content type and tests it: a type containing `json` sends the body to whichever JSON mapper is on the classpath, a type containing `xml` to an XML one, and a type containing neither — `text/plain`, say — produces `IllegalStateException` complaining that no supported `Content-Type` was present. The server's label is in charge. That is the right default. It means a suite that talks to a well-behaved service never mentions a mapper at all, and it means the same test keeps working when an endpoint is renegotiated from XML to JSON. ## What the second argument changes `extract().as(ScaffoldInspection.class, ObjectMapperType.GSON)` takes the decision away from the response. Internally REST Assured passes **no** content type into the mapping step for this overload, so the header is not consulted and cannot fail the call. The value you pass names a mapper family directly, and that mapper reads the body regardless of how the server labelled it. What this buys you, in order of how often it actually matters: - **Pinning a reader when several are on the classpath.** A build that drags in more than one JSON mapper transitively will otherwise use whichever the classpath scan finds first, which can change under you when a dependency is bumped. - **Reading a mislabelled body without touching global state.** Because the header is skipped, this is a per-call answer to a `text/plain` body carrying JSON — no `registerParser`, no `defaultParser`, nothing that outlives the test. - **Matching a DTO to the mapper it was written for.** If the type carries annotations that only one mapper family understands, saying so at the call site documents the coupling. ## What it does not change The overload is narrower than it looks: | Concern | Affected by the second argument? | |---|---| | Which mapper reads the body | Yes — that is the whole point | | Whether the response `Content-Type` is read | Yes — it is skipped entirely | | Generic element types | No — `Class` still erases; use `TypeRef` | | A globally installed default `ObjectMapper` instance | No — that instance is checked first and still wins | | Whether validation ran before extraction | No — that is decided by where `extract()` sits in the chain | The third row is the one that trips people up. `as(List.class, ObjectMapperType.GSON)` still hands back one map per array element, because naming a mapper does nothing about erasure. There is also no `as(TypeRef, ObjectMapperType)` overload; a generic container plus a named mapper means passing `typeRef.getType()` into the `as(Type, ObjectMapperType)` form. ## Failure behaviour is strict, on purpose Naming a mapper that is not on the classpath does not degrade gracefully: 1. REST Assured checks the named family against the classpath. 2. If it is absent, it throws `IllegalArgumentException` whose message names the mapper it could not find. 3. It does **not** fall through to another mapper, and it does not fall back to the content-type route it skipped. This is deliberate. A silent fallback would mean a dependency change quietly swapping the reader under a passing test, which is exactly the ambiguity the overload exists to remove. The loud failure is the feature. ## Related call forms on the read side Four overloads sit next to each other and are worth being able to tell apart in an interview: - `as(Class)` — reader from the response content type. - `as(Class, ObjectMapperType)` — reader named by enum constant; content type skipped. - `as(Class, ObjectMapper)` — an `ObjectMapper` *instance* you supply, called directly; the registry and the selection logic are both bypassed. - `as(TypeRef<T>)` — solves erasure, but resolves its reader from the content type exactly as `as(Class)` does. The `Type`-taking mirrors of the first three exist too, which is how a `TypeRef` is combined with a named mapper. ## When to reach for it Default to the one-argument form. It keeps the test honest about what the service claims to return, and a content-type failure is genuinely useful signal: it usually means the service is mislabelling something. Reach for the two-argument form when you have a specific reason — a contested classpath, a per-call workaround you do not want to make global, or a DTO whose annotations bind it to one mapper family. Reaching for it reflexively hides real problems behind a mapper name, and it makes every one of those call sites something a future reader has to justify.
- What happens if the ObjectMapperType you name is not on the classpath?REST Assured throws `IllegalArgumentException` and the message names the mapper it could not find. It does not fall back to another mapper, and it does not revert to the content-type route it skipped. The strictness is intentional: a silent fallback would let a dependency bump swap the reader under a still-passing test.
- How does as(Class, ObjectMapper) differ from as(Class, ObjectMapperType)?The enum names a mapper family and lets REST Assured build it from the configured factory. The `ObjectMapper` overload takes an instance you constructed yourself and calls it directly, so the classpath scan, the content-type decision and the configured factories are all bypassed. Use it when the mapper needs configuration REST Assured does not expose.
saying these in an interview costs you the question
- Believing an absent named mapper silently falls back to another one
- Thinking the second argument also fixes generic element types
- Claiming as(Class, ObjectMapperType) still validates the response Content-Type
- Reaching for the two-argument form by default instead of on purpose
- Confusing the ObjectMapperType enum with an ObjectMapper instance