reproduce project link : https://github.com/toohandsome/springdemo/

Spring Boot version: 2.7.1

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

demo:

    @Autowired
    private RestTemplate restTemplate;

    @GetMapping("/runTest")
    public String runTest() {

        new Thread(new Runnable() {
            @Override
            public void run() {
                for (; ; ) {
                    try {
                        HttpHeaders headers = new HttpHeaders();
                        MultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
                        map.add("name", "xiaoming");
                        map.add("age", "123456");
                        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                        HttpEntity<MultiValueMap<String, Object>> param = new HttpEntity<>(map, headers);
                        ResponseEntity<String> response = restTemplate.postForEntity("http://127.0.0.1:8080/postTest", param, String.class);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();


        new Thread(new Runnable() {
            @Override
            public void run() {
                for (; ; ) {
                    try {
                        HashMap<String, String> objectObjectHashMap = new HashMap<>();
                        objectObjectHashMap.put("a", "1");
                        objectObjectHashMap.put("b", "1");
                        ResponseEntity<String> response = restTemplate.getForEntity("http://127.0.0.1:8080/getParams?a={a}&b={b}", String.class, objectObjectHashMap);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        return "run success";
    }


    @GetMapping("/getParams")
    public String getParams(String a, int b) {
        return "get success";
    }


    @PostMapping("/postTest")
    public String postTest(HttpServletRequest request) {
        String age1 = request.getParameter("age");
        String name1 = request.getParameter("name");
        new Thread(new Runnable() {
            @Override
            public void run() {
                String age2 = request.getParameter("age");
                String name2 = request.getParameter("name");
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                age2 = request.getParameter("age");
                name2 = request.getParameter("name");
            }
        }).start();
        return "post success";
    }

call runtest method with browser, it will get error msg like this:

java.lang.IllegalStateException: Optional int parameter 'b' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type

Spring in asynchronous tasks use request.getParameter(),  It may cause the next

I found it was because

org.springframework.web.method.annotation.RequestParamMethodArgumentResolver#resolveName

return a null value.

Spring in asynchronous tasks use request.getParameter(),  It may cause the next

Based on further analysis, i found

org.apache.tomcat.util.http.Parameters#handleQueryParameters

this method parsing parameters found didQueryParameters is true ,Tomcat thinks that the parameter has been resolved.

Can we handle it in this case?

When the RequestParamMethodArgumentResolver cannot get the parameters from the NativeWebRequest, try to get them from query string?

Comment From: toohandsome

If my proposal is feasible, I can submit a PR to fix this problem

Comment From: poutsma

If my proposal is feasible, I can submit a PR to fix this problem

For now, we'd rather have a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem, instead of snippets and screenshots.

Comment From: toohandsome

If my proposal is feasible, I can submit a PR to fix this problem

For now, we'd rather have a complete minimal sample (something that we can unzip or git clone, build, and deploy) that reproduces the problem, instead of snippets and screenshots.

https://github.com/toohandsome/springdemo/

Comment From: toohandsome

it's solved. use AsyncContext run Thread..

@PostMapping("/postTest")
    public String postTest(HttpServletRequest request, HttpServletResponse response, String age, String name) {
        AsyncContext asyncContext =
                request.isAsyncStarted()
                        ? request.getAsyncContext()
                        : request.startAsync(request, response);
        asyncContext.start(new Runnable() {
            @Override
            public void run() {
                String age2 = request.getParameter("age");
                String name2 = request.getParameter("name");
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                String age3 = request.getParameter("age");
                String name3 = request.getParameter("name");
                System.out.println("age1: " + age + " , name1: " + name + " , age2: " + age2 + " , name2: " + name2 + " , age3: " + age3 + " , name3: " + name3);
                asyncContext.complete();
            }
        });

        return "post success";
    }

Comment From: zjunothing

Just pass value into the other thread,not pass in the whole request ...