Affects: 3.2.2

  • id("org.springframework.boot") version "3.2.2"
  • kotlin("jvm") version "1.9.22"

  • This is my requestparam to get the data from application.yml

@RequestParam(name = "size", defaultValue = "\${spring.data.web.pageable.default-page-size:10}", required = false) size: Int,

  1. When i try to run basic integration-test using @SpringBootTest i get following error;

Failed to convert value of type 'java.lang.String' to required type 'int'; For input string: "${spring.data.web.pageable.default-page-size:10}"

  1. I do have parameter defined in my yml so following works in same test; @Value("\${spring.data.web.pageable.default-page-size}") private lateinit var pageSize: String

Comment From: senocak

I am guessing this is not related with kotlin or java because i made basic app both kotlin and java with almost every springboot3 releases and they all fail. Here is the code snippet for java and kotlin;

java:

@SpringBootApplication
public class Auth3Application {
    public static void main(String[] args) {
        SpringApplication.run(Auth3Application.class, args);
    }
}

@Validated
@RestController
@RequestMapping("/users")
class UserController {
    @GetMapping
    private String allUsers(
        @RequestParam(defaultValue = "${spring.data.web.pageable.default-page-size:10}", required = false) final String size
    ) {
        return size;
    }
}

// tests

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class Auth3ApplicationTests {
    @Autowired private UserController userController;

    @Test
    void contextLoads() throws Exception {
        MockMvc mockMvc = MockMvcBuilders .standaloneSetup(userController).build();
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/users"));
        perform.andExpect(MockMvcResultMatchers.status().isBadRequest());
    }


}

kotlin:

@SpringBootApplication
class SpringKotlinApplication

fun main(args: Array<String>) {
    runApplication<SpringKotlinApplication>(*args)
}

@Validated
@RestController
@RequestMapping("/users")
class UserController {

    @Value("\${spring.data.web.pageable.default-page-size}")
    private lateinit var jwtExpirationInMs: String

    @GetMapping
    fun allUsers(
        @RequestParam(defaultValue = "\${spring.data.web.pageable.default-page-size:10}", required = false) size: String
    ): String {
        println("sizesizesizesize: $size")
        return size
    }
}

// test

@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class UserControllerTest {
    @Autowired private lateinit var userController: UserController

    private lateinit var mockMvc: MockMvc

    @BeforeEach
    fun beforeEach() {
        mockMvc = MockMvcBuilders.standaloneSetup(userController).build()
    }

    @Test
    fun givenSortColumnIsInvalid_whenPatchMe_thenThrowServerException() {
        // Given
        val requestBuilder: RequestBuilder = MockMvcRequestBuilders
            .get("/users")
        // When
        val perform: ResultActions = mockMvc.perform(requestBuilder)
        // Then
        perform.andExpect(MockMvcResultMatchers.status().isBadRequest)
    }

}

Comment From: snicoll

Please move all that code in text in a sample we can actually run. The Java sample is enough.

Comment From: senocak

Please move all that code in text in a sample we can actually run. The Java sample is enough.

The code can be run straightly, please tell me what else should i provide?

Comment From: snicoll

A sample application we can run that reproduces the problem in the form of a zip file attached to this issue. Alternatively, you can push the code to GitHub and share the url of the repo here.

Comment From: senocak

Okay so i figured out that problem occurs when i configure MockMvc manually like; MockMvc mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); Changing it with @AutoConfigureMockMvc works ok.

Main app;

@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }
}

@Validated
@RestController
@RequestMapping("/users")
class UserController {
    @GetMapping
    private String allUsers(
        @RequestParam(defaultValue = "${spring.data.web.pageable.default-page-size:10}", required = false) final String size
    ) {
        return size;
    }
}

Failed one

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class DemoApplicationTests {
    @Autowired private UserController userController;

    @Test
    void contextLoads() throws Exception {
        MockMvc mockMvc = MockMvcBuilders.standaloneSetup(userController).build();
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/users"));
        perform.andExpect(MockMvcResultMatchers.status().isBadRequest());
    }

}

Success one;

@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
class DemoApplicationTests {
    @Autowired private MockMvc mockMvc;

    @Test
    void contextLoads() throws Exception {
        ResultActions perform = mockMvc.perform(MockMvcRequestBuilders.get("/users"));
        perform.andExpect(MockMvcResultMatchers.status().isBadRequest());
    }
}

If this is expected then issue can be closed, if not please let me know how.

demo.zip

Comment From: snicoll

A standalone setup has no link with the context or its environment so that is expected. Please review the javadoc of standaloneSetup, you should not create a context at all for this but create the controller manually.

If you need a controller that’s linked to the context you should not use this, but inject MockMvc as the working setup shows.

Comment From: senocak

@snicoll If thats the case, why can i get the exact same variable using @Value annotation. I would expect same result as it is. Screenshot 2024-02-07 at 22 20 17 I know injection is not working it just use default value for @Value annotation, i am asking why default is not working in @RequestParam as well

Comment From: snicoll

Because the controller instance is created by the context of your integration test, so @Value just works as expected. However you're passing that instance into a MockMvc standalone setup and I already explained why that doesn't use the existing context and asked you to review the Javadoc.

If you have further questions, please follow-up on StackOverflow, as mentioned in the guidelines for contributing, we prefer to use the issue tracker only for bugs and enhancements.