Märten
Märten

Reputation: 41

Spring Boot controller converts JSON objects to null

I'm building a RESTful controller in Spring Boot. The controller's method work when there is only one method parameter. Unfortunately, when there are two parameters then both POJOs fields' values end up null. I'd appreciate it if anyone could help me figure out why. Also, why doesn't @Valid seem to work in my code?

Controller

@RestController
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Slf4j
public class ParticipantController {

    @Autowired
    ParticipantServiceImpl participantService;

    @DeleteMapping(value = "/removeParticipantFromConference", consumes = "application/json")
    public String removeParticipantFromConference(@RequestBody @Valid Participant participant, @Valid Conference conference, BindingResult bindingResult) {
        log.info("Call for ParticipantController -> removeParticipantFromConference");
        log.info("Received message is {}, {}", participant, conference);

        if (bindingResult.hasErrors()) {
            log.error("bindingResult.hasErrors()");
            return "bindingResult.hasErrors()";
        }

        String resultMessage = participantService.removeParticipantFromConference(participant, conference);
        return resultMessage;
    }

JSON message sent with Postman is

{
    "participant": {
        "fullName": "FirstName LastName",
        "dateOfBirth": "10-06-2020"
    },
    "conference": {
        "name": "testConferenceName",
        "startDateTime": "10-06-2020 10:10",
        "endDateTime": "10-06-2020 11:15",
        "conferenceRoom": {
            "name": "ConferenceRoom_1",
            "location": "Location_1",
            "maxSeats": 5
        }
    }
}

which is logged as

Received message is Participant(id=0, fullName=null, dateOfBirth=null), Conference(id=0, name=null, startDateTime=null, endDateTime=null, conferenceRoom=null, participants=[])

All class fields are private and have getters.

Similar code works in a different controller although @Valid still doesn't throw any errors

@RestController
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
@Slf4j
public class ConferenceController {

    @Autowired
    ConferenceServiceImpl conferenceService;

    @PostMapping(value = "/addConference", consumes = "application/json")
    public String addConference(@RequestBody @Valid Conference conference, BindingResult bindingResult) {
        log.info("Call for ConferenceController -> addConference. Received message is {}", conference);

        String resultMessage = conferenceService.addConference(conference);

        log.info("Sending response: " + resultMessage);
        return resultMessage;
    }
}
{
    "name": "testConferenceName",
    "startDateTime": "10-06-2020 10:10",
    "endDateTime": "10-06-2020 11:15",
    "conferenceRoom": {
        "name": "ConferenceRoom_1",
        "location": "Location_1",
        "maxSeats": 5
    }
}

As for @Valid, one of Participant's fields is

@NotNull(message = "Participant must have name")
    @Pattern(regexp = ".+ .+")
    @Column(nullable = false)
    String fullName;

but it doesn't throw a validation error when the received JSON message has the fullName value "test".

Upvotes: 1

Views: 632

Answers (2)

You can receive only one @RequestBody. (Your code "Conference" argument is recognized as @ModelAttribute.) And add @Valid annotation to fields on demand.

@Data
public class RemoveParticipantFromConferenceRequest {
    @Valid
    private Participant participant;
    @Valid
    private Conference conference;
}

    @DeleteMapping(value = "/removeParticipantFromConference", consumes = "application/json")
    public String removeParticipantFromConference(@RequestBody @Valid RemoveParticipantFromConferenceRequest req, BindingResult bindingResult) {
        Participant participant = req.getParticipant();
        Conference conference = req.getConference();
...

Upvotes: 2

Marc Stroebel
Marc Stroebel

Reputation: 2357

requestbody is always an object, you can't split it in two params just with annotations... use wrapper object like this:

public class Wrapper {
  @Valid
  private Participant participant;
  @Valid
  private Conference conference;
  //....
}

and the controller method

public String removeParticipantFromConference(@RequestBody @Valid Wrapper wrapper...)

Upvotes: 1

Related Questions