Skip to content
This repository was archived by the owner on Jul 7, 2026. It is now read-only.
This repository was archived by the owner on Jul 7, 2026. It is now read-only.

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

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!

Activity

  1. Awakuruf commented on Mar 6, 2026

    @Awakuruf
    Author

    Any help would be much appreciated @marcingrzejszczak

  2. marcingrzejszczak commented on Mar 6, 2026

    @marcingrzejszczak
    Contributor

    If you're doing consumer contract approach the fact that the consumer drops the requirement doesn't imply anything from the point of view of the producer. If other consumers require the field the producer must keep it. I don't understand the problem.

  3. Awakuruf commented on Mar 6, 2026

    @Awakuruf
    Author

    @marcingrzejszczak

    If you're doing consumer contract approach the fact that the consumer drops the requirement doesn't imply anything from the point of view of the producer. If other consumers require the field the producer must keep it. I don't understand the problem.

    Because provider has only one single consumer, the problem this causes would be that actual provider implementation (DTO) and contract will be out of sync.

    As I mentioned, SCC regenerates provider tests, dateTime is no longer asserted.

    • The provider side verification expects this to fail because there is a mismatch between it's own implementation (it still contains dateTime in it's DTO) and the contract (it no longer contains dateTime in the contract).
    • The regenerated test no longer contains assertThatJson() for dateTime anymore so it passes silently.
    • The provider continues serializing dateTime in every response.
    • The discrepancy goes undetected because there is no test case to check for deleted fields.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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