Override Changes Nullability Contract

ID

java.method_overrides_change_contracts

Severity

high

Remediation Complexity

medium

Remediation Risk

low

Remediation Effort

medium

Resource

Code Smell

Language

Java

Tags

best-practice, reliability

Description

Reports an overriding method that tightens a @Nullable parameter to @Nonnull, or loosens a @Nonnull return value to @Nullable, relative to the superclass method it overrides.

Rationale

Code holding a reference typed as the superclass relies on the nullability contract that class advertises. If an override secretly requires a non-null argument where the superclass accepted null, or starts returning null where the superclass promised it never would, a caller that only knows about the superclass contract can be handed a subclass instance and break at runtime — exactly the kind of substitution failure the Liskov substitution principle warns about.

class Cache {
    void put(@Nullable String value) {
        // accepts null
    }
}

class StrictCache extends Cache {
    @Override
    void put(@Nonnull String value) { // Bad -- narrower than what Cache promises
        // ...
    }
}

Remediation

Keep the override’s contract at least as permissive as the superclass: accept whatever the superclass accepts, and promise to return at least what the superclass promises.

class Cache {
    void put(@Nullable String value) {
        // accepts null
    }
}

class StrictCache extends Cache {
    @Override
    void put(@Nullable String value) { // Good -- honors the inherited contract
        if (value != null) {
            // ...
        }
    }
}

© 2026 Xygeni. All rights reserved