googleapis / googleapis/google-cloud-java
[Testing] Mockito fails with ArrayStoreException on JDK 8 due to JSpecify TYPE_USE annotations
- Lingua principale
- Java
- Stelle
- 2.1k
- Fork
- 1.2k
- Merge medio
- 1g 23h
- PR unite (30g)
- 154
Descrizione
**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](https://github.com/googleapis/google-cloud-java/pull/13702)
[#13612](https://github.com/googleapis/google-cloud-java/pull/13612)
[#13621](https://github.com/googleapis/google-cloud-java/pull/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.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Start by running the Maven testing phase on JDK 8 with a generated Stub or Client class using JSpecify annotations and a standard Mockito mock. Compare the failing declaration-based mock with Mockito.mock(..., Mockito.withSettings().withoutAnnotations()). The issue names no target file or acceptance criteria, so the intended fix and definition of done need clarification.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- java
- Ambito
- testing-qa
- Tipo di issue
- Bug
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Da chiarire
- Idoneità per principianti
- 35/100