Skip to content

feat: Add support for JDK21 Sequenced Collections. #3708

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

BeomSeogKim
Copy link
Contributor

This PR resolves issue #3659 by adding support for JDK 21's Sequenced Collections.

Description

JEP 431 introduced new SequencedCollection, SequencedSet, and SequencedMap interfaces in JDK 21. When a mock method with one of these return types was unstubbed, Mockito would previously return null instead of an empty collection.

Implementation Details

To address this while maintaining Java 11 compatibility, ReturnsEmptyValues has been updated. The key changes are:

A new private method, returnValueForSequencedCollection, was introduced to handle the reflection-based checks in isolation.

private Object returnValueForSequencedCollection(Class<?> type) {
    String typeName = type.getName();
    if ("java.util.SequencedCollection".equals(typeName)) {
        return new ArrayList<>();
    } else if ("java.util.SequencedSet".equals(typeName)) {
        return new LinkedHashSet<>();
    } else if ("java.util.SequencedMap".equals(typeName)) {
        return new LinkedHashMap<>();
    }
    // Return null to allow other checks to proceed.
    return null;
}

This method is called at the beginning of returnValueFor to prioritize these special version-specific checks.

Object returnValueFor(Class<?> type) {
    // 1. Handle special Sequenced Collections first.
    Object sequencedCollection = returnValueForSequencedCollection(type);
    if (sequencedCollection != null) {
        return sequencedCollection;
    }

    // ... rest of the code

Fixes #3659

Checklist

  • Read the contributing guide
  • PR should be motivated, i.e. what does it fix, why, and if relevant how
  • If possible / relevant include an example in the description, that could help all readers
    including project members to get a better picture of the change
  • Avoid other runtime dependencies
  • Meaningful commit history ; intention is important please rebase your commit history so that each
    commit is meaningful and help the people that will explore a change in 2 years
  • The pull request follows coding style (run ./gradlew spotlessApply for auto-formatting)
  • Mention Fixes #<issue number> in the description if relevant
  • At least one commit should end with Fixes #<issue number> if relevant

JEP 431 introduced new Sequenced Collection interfaces in JDK 21.
Previously, unstubbed methods returning these types would result in null.

This changes allow Mockito appropriate empty collections (e.g. ArrayList for SequencedCollection) while maintaining the Java 11 baseline compatability.

Fixes mockito#3659

Signed-off-by: BeomSeogKim <kbs4520@daum.net>
@@ -176,6 +176,33 @@ public void should_return_empty_duration() throws Exception {
assertEquals("seconds of empty " + fqcn, 0L, seconds);
}

@Test
public void should_return_empty_sequenced_collection_on_java21() throws Exception {
Class<?> sequencedCollectionClass = getClassOrSkipTest("java.util.SequencedCollection");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mockito/developers I wonder if we should split this test for each JDK?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can use Assume.assumeThat for this: https://github.com/search?q=repo%3Amockito%2Fmockito+assumeThat&type=code However, let's do that in a follow-up PR to keep things manageable.

@BeomSeogKim do you mind picking that up next?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the follow up PR.
#3711

Thanks for the kindness review.

Copy link
Contributor

@TimvdLippe TimvdLippe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@@ -176,6 +176,33 @@ public void should_return_empty_duration() throws Exception {
assertEquals("seconds of empty " + fqcn, 0L, seconds);
}

@Test
public void should_return_empty_sequenced_collection_on_java21() throws Exception {
Class<?> sequencedCollectionClass = getClassOrSkipTest("java.util.SequencedCollection");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we can use Assume.assumeThat for this: https://github.com/search?q=repo%3Amockito%2Fmockito+assumeThat&type=code However, let's do that in a follow-up PR to keep things manageable.

@BeomSeogKim do you mind picking that up next?

@codecov-commenter
Copy link

codecov-commenter commented Aug 15, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.43%. Comparing base (ad6ae2f) to head (365802d).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #3708      +/-   ##
============================================
+ Coverage     86.42%   86.43%   +0.01%     
- Complexity     2964     2969       +5     
============================================
  Files           341      341              
  Lines          9000     9011      +11     
  Branches       1105     1110       +5     
============================================
+ Hits           7778     7789      +11     
  Misses          941      941              
  Partials        281      281              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@TimvdLippe TimvdLippe merged commit 144751b into mockito:main Aug 15, 2025
18 checks passed
svc-squareup-copybara pushed a commit to cashapp/misk that referenced this pull request Aug 15, 2025
| Package | Type | Package file | Manager | Update | Change |
|---|---|---|---|---|---|
| [org.mockito:mockito-core](https://github.com/mockito/mockito) |
dependencies | misk/gradle/libs.versions.toml | gradle | minor |
`5.18.0` -> `5.19.0` |
|
[com.google.api-client:google-api-client](https://github.com/googleapis/google-api-java-client)
| dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.8.0` -> `2.8.1` |
| [com.datadoghq:dd-trace-api](https://github.com/datadog/dd-trace-java)
| dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`1.52.0` -> `1.52.1` |
| [software.amazon.awssdk:sdk-core](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:sqs](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:regions](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
|
[software.amazon.awssdk:dynamodb-enhanced](https://aws.amazon.com/sdkforjava)
| dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:dynamodb](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:aws-core](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:bom](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |
| [software.amazon.awssdk:auth](https://aws.amazon.com/sdkforjava) |
dependencies | misk/gradle/libs.versions.toml | gradle | patch |
`2.32.22` -> `2.32.23` |

---

### Release Notes

<details>
<summary>mockito/mockito (org.mockito:mockito-core)</summary>

### [`v5.19.0`](https://github.com/mockito/mockito/releases/tag/v5.19.0)

<sup><sup>*Changelog generated by [Shipkit Changelog Gradle
Plugin](https://github.com/shipkit/shipkit-changelog)*</sup></sup>

##### 5.19.0

- 2025-08-15 - [37
commit(s)](mockito/mockito@v5.18.0...v5.19.0)
by Adrian-Kim, Tim van der Lippe, Tran Ngoc Nhan, dependabot\[bot],
juyeop
- feat: Add support for JDK21 Sequenced Collections.
[(#&#8203;3708)](mockito/mockito#3708)
- Bump actions/checkout from 4 to 5
[(#&#8203;3707)](mockito/mockito#3707)
- build: Allow overriding 'Created-By' for reproducible builds
[(#&#8203;3704)](mockito/mockito#3704)
- Bump org.assertj:assertj-core from 3.27.3 to 3.27.4
[(#&#8203;3703)](mockito/mockito#3703)
- Bump androidx.test:runner from 1.6.2 to 1.7.0
[(#&#8203;3697)](mockito/mockito#3697)
- Bump org.junit.platform:junit-platform-launcher from 1.13.3 to 1.13.4
[(#&#8203;3694)](mockito/mockito#3694)
- Bump com.diffplug.spotless:spotless-plugin-gradle from 7.1.0 to 7.2.1
[(#&#8203;3693)](mockito/mockito#3693)
- Bump junit-jupiter from 5.13.3 to 5.13.4
[(#&#8203;3691)](mockito/mockito#3691)
- Bump com.gradle.develocity from 4.0.2 to 4.1
[(#&#8203;3689)](mockito/mockito#3689)
- Bump com.google.googlejavaformat:google-java-format from 1.27.0 to
1.28.0 [(#&#8203;3688)](mockito/mockito#3688)
- Bump com.google.googlejavaformat:google-java-format from 1.25.2 to
1.27.0 [(#&#8203;3686)](mockito/mockito#3686)
- Bump com.diffplug.spotless:spotless-plugin-gradle from 7.0.4 to 7.1.0
[(#&#8203;3685)](mockito/mockito#3685)
- Bump junit-jupiter from 5.13.2 to 5.13.3
[(#&#8203;3684)](mockito/mockito#3684)
- Bump org.shipkit:shipkit-auto-version from 2.1.0 to 2.1.2
[(#&#8203;3683)](mockito/mockito#3683)
- Bump com.diffplug.spotless:spotless-plugin-gradle from 7.0.2 to 7.0.4
[(#&#8203;3682)](mockito/mockito#3682)
- Only run release after both Java and Android tests have finished
[(#&#8203;3681)](mockito/mockito#3681)
- Bump org.junit.platform:junit-platform-launcher from 1.12.2 to 1.13.3
[(#&#8203;3680)](mockito/mockito#3680)
- Bump org.codehaus.groovy:groovy from 3.0.24 to 3.0.25
[(#&#8203;3679)](mockito/mockito#3679)
- Bump org.eclipse.platform:org.eclipse.osgi from 3.23.0 to 3.23.100
[(#&#8203;3678)](mockito/mockito#3678)
- Can no longer publish snapshot releases
[(#&#8203;3677)](mockito/mockito#3677)
- Update Gradle to 8.14.2
[(#&#8203;3676)](mockito/mockito#3676)
- Bump errorprone from 2.23.0 to 2.39.0
[(#&#8203;3674)](mockito/mockito#3674)
- Correct Junit docs link
[(#&#8203;3672)](mockito/mockito#3672)
- Bump net.ltgt.gradle:gradle-errorprone-plugin from 4.1.0 to 4.3.0
[(#&#8203;3670)](mockito/mockito#3670)
- Bump junit-jupiter from 5.13.1 to 5.13.2
[(#&#8203;3669)](mockito/mockito#3669)
- Bump bytebuddy from 1.17.5 to 1.17.6
[(#&#8203;3668)](mockito/mockito#3668)
- Bump junit-jupiter from 5.12.2 to 5.13.1
[(#&#8203;3666)](mockito/mockito#3666)
- Bump org.jetbrains.kotlin:kotlin-stdlib from 2.0.21 to 2.2.0
[(#&#8203;3665)](mockito/mockito#3665)
- Bump org.gradle.toolchains.foojay-resolver-convention from 0.9.0 to
1.0.0 [(#&#8203;3661)](mockito/mockito#3661)
- Bump org.junit.platform:junit-platform-launcher from 1.11.4 to 1.12.2
[(#&#8203;3660)](mockito/mockito#3660)
- Add JDK21 sequenced collections for ReturnsEmptyValues
[(#&#8203;3659)](mockito/mockito#3659)
- Bump com.gradle.develocity from 3.19.1 to 4.0.2
[(#&#8203;3658)](mockito/mockito#3658)
- Bump ru.vyarus:gradle-animalsniffer-plugin from 1.7.2 to 2.0.1
[(#&#8203;3657)](mockito/mockito#3657)
- Bump org.eclipse.platform:org.eclipse.osgi from 3.22.0 to 3.23.0
[(#&#8203;3656)](mockito/mockito#3656)
- Bump org.codehaus.groovy:groovy from 3.0.23 to 3.0.24
[(#&#8203;3655)](mockito/mockito#3655)
- Bump junit-jupiter from 5.11.4 to 5.12.2
[(#&#8203;3653)](mockito/mockito#3653)
- Reproducible Build: need to inject JDK distribution details to rebuild
[(#&#8203;3563)](mockito/mockito#3563)

</details>

<details>
<summary>googleapis/google-api-java-client
(com.google.api-client:google-api-client)</summary>

###
[`v2.8.1`](https://github.com/googleapis/google-api-java-client/blob/HEAD/CHANGELOG.md#281-2025-08-14)

##### Bug Fixes

- **deps:** Update project.http.version to v2
([#&#8203;2598](googleapis/google-api-java-client#2598))
([4874da1](googleapis/google-api-java-client@4874da1))

</details>

<details>
<summary>datadog/dd-trace-java (com.datadoghq:dd-trace-api)</summary>

###
[`v1.52.1`](https://github.com/DataDog/dd-trace-java/releases/tag/v1.52.1):
1.52.1

### Components

#### Application Security Management (WAF)

- 🐛 Fix NullPointerException log in AppSec
([#&#8203;9356](DataDog/dd-trace-java#9356) -
[@&#8203;jandro996](https://github.com/jandro996))

#### Continuous Integration Visibility

- ✨⚡ Do not follow symlinks by default when building
repository index
([#&#8203;9322](DataDog/dd-trace-java#9322) -
[@&#8203;nikita-tkachenko-datadog](https://github.com/nikita-tkachenko-datadog))

#### GraalVM native-image

- 🐛 Update GraalVM config to reflect TempLocationManager's new
package
([#&#8203;9338](DataDog/dd-trace-java#9338) -
[@&#8203;luneo7](https://github.com/luneo7) - thanks for the
contribution!)

#### Profiling

- 🐛 Properly handle trace agent IPv6 URL in profiling
([#&#8203;9339](DataDog/dd-trace-java#9339) -
[@&#8203;jbachorik](https://github.com/jbachorik))

#### Realtime User Monitoring

- ✨ Support async servlet for RUM injection
([#&#8203;9343](DataDog/dd-trace-java#9343) -
[@&#8203;amarziali](https://github.com/amarziali))
- 🐛 Improve RUM injection matching and avoid truncating responses
([#&#8203;9342](DataDog/dd-trace-java#9342) -
[@&#8203;amarziali](https://github.com/amarziali))
- ✨ Make rum injector stream/writer more resilient to errors
([#&#8203;9340](DataDog/dd-trace-java#9340) -
[@&#8203;amarziali](https://github.com/amarziali))

#### Tracer core

- 🐛 Avoid NPE on featureDiscovery creation
([#&#8203;9354](DataDog/dd-trace-java#9354) -
[@&#8203;amarziali](https://github.com/amarziali))

</details>

---

### Configuration

📅 **Schedule**: Branch creation - "after 6pm every weekday,before 2am
every weekday" in timezone Australia/Melbourne, Automerge - At any time
(no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Never, or you tick the rebase/retry checkbox.

👻 **Immortal**: This PR will be recreated if closed unmerged. Get
[config help](https://github.com/renovatebot/renovate/discussions) if
that's undesired.

---

- [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check
this box

---

This PR has been generated by [Renovate
Bot](https://github.com/renovatebot/renovate).

GitOrigin-RevId: 74bf02ba96add7578dbd1f225449c2f86de0c99d
BeomSeogKim added a commit to BeomSeogKim/mockito that referenced this pull request Aug 18, 2025
…ard `Assume.assumeThat` utility for conditional execution.

Follow-up to mockito#3708

Signed-off-by: BeomSeogKim <kbs4520@daum.net>
BeomSeogKim added a commit to BeomSeogKim/mockito that referenced this pull request Aug 18, 2025
…ard `Assume.assumeThat` utility for conditional execution.

Follow-up to mockito#3708

Signed-off-by: BeomSeogKim <kbs4520@daum.net>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add JDK21 sequenced collections for ReturnsEmptyValues
4 participants