In REST Assured, which settings control how JsonPath materialises JSON numbers?
answer
- four values, one default
- decimals and integers move separately
- the same pair on two classes
- a cap measured in characters
- negative switches the cap off
basics
~20 sREST Assured's numberReturnType controls how JSON numbers are materialised, with four values: FLOAT_AND_DOUBLE (the default), BIG_DECIMAL, DOUBLE and BIG_INTEGER. Set it on JsonConfig for the DSL or JsonPathConfig standalone. Both also cap numeric literals via numberLengthLimit.
solid answer
~50 sTwo settings, mirrored on two classes. `numberReturnType` decides the Java type of a parsed number and has exactly four values: `FLOAT_AND_DOUBLE` (the default — a decimal becomes a `Float`, or a `Double` above `Float.MAX_VALUE`), `BIG_DECIMAL`, `DOUBLE`, and `BIG_INTEGER`, which converts whole numbers rather than decimals. `numberLengthLimit`, added in 6.0.1, caps a single numeric literal at **1000 characters** by default and throws when a token is longer; a negative value disables the check. Where you set them depends on which side you are on: `JsonPathConfig` for a standalone `JsonPath` — through `using(...)` or the static `JsonPath.config` — and `JsonConfig` inside `RestAssuredConfig` for the DSL, applied globally via `RestAssured.config`, on a spec builder, or per request with `given().config(...)`. The two sides are independent, which is the first thing to check when a configuration change appears to have had no effect at all.
code
java · 11 linesRestAssured.config = RestAssured.config()
.jsonConfig(jsonConfig()
.numberReturnType(NumberReturnType.BIG_DECIMAL)
.numberLengthLimit(200));
get("/glossaries/ui-strings")
.then()
.body("glossary.entry[0].confidence", is(new BigDecimal("0.82")));
JsonPath standalone = new JsonPath(rawBody)
.using(jsonPathConfig().numberReturnType(NumberReturnType.BIG_DECIMAL));go deeper
Recall that the number model is configurable and that the default makes decimals arrive as Floats. Know the setting is called numberReturnType and that four values exist.
Explain what each value does and, crucially, that BIG_DECIMAL touches decimals while BIG_INTEGER touches whole numbers. Be able to say where the setting lives on each side of the library.
Treat a model change as suite-wide. Show that you would land it in one commit, name the assertions it breaks, and explain the numberLengthLimit cap as a denial-of-service defence rather than a formatting knob.
Own the policy. Decide whether the estate standardises on one number model, where that setting is declared so nobody sets it twice, and under what conditions a team is allowed to relax the parser's limits.
## Two knobs, mirrored on two classes JSON has one number type; Java has several. Somebody has to choose, and in REST Assured that choice lives in two settings that appear twice — once on `JsonPathConfig`, which configures a standalone `JsonPath`, and once on `JsonConfig`, which is the wrapper that sits inside `RestAssuredConfig` and drives the `given()...then()` DSL. They carry the same two values and mean the same thing; only the entry point differs. ## numberReturnType — exactly four values | Value | Effect on a decimal such as 0.82 | Effect on a whole number such as 3 | |---|---|---| | `FLOAT_AND_DOUBLE` (default) | `Float`, or `Double` above `Float.MAX_VALUE` | left as `Integer` / `Long` | | `DOUBLE` | always `Double` | left as `Integer` / `Long` | | `BIG_DECIMAL` | left as the parser's `BigDecimal` | left as `Integer` / `Long` | | `BIG_INTEGER` | left as the parser's `BigDecimal` | converted to `BigInteger` | The mechanism is worth knowing because it explains the asymmetry. The parser underneath is a copy of Groovy's slurper, and it produces a `BigDecimal` for every non-integer literal and an `Integer` or `Long` for whole numbers. REST Assured then post-processes: - Under the two float-ish modes it narrows the `BigDecimal` by calling `floatValue()` or `doubleValue()`. - Under `BIG_DECIMAL` it does nothing, so you keep the parser's own value. - Under `BIG_INTEGER` it leaves decimals alone and instead widens `Integer` and `Long` results. So `BIG_DECIMAL` and `BIG_INTEGER` are not two halves of one "big numbers" mode — they touch opposite halves of the payload, and switching to `BIG_INTEGER` breaks every `equalTo(3)` in a suite while leaving the decimals exactly as they were. ## numberLengthLimit — a denial-of-service cap, added in 6.0.1 A JSON document can contain a numeric literal thousands of digits long. Parsing one into an arbitrarily large `BigInteger` is quadratic in CPU and heap, which made oversized literals a cheap denial-of-service against anything parsing untrusted JSON. 6.0.1 added a cap: - The default limit is **1000 characters**, matching the equivalent default in Jackson's stream-read constraints. - A longer token throws a parse exception whose message names both the token length and the configured limit, and points at the setting. - A **negative** value disables the check entirely. - The setting exists on both `JsonPathConfig` and `JsonConfig`, and is the only reason most suites will ever touch either class. Raising it is reasonable when you deliberately test very large numbers; disabling it in a suite that points at anything you do not control is not. ## Where to set them ```java // DSL-wide RestAssured.config = RestAssured.config() .jsonConfig(jsonConfig().numberReturnType(NumberReturnType.BIG_DECIMAL)); // one request only given().config(RestAssured.config().jsonConfig(jsonConfig().numberReturnType(BIG_DECIMAL))) .when().get("/glossaries/ui-strings"); // a standalone JsonPath JsonPath path = new JsonPath(rawBody) .using(jsonPathConfig().numberReturnType(NumberReturnType.BIG_DECIMAL)); ``` The two sides do not see each other. Setting `RestAssured.config` does not change how a `JsonPath` you constructed yourself behaves, and setting the static `JsonPath.config` does not change what the DSL does. That split surprises people who set one and assert through the other, and it is the first thing to check when a configuration change appears to have had no effect. ## Choosing a model for a real suite For a translation-glossary API whose entries carry a `confidence` score, the practical questions are: 1. **Does exactness matter?** If the test asserts a band — confidence above 0.5 — the default is fine and costs nothing. If it asserts a stored decimal exactly, `BIG_DECIMAL` removes the binary-representation argument from every future discussion. 2. **Who else reads these values?** A model change is global to everything the configuration covers, so it lands on every assertion at once. Make it deliberately, in one commit, with the suite green before and after. 3. **Is any of this JSON untrusted?** If a test can be pointed at an environment you do not own, leave `numberLengthLimit` alone. When you do choose `BIG_DECIMAL`, build the expected value from a **string** — `new BigDecimal("0.82")` — because `BigDecimal.equals` compares scale as well as value, and constructing one from a `double` gives you the binary approximation you were trying to avoid. ## Mistakes this surface produces - Setting the model on one side and asserting through the other, then concluding the setting is broken. - Reading `numberLengthLimit` as a precision or rounding control. It counts characters in a token and discards nothing; it either admits the literal or throws. - Assuming `BIG_DECIMAL` and `BIG_INTEGER` are two spellings of the same idea, and switching between them when an assertion fails. - Turning the length cap off globally because one fixture carries a long literal, rather than raising it for that one configuration. - Comparing a `BigDecimal` built from a `double` against a parsed one and blaming the parser for the scale mismatch that follows.
- You set RestAssured.config but a standalone JsonPath still returns Floats. Why?The two configurations are independent. `RestAssured.config` feeds the `given()...then()` pipeline through `JsonConfig`; a `JsonPath` you constructed yourself reads its own `JsonPathConfig`, supplied through `using(...)` or the static `JsonPath.config`. Set whichever side the code under test actually uses.
- Why does switching to BIG_INTEGER break assertions that BIG_DECIMAL leaves alone?They act on opposite halves of the payload. `BIG_DECIMAL` affects decimals only, leaving whole numbers as `Integer` or `Long`. `BIG_INTEGER` leaves decimals alone and converts whole numbers to `BigInteger`, so every `equalTo(3)` in the suite stops matching while every decimal assertion is untouched.
saying these in an interview costs you the question
- Thinking BIG_DECIMAL and BIG_INTEGER affect the same values
- Expecting the DSL config to reach a standalone JsonPath
- Treating numberLengthLimit as a digit-precision setting
- Disabling the length cap on a suite that parses untrusted JSON
- Building an expected BigDecimal from a double literal