mi.mo
mi.mo

Reputation: 81

Handle empty RequestBody in Spring

I'm currently developing an application using Spring Boot and I have an API endpoint(POST method with @RequestBody) that performs different kind of operation based on request parameters. For example, if I receive object like this:

{
"field1":["value1"],
"field2":["value2"]
}

I need to do some transformations based on field1, field2. So, when I send object like this:

{}

Jackson converts JSON obj to my model, but because this obj is empty, all fields in Model setting to null. So, does Spring contain some methods to avoid this?

Do thing like this:

if(allFieldsAreEmpty(requestObj)){
 throw new RuntimeException("All fields are empty.");    
 }

P.S. Models classes generated by Swagger and I can`t modify it.

Upvotes: 2

Views: 3120

Answers (1)

Naman Gupta
Naman Gupta

Reputation: 31

You can implement "org.springframework.validation.Validator" according to your models and validation you want to perform. And you can use InitBinder in your controller to validate request object. Below is an example which I used one of my project:

@Component(value = "fromToDateValidator")
public class FromToDateValidator implements Validator {

    @Override
    public boolean supports(Class<?> clazz) {
        return (InventorySearchRequestByDate.class.equals(clazz) || OrderRequestDetails.class.equals(clazz));
    }

    @Override
    public void validate(Object target, Errors errors) {
        if (!errors.hasErrors()) {
            Date fromDate = null;
            Date toDate = null;
            if (target instanceof InventorySearchRequestByDate) {
                fromDate = ((InventorySearchRequestByDate) target).getFromDate();
                toDate = ((InventorySearchRequestByDate) target).getToDate();
            } else if (target instanceof OrderRequestDetails) {
                fromDate = ((OrderRequestDetails) target).getFromDate();
                toDate = ((OrderRequestDetails) target).getToDate();
            }
            if (fromDate.compareTo(toDate) > 0) {
                errors.rejectValue("toDate", null, "To Date is prior to From Date");
            }
        }
    }
}

So, supports method take class parameter which check whether the class validation is applicable to the model or not. So like in my example I have to check for the InventorySearchRequestByDate request object or OrderRequestDetails request object, So I performed check according to date.

Now in the validate method contains core logic for validating the model and adding the errors.

You can bind this validator in your controller like below and use it:

@RestController
public class ItemInventoryController extends BaseController {

    @Autowired
    @Qualifier("fromToDateValidator")
    private Validator fromToDateValidator;

    @Autowired
    private ItemInventoryService itemInventoryService;

    @InitBinder
    private void initBinder(WebDataBinder binder) {
        binder.addValidators(fromToDateValidator);
    }

    @RequestMapping(value = WebServiceEndPoints.INVENTORY_AVAILABILITY_BY_DATE, method = RequestMethod.POST)
    public Map<String, Set<ItemDetails>> getAvailableItems(@RequestBody @Validated InventorySearchRequestByDate
                                                       inventorySearchRequestByDate, BindingResult bindingResult) throws InvalidFieldException {
        validRequest(bindingResult);
        return itemInventoryService.searchItemsByDateAvailablity(inventorySearchRequestByDate.getFromDate()
                , inventorySearchRequestByDate.getToDate());
    }

    public void validRequest(BindingResult bindingResult) throws InvalidFieldException {
        if (bindingResult.hasErrors()) {
            throw new InvalidFieldException(bindingResult.getFieldErrors());
        }
    }

}

So above code validate the model and throw exception body according to your global handlers.

Upvotes: 2

Related Questions