Numero 21
Numero 21

Reputation: 265

How can I set an optional RequestBody field without it being deleted when I make the call?

I have a small program in spring-boot which through a get call having a @RequestBody returns me a message with all the specifications (in my case of cars)

public class CarsRequest implements Serializable {
    private String name;
    private String plate ;
    private  String price;
}

I would like to be able to make sure that if a field is set to null, it can still find the relative message with the other fields having a value, in my case, I wanted to put that the "name" field is optional in the RequestBody, is it possible to do this? I tried setting

    public CarsResponse getCars(@RequestBody (required = false) CarsRequest request) throws IOException {
           //some code 

   }

but then when I go to do the get it completely deletes the null field at the time of the get and therefore fails to do it

Upvotes: 1

Views: 5477

Answers (3)

Saffie
Saffie

Reputation: 535

You can make a single field optional by making it an Optional, in your case Optional<String>. If the field does not appear in the request body, then the Optional will be empty.

public class CarsRequest implements Serializable {
    private String name;
    private String plate;
    private Optional<String> price;
}

Upvotes: 1

code_mechanic
code_mechanic

Reputation: 1148

Just remove the @RequestBody annotation from the function and keep it as it is

public CarsResponse getCars(CarsRequest request) throws IOException {
           //some code 

}

Now all fields will be converted into query params and all will be optional, because query param by convention are optional

public class CarsRequest implements Serializable {
    private String name;
    private String plate ;
    private  String price;
}

And call like this

GET /someEndpoint?name=<value>&plate=null

But still if you want to make some params mandatory, then use javax.annotations or apply validation yourself.

EDIT: As asked in comment, if you are accepting JSON as parameter body then you can do one thing, you can accept it as String and then convert json to object inside function body

public CarsResponse getCars(@RequestParam(required = false) String request) throws IOException {
           ObjectMapper mapper = new ObjectMapper();
           CarRequest request = mapper.readValue(request,CarRequest.class);
          // other code

}

and call it something like this

GET /someEndpoint?request="{ \"name\" : null, \"plate\": \"someValue\" }"

EDIT 2:

You can do one more thing if you want to keep sending json and have it transformed into object, you can declare a binder something like this

// Some controller class
class SomeController {
   @Autowired
   ObjectMapper mapper;
   
   // Ommited methods here
   
    @GetMapping("/carRequest")
    public ResponseEntity<String> testBinder(@RequestParam CarRequest request) {
        return ResponseEntity.ok("{\"success\": \"" + request.name+ "\"}");
    }

    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.registerCustomEditor(CarRequest.class, new CarRequestEditor(mapper));
    }

    static class CarRequestEditor extends PropertyEditorSupport {

        private ObjectMapper objectMapper;

        public CarRequestEditor(ObjectMapper objectMapper) {
            this.objectMapper = objectMapper;
        }

        @Override
        public void setAsText(String text) throws IllegalArgumentException 
        {
            if (StringUtils.isEmpty(text)) {
                setValue(new CarRequest());
            } else {
                try {
                    setValue(objectMapper.readValue(text, CarRequest.class));
                } catch (JsonProcessingException e) {
                    throw new IllegalArgumentException(e);
                }
            }
        }
    }
   
}

Please note that the client need to send the json URL encoded like this

http://localhost:8180/carRequest?request=%7B%22name%22%3"test"%7D

Upvotes: 1

Sandeep Kumar
Sandeep Kumar

Reputation: 70

Hi you are using @RequestBody (required = false) CarsRequest that means your CarsRequest object itself is optional rather than you can use

@NotEmpty 
private String plate ;
@NotEmpty
private  String price;

Upvotes: 0

Related Questions