Spring MVC
RequestParam
Java
List Binding
Web Development

Binding a list in RequestParam

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Spring MVC can bind request parameters directly into a List when the incoming values are simple types such as strings, integers, or longs. The two most common input shapes are repeated parameters and comma-separated values. Both can be convenient, but you should choose the one that matches how your clients actually send requests.

Basic List Binding

A controller can bind a list parameter directly.

java
1import org.springframework.web.bind.annotation.GetMapping;
2import org.springframework.web.bind.annotation.RequestParam;
3import org.springframework.web.bind.annotation.RestController;
4
5import java.util.List;
6
7@RestController
8public class ProductController {
9
10    @GetMapping("/products")
11    public List<Long> getProducts(@RequestParam List<Long> ids) {
12        return ids;
13    }
14}

This works with requests like:

  • '/products?ids=1,2,3'
  • '/products?ids=1&ids=2&ids=3'

Spring converts the incoming values into the target element type, here Long.

Comma-Separated Versus Repeated Parameters

Both forms are widely used, but they are not identical from an API-design point of view.

Comma-separated form:

text
/products?ids=1,2,3

Repeated-parameter form:

text
/products?ids=1&ids=2&ids=3

Repeated parameters are often clearer because they avoid extra splitting rules in clients and proxies. Comma-separated values are concise and still common. Spring can usually handle either for simple scalar types.

Optional Lists

If the parameter is optional, mark it as not required.

java
1@GetMapping("/search")
2public List<String> search(@RequestParam(required = false) List<String> tags) {
3    return tags == null ? List.of() : tags;
4}

This avoids a missing-parameter error when the client does not send the list at all.

Be explicit about what absence means in your API. Sometimes an omitted list means "no filter," while an empty list means "filter to nothing." Those are not always the same business rule.

Type Conversion and Validation

Simple element types work well because Spring can convert them automatically.

Examples that bind cleanly:

  • 'List<String>'
  • 'List<Integer>'
  • 'List<Long>'
  • 'List<UUID> if conversion support is present'

If one value cannot be converted, Spring throws a binding error. That means /products?ids=1,two,3 will fail for List<Long>.

This is usually what you want because the request is malformed.

When @RequestParam Is the Wrong Tool

@RequestParam is best for simple lists in query strings or form parameters. It is not the right choice for complex nested structures.

If the client is sending a JSON array in the request body, use @RequestBody instead.

java
1@PostMapping("/products/filter")
2public List<Long> filter(@RequestBody List<Long> ids) {
3    return ids;
4}

Likewise, if the input is a richer form object with several fields, a request DTO or @ModelAttribute is usually cleaner than many independent request parameters.

Testing the Binding Behavior

If you are unsure how your controller will interpret a query string, write a small MockMvc test. That is especially useful when several clients call the same endpoint and you want to lock in one accepted format.

java
1import org.junit.jupiter.api.Test;
2import org.springframework.beans.factory.annotation.Autowired;
3import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
4import org.springframework.test.web.servlet.MockMvc;
5
6import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
7import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
8import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
9
10@WebMvcTest(ProductController.class)
11class ProductControllerTest {
12
13    @Autowired
14    private MockMvc mockMvc;
15
16    @Test
17    void bindsRepeatedParameters() throws Exception {
18        mockMvc.perform(get("/products").param("ids", "1", "2", "3"))
19               .andExpect(status().isOk())
20               .andExpect(content().json("[1,2,3]"));
21    }
22}

This kind of test documents the contract more clearly than prose alone. If you also accept comma-separated input, add a second test so future refactoring does not accidentally narrow the supported format.

Common Pitfalls

The most common mistake is using @RequestParam for complex structured data that really belongs in a request body object.

Another mistake is assuming every client will send the list in the same format without documenting whether the API expects repeated parameters or comma-separated values.

A third pitfall is forgetting that missing and empty list semantics may need different business handling.

Summary

  • Spring MVC can bind request parameters directly into List types.
  • Repeated parameters and comma-separated values are both common input formats.
  • Use required = false when the list is optional.
  • Simple scalar element types bind cleanly; malformed values trigger conversion errors.
  • Use @RequestBody instead of @RequestParam when the client is sending structured JSON data.

Course illustration
Course illustration

All Rights Reserved.