[Testing] Mockito fails with ArrayStoreException on JDK 8 due to JSpecify TYPE_USE annotations

未關閉
#13,708 2 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
4/5
預估耗時
3-5 天
新手友好度
35/100
Issue 類型
缺陷
描述清晰度
需要釐清
活躍度
冷清
技術堆疊
java
領域
testing-qa

研究方向

首先,在 JDK 8 上使用一個採用 JSpecify 註解的產生 Stub 或 Client 類別以及一個標準的 Mockito mock,執行 Maven 測試階段。將失敗的基於宣告的 mock 與 Mockito.mock(..., Mockito.withSettings().withoutAnnotations()) 進行比較。該 issue 未指定目標檔案或驗收標準,因此需要釐清預期的修正方案和 definition of done。

由索引模型根據 Issue 內容生成。

描述

priority: p3 type: bug

Description
Mockito tests running on Java 8 (JDK 1.8) crash with an ArrayStoreException / EnumConstantNotPresentExceptionProxy when attempting to mock generated Stub or Client classes that contain JSpecify annotations (@NullMarked or @Nullable).

Because JSpecify uses Type-Use (TYPE_USE) annotations, it triggers a known limitation in standard JDK 8 Java Reflection API. Standard JVM annotation parsers throw an ArrayStoreException when bytecode scanners (like ByteBuddy, underneath Mockito) introspect parameterized types, arrays, or generic descriptors holding Type-Use annotations.

Workaround
Handwritten tests aiming to maintain backwards compatibility with Java 8 while using JSpecify must explicitly disable annotation processing on mocked generated classes. Instead of standard @Mock Declaration annotations, instantiations must use:
Mockito.mock(MyStub.class, Mockito.withSettings().withoutAnnotations());.

This workaround has been successfully applied in the following integration PRs:

#13702
#13612
#13621

Reproducer
Steps to reproduce:

  1. Generate GAPIC veneers/stubs annotated with JSpecify @NullMarked or @Nullable (Type-Use).
  2. Write a handwritten unit test using Java 8 runtime.
  3. Instantiate standard Mockito mock for the generated class: MetricServiceStub mockStub = Mockito.mock(MetricServiceStub.class); or @Mock private MetricServiceStub mockStub;.
  4. Run tests and observe ArrayStoreException crash.

Code Snippets:

Failing Snippet (Standard/Declaration):

@Mock private MetricServiceStub mockMetricServiceStub; // Crashes on JDK 8
Bypass/Working Snippet (Programmatic without annotations):

private MetricServiceStub mockMetricServiceStub;

@Before
public void setUp() {
// Bypasses reflection parser crash
mockMetricServiceStub = Mockito.mock(
MetricServiceStub.class,
Mockito.withSettings().withoutAnnotations()
);
}

Logs and Stack Trace

org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class com.google.cloud.monitoring.v3.stub.MetricServiceStub.

Mockito can only mock non-private & non-final classes, but the root cause of this error might be different.
...
Caused by: java.lang.ArrayStoreException: sun.reflect.annotation.EnumConstantNotPresentExceptionProxy
at java.lang.Class.createAnnotationData(Class.java:3521)
at java.lang.Class.annotationData(Class.java:3510)
at java.lang.Class.getDeclaredAnnotations(Class.java:3477)

Behavior
When did the issue begin? Began following PR integrations introducing JSpecify Type-Use annotations (@NullMarked, @Nullable) to generated surfaces.
Is this behavior flaky? No, it is consistently seen during the Maven Testing Phase running specifically on JDK 1.8.

主要語言
Java
星號
2.1k
分支
1.2k
平均合併
2 天 14 小時
30 天內合併 PR
192

環境準備

  • 沒有 Dockerfile 或 Docker Compose 檔案
  • 沒有 Pull Request 範本
  • 閱讀貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

googleapis/google-cloud-java 的其他 Issue

查看 googleapis/google-cloud-java 的全部 Issue

相似的 Issue

更多 Java Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。