Skip to content

Fix InaccessibleObjectException when spying on JDK interfaces on JDK 16+#1457

Merged
Raibaz merged 3 commits intomasterfrom
copilot/fix-inaccessibleobjectexception
Dec 2, 2025
Merged

Fix InaccessibleObjectException when spying on JDK interfaces on JDK 16+#1457
Raibaz merged 3 commits intomasterfrom
copilot/fix-inaccessibleobjectexception

Conversation

Copy link
Contributor

Copilot AI commented Dec 1, 2025

Spying on JDK functional interfaces like Consumer fails on JDK 16+ with InaccessibleObjectException because MethodCall.call() unconditionally calls method.isAccessible = true on internal JDK lambda methods, which the module system blocks.

// This fails on JDK 16+ without --add-opens
val consumer = spyk<Consumer<String>> {
    every { this@spyk.accept(any()) } answers { /* ... */ }
}
consumer.andThen { /* ... */ }.accept("value")  // InaccessibleObjectException

Changes

  • MethodCall.kt: Wrap isAccessible call in try-catch, matching existing pattern in ProxyMaker.kt and InjectionHelpers.kt. Public methods on public interfaces invoke successfully without accessibility override.
  • JdkConsumerSpyTest.kt: Add regression tests for spying on JDK Consumer interface including andThen() chaining.
Original prompt

This section details on the original issue you should resolve

<issue_title>java.base does not "opens java.util.function" since 1.14.0</issue_title>
<issue_description>Appeared since version 1.14.0

Given:

val defaultConsumer = spyk<Consumer<RequestConfig.Builder>> {
            every { this@spyk.accept(any()) } returns Unit
        }

I get

java.lang.reflect.InaccessibleObjectException: Unable to make private void java.util.function.Consumer.lambda$andThen$0(java.util.function.Consumer,java.lang.Object) accessible: module java.base does not "opens java.util.function" to unnamed module @7f8a9499
	at java.base/java.lang.reflect.AccessibleObject.throwInaccessibleObjectException(AccessibleObject.java:391)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:367)
	at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:315)
	at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:203)
	at java.base/java.lang.reflect.Method.setAccessible(Method.java:197)
	at io.mockk.proxy.jvm.advice.MethodCall.call(MethodCall.kt:13)
	at io.mockk.proxy.jvm.advice.SelfCallEliminatorCallable.call(SelfCallEliminatorCallable.kt:14)
	at io.mockk.impl.instantiation.JvmMockFactoryHelper.handleOriginalCall(JvmMockFactoryHelper.kt:96)
	at io.mockk.impl.instantiation.JvmMockFactoryHelper.access$handleOriginalCall(JvmMockFactoryHelper.kt:19)
	at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1$invocation$1$1.invoke(JvmMockFactoryHelper.kt:28)
	at io.mockk.impl.stub.MockKStub$handleInvocation$originalPlusToString$1.invoke(MockKStub.kt:235)
	at io.mockk.impl.stub.SpyKStub.defaultAnswer(SpyKStub.kt:15)
	at io.mockk.impl.stub.MockKStub.answer(MockKStub.kt:44)
	at io.mockk.impl.recording.states.AnsweringState.call(AnsweringState.kt:16)
	at io.mockk.impl.recording.CommonCallRecorder.call(CommonCallRecorder.kt:53)
	at io.mockk.impl.stub.MockKStub.handleInvocation(MockKStub.kt:271)
	at io.mockk.impl.instantiation.JvmMockFactoryHelper$mockHandler$1.invocation(JvmMockFactoryHelper.kt:24)
	at io.mockk.proxy.jvm.advice.Interceptor.call(Interceptor.kt:21)
	at java.base/java.util.function.Consumer.lambda$andThen$0(Consumer.java:65)
	at java.base/java.util.function.Consumer.lambda$andThen$0(Consumer.java:65)
	at org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder.createDefaultRequestConfig(HttpComponentsClientHttpRequestFactoryBuilder.java:239)
	at org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder.createHttpClient(HttpComponentsClientHttpRequestFactoryBuilder.java:205)
	at org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder.createClientHttpRequestFactory(HttpComponentsClientHttpRequestFactoryBuilder.java:193)
	at org.springframework.boot.http.client.HttpComponentsClientHttpRequestFactoryBuilder.createClientHttpRequestFactory(HttpComponentsClientHttpRequestFactoryBuilder.java:59)
	at org.springframework.boot.http.client.AbstractClientHttpRequestFactoryBuilder.build(AbstractClientHttpRequestFactoryBuilder.java:76)
	at org.springframework.boot.http.client.ClientHttpRequestFactoryBuilder.build(ClientHttpRequestFactoryBuilder.java:53)

I guess it's possible to fix with JVM args, but I don't want to, it doesn't make sense it have it on the client side, IMO.

Is it possible to fix on your side? If it's my mis configuration I'd like to know to</issue_description>

Comments on the Issue (you are @copilot in this section)

Custom agent used: tech-lead
Tech lead expert for MockK - Kotlin's premier mocking library. Specializes in complex bug fixing, bytecode manipulation, DSL design, and multi-platform architecture. Proactively handles recursion issues, signature matching problems, and JVM agent complexities.


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits December 1, 2025 12:00
Wrap method.isAccessible = true in try-catch to handle JDK module
system restrictions. This prevents InaccessibleObjectException when
spying on JDK functional interfaces like java.util.function.Consumer.

Co-authored-by: oleksiyp <5249932+oleksiyp@users.noreply.github.com>
Co-authored-by: oleksiyp <5249932+oleksiyp@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix InaccessibleObjectException for java.util.function Fix InaccessibleObjectException when spying on JDK interfaces on JDK 16+ Dec 1, 2025
Copilot AI requested a review from oleksiyp December 1, 2025 12:04
@oleksiyp oleksiyp marked this pull request as ready for review December 1, 2025 12:11
@Raibaz Raibaz merged commit b7b72de into master Dec 2, 2025
32 of 45 checks passed
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.

java.base does not "opens java.util.function" since 1.14.0

3 participants