javaspringspring-bootjackson-databind

Binding url params to POJO in Spring


How to bind @RequestParam to object in Spring (GET mapping).

I have the following method in my controller class:

@GetMapping("/quotes")
void getQuotes(QuoteRequest request) {  }

QuoteRequest in a simple POJO:

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
public class QuoteRequest {

   @Size(min = 1, max = 5)
   private List<String> topics;
}

It it easy to create http request, e.g. by using curl http://localhost:8080/quotes?topics=%5B%22string%22%5D

However, when I tried to replace List with a list of custom objects, Spring won't accept such a request.

Please show me me code: I replaced private List<String> topics; with private List<Topic> topics; and Topic class is as follows:

@Data
public class Topic {

   private String name;
   private Integer amount;

}

I used Swagger to create request:

enter image description here

Which translates to the following request URL; http://localhost:8080/api/v1/quotes?topics=%5B%7B%22name%22%3A%22string%22%2C%22amount%22%3A0%7D%5D

This time Spring returned the following error:

{
  "topics": "Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'topics'; Cannot convert value of type 'java.lang.String' to required type 'Topic' for property 'topics[0]': no matching editors or conversion strategy found"
}

Why is that? How do I fix this?


Solution

  • Ideally, complex objects need to be sent through @postmapping, as shown below

    @PostMapping("/quotes")
    void getQuotes(@RequestBody QuoteRequest request) {}
    

    But if you really want to send the data in the get request as mentioned in the other comment the url has to be http:// localhost : 8080/api/v1/quotes?topics[]= ... again with this since the spring cannot parse the data you need to parse the data, may be using ObjectMapper as shown below

    @GetMapping("/quotes")
    void getQuotes(@RequestParam ("topics") String topics) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        List<Topic> topicList = mapper.readValue(topics, new TypeReference<List<Topic>>() {});
        //your logic..
    }
    

    then if you do send the request in the swagger like this { "topics": [{ "name": "test", "amount": 0 }] } it will work.