Skip to content

How to detect dead code fields in provider DTOs when using Spring Cloud Contract (bidirectional contract-DTO sync)? #2434

@Awakuruf

Description

@Awakuruf

I'm implementing consumer-driven contract testing with Spring Cloud Contract (SCC) on a Spring Boot provider service. I've identified a gap in the standard verification approach: SCC only validates that fields declared in the contract are present in the provider response. It does not detect provider DTO fields that consumers have silently dropped from their contracts.

The Problem
Consider this contract lifecycle:

// v1: Consumer contract expects "dateTime"
response {
    body(
        id: "123",
        dateTime: "2025-01-15T10:30:00Z",
        clientId: "cid-123"
    )
}

// v2: Consumer removes "dateTime" — no longer needed
response {
    body(
        id: "123",
        clientId: "cid-123"
    )
}

After dateTime is removed from the contract:

  1. SCC regenerates provider tests, dateTime is no longer asserted
  2. The provider DTO still declares dateTime
  3. The regenerated test passes silently
  4. The provider continues serializing dateTime in every response
  5. The discrepancy goes undetected

This silently accumulates technical debt:

  • Dead DTO fields: Provider maintains fields no consumer uses
  • False confidence: All tests pass, DTO and contract are out of sync

My Current Approach
I implemented a supplementary ContractFieldVerificationTest that runs alongside the standard SCC-generated tests. It:

  1. Parses SCC-generated test source files to extract asserted fields (using regex patterns targeting various assertThatJson() styles)
  2. Reflects on provider DTO class hierarchies to collect all non-static instance fields
  3. Compares bidirectionally:
  • Dead code: fields in DTO but absent from contract assertions
  • Missing implementation: fields in contract assertions but absent from DTO

Example failure output:

DEAD CODE: 1 field(s) in DTO but not in contract:
  - dateTime
ACTION REQUIRED: Remove from ResponseDTO.java or add back to the consumer contract

The test file content is cached via @BeforeAll to avoid redundant I/O, and the contracts directory is resolved dynamically to be resilient to consumer version changes.

The Concern

A teammate has raised that parsing generated test source files as a verification signal is a clumsy approach, coupling test verification to generated code internals that could change with any SCC version upgrade.

Question
Is there an established, idiomatic approach for bidirectional contract-DTO synchronization in Spring Cloud Contract that avoids parsing generated sources?
Specifically:

  • Does SCC offer a strict body-matching mode that would fail if the provider returns fields not declared in the contract (similar to Pact's PactVerifyProvider with strict matching)?
  • Is there a StubRunnerExtension hook or a custom ContractVerifierConfigurer that could intercept response serialization for this purpose?
  • Would switching to Pact be more appropriate here, given its richer support for explicit field-level matching rules?
  • Alternatively, is there a pattern using Jackson @JsonIgnoreProperties(allowGetters=false) or a custom serialization filter that could enforce DTO-contract alignment at the framework level rather than at the test level?

Any guidance on the idiomatic approach, or confirmation that source-parsing is an acceptable trade-off, would be appreciated!

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions