Class RecordedExpectationPostProcessor

java.lang.Object
org.mockserver.persistence.RecordedExpectationPostProcessor

public class RecordedExpectationPostProcessor extends Object
Opt-in post-processing of recorded (proxy SPY/CAPTURE) expectations that (a) deduplicates structurally-identical recorded request/response pairs, keeping a single representative, and (b) templatizes variable path segments so that, for example, recorded calls to /users/1, /users/2 and /users/3 collapse into a single expectation that matches /users/{id} (a declared MockServer path parameter, which the matcher normalises to a .* regex segment).

This is a pure function over List<Expectation> so it can be tested in isolation and invoked from a recording/retrieve path without side effects. It is intentionally conservative:

  • Only HTTP requests with a concrete HttpResponse are considered; any other expectation (callbacks, forwards, OpenAPI matchers, etc.) is passed through unchanged and never merged.
  • A path segment is only treated as variable when it looks like an id — all digits, or a canonical UUID. Nothing else is collapsed.
  • A group of requests is only collapsed into one templated expectation when the non-variable parts (method, every fixed path segment, and the request body shape) match exactly, the variable segments occupy the same positions, and all responses in the group are equal. If responses differ, the group is left as distinct expectations (we never merge differing responses under one matcher).
  • Exact duplicates (same request signature and equal response) always collapse to a single expectation, even when there is no variable segment to templatize.

Order is preserved: the first expectation of each retained group keeps its original position in the output.

Value templatization (opt-in, additive). When the caller passes templatizeValues = true a second, equally-conservative generalisation runs on each retained expectation: volatile-looking query parameter, header and JSON body leaf values — ids, UUIDs, ISO-8601 or epoch-millis timestamps, and long opaque tokens (JWT / base64 / hex) — are replaced with regex matchers so the recorded expectation is reusable instead of pinned to one captured value. Stable values (short strings, words, booleans, enums, small numbers, common content-types) are preserved verbatim. The two-argument deduplicateAndTemplatize(List) overload keeps the historical path-only behaviour for full back-compat; value templatization only happens through deduplicateAndTemplatize(List, boolean) with the flag set (wired behind the templatizeRecordedValues configuration option).

  • Method Details

    • deduplicateAndTemplatize

      public static List<Expectation> deduplicateAndTemplatize(List<Expectation> expectations)
      Deduplicate and templatize a list of recorded expectations. Pure function: the input list and its elements are not mutated.
      Parameters:
      expectations - recorded expectations (may be null or empty)
      Returns:
      a new list with structurally-identical requests deduplicated and variable id path segments collapsed into templated expectations
    • deduplicateAndTemplatize

      public static List<Expectation> deduplicateAndTemplatize(List<Expectation> expectations, boolean templatizeValues)
      Deduplicate and templatize a list of recorded expectations. Pure function: the input list and its elements are not mutated.
      Parameters:
      expectations - recorded expectations (may be null or empty)
      templatizeValues - when true, also generalise volatile-looking query parameter, header and JSON body leaf values into regex matchers (ids, UUIDs, timestamps, tokens); when false those values are kept verbatim (historical, fully back-compatible behaviour)
      Returns:
      a new list with structurally-identical requests deduplicated, variable id path segments collapsed, and — when templatizeValues is set — volatile values generalised into matchers
    • consolidate

      public static List<Expectation> consolidate(List<Expectation> expectations, boolean parameterizeValues)
      Consolidate a list of recorded expectations into a compact set of reusable active mocks — the "record→mock" engine. This differs from deduplicateAndTemplatize(List, boolean) (which preserves the recorded Times/TimeToLive and emits one expectation per distinct response) in three deliberate ways, so the output is directly usable as long-lived mocks rather than a faithful replay of what was recorded:
      1. One expectation per request shape. All exchanges sharing a structural signature (method + templatized path shape + body shape) collapse into a single expectation. Where the group spans several concrete ids the varying id path segments become {id} path parameters (path inference); otherwise the concrete path is kept.
      2. Unlimited times/TTL. Every consolidated expectation is emitted with Times.unlimited() and TimeToLive.unlimited() so it keeps matching, replacing the recorded Times.once() that makes raw recordings brittle.
      3. Differing responses are sequenced. When the same request shape produced several distinct responses they are attached as a ResponseMode.SEQUENTIAL response list (first-seen order, de-duplicated) rather than fanned out into multiple competing expectations.
      Volatile request headers (reusing HarImporter.volatileRequestHeaders()) are always stripped from the generated matcher. When parameterizeValues is set, volatile-looking query parameter, header and JSON body leaf values are additionally generalised to regex matchers (the same heuristics used by deduplicateAndTemplatize(List, boolean)).

      Ineligible expectations (no concrete HttpResponse — callbacks, forwards, errors, OpenAPI matchers, etc.) are passed through unchanged in their original position. Pure function: the input and its elements are not mutated.

      Parameters:
      expectations - recorded expectations (may be null/empty)
      parameterizeValues - when true, also generalise volatile query parameter, header and JSON body leaf values
      Returns:
      the consolidated expectations