ReflectJvmMapping.getKotlinFunction returns null for Kotlin properties and must be handled properly (see #31856).
I hit another erroneous usage here:
2025-01-19T08:43:01.882+01:00 INFO 8982 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2025-01-19T08:43:01.882+01:00 INFO 8982 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2025-01-19T08:43:01.883+01:00 INFO 8982 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 1 ms
2025-01-19T08:43:01.935+01:00 ERROR 8982 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: java.lang.IllegalArgumentException: Kotlin function must not be null] with root cause
java.lang.IllegalArgumentException: Kotlin function must not be null
at org.springframework.util.Assert.notNull(Assert.java:181)
at org.springframework.http.converter.AbstractKotlinSerializationHttpMessageConverter.serializer(AbstractKotlinSerializationHttpMessageConverter.java:153)
at org.springframework.http.converter.AbstractKotlinSerializationHttpMessageConverter.canWrite(AbstractKotlinSerializationHttpMessageConverter.java:96)
at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:328)
at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:208)
at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:78)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:986)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:891)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1088)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:978)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:903)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:564)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:885)
at jakarta.servlet.http.HttpServlet.service(HttpServlet.java:658)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:195)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:164)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:140)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:483)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:115)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:344)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:397)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:905)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1741)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52)
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1190)
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:63)
at java.base/java.lang.Thread.run(Thread.java:1575)
More Assert.notNull on the value returned from ReflectJvmMapping.getKotlinFunction can be found in spring-framework sources.
Comment From: bclozel
Unfortunately, we can't triage this issue right now. You have not given us much to work with.
Is this a regression, meaning that the sample in the linked issue doesn't work anymore as it did after the initial fix?
Which Spring and Kotlin versions are you using?
How can we reproduce the problem?
Comment From: wolfseifert
Sorry for the shortness of my issue description. But if you assign this issue to someone like @sdeleuze (who fixed #31856) he will know what to do: grep the springframework for ReflectJvmMapping.getKotlinFunction and check if all returned null are handled correctly.
Comment From: snicoll
@wolfseifert that's not an acceptable answer: it's totally fair that one of us asks for additional details. If you want us to consider the report, make it actionable as Brian asked.
Comment From: wolfseifert
Here is a small reproducer: spring-boot.zip
- Unzip
spring-boot.zip - Set
JAVA_HOMEto/usr/lib/jvm/java-17-openjdk,/usr/lib/jvm/java-21-openjdkor/usr/lib/jvm/java-23-openjdk $ gradlew bootRun$ gradlew client
The IllegalArgumentException: Kotlin function must not be null from above appears in the spring-boot console.
Versions: - OpenJDK 17, 21 or 23 - Gradle 8.12 - Kotlin 2.1.0 - Spring-Boot 3.4.1
OS: Linux or Windows
Comment From: sdeleuze
Fixed with the limitation that the type used for Kotlin properties is created from the Java type, not the Kotlin one, since kotlin-reflect does not provide a direct match from the Java method to the Kotlin property.
As mentioned in https://github.com/spring-projects/spring-framework/issues/31856#issuecomment-1862606610, the main reason we support this use case is to avoid unnecessary Kotlin checks at RequestMappingHandlerMapping level, and it was introduced at a time where non suspending function were invoked with Java reflection, not Kotlin one like in 6.2+.
Kotlin properties are supported in a best effort fashion, this is not something I recommend or plan to document explicitly. If more side effects are found, I may decide to remove the support in a future major release, but for now let's try to keep this pragramatic status quo.