Skip to content

MetadataReader misses enclosing class name for Kotlin nested classes with Java 24+ #36451

@matthew-js-porter

Description

@matthew-js-porter

When Spring Boot 4.0.3, Java 25 and Kotlin 2.2.21. @TestConfiguration from other Kotlin classes in the same package are loaded when running a @SpringBootTest from another Test class.

Example:

package com.example.kotlin_test_config_issue

import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@SpringBootTest
@AutoConfigureMockMvc
class OneTest {

    @Autowired
    private lateinit var mockMvc: MockMvc

    @Test
    fun `invoke test endpoint`() {
        mockMvc.get("/test").andExpect { status { isOk() } }
    }

    @TestConfiguration
    class TestConfig {
        @RestController
        class TestController {
            @GetMapping("/test")
            fun test() = 2
        }
    }
}
package com.example.kotlin_test_config_issue

import org.junit.jupiter.api.Test
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.boot.test.context.TestConfiguration
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.get
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.RestController

@SpringBootTest
@AutoConfigureMockMvc
class TwoTest {

    @Autowired
    private lateinit var mockMvc: MockMvc

    @Test
    fun `invoke test endpoint`() {
        mockMvc.get("/test").andExpect { status { isOk() } }
    }

    @TestConfiguration
    class TestConfig {
        @RestController
        class TestController {
            @GetMapping("/test")
            fun test() = 2
        }
    }
}

When running either test both @TestConfigurations are loaded and an error is thrown.

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/webmvc/autoconfigure/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Ambiguous mapping. Cannot map 'twoTest.TestConfig.TestController' method 
com.example.kotlin_test_config_issue.TwoTest$TestConfig$TestController#test()
to {GET [/test]}: There is already 'oneTest.TestConfig.TestController' bean method
com.example.kotlin_test_config_issue.OneTest$TestConfig$TestController#test() mapped.

The same tests will work when using Java 21.

This sample repository generated from Spring Initializer demostrates the issue

  • run ./mvnw clean test with JDK 21. Observe tests pass.
  • run ./mvnw clean test with JDK 25. Observe tests fail.

Running similar tests while using Java works fine.

Metadata

Metadata

Assignees

Labels

in: coreIssues in core modules (aop, beans, core, context, expression)type: bugA general bug

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions