简体   繁体   中英

Conditional JSON Request mapping in Spring boot

I have a post request with URL http://my-custom-url/{param}

now

//pseudo code
if param == param1
then request body must be mapped to model Class A
if param == param2
then request body must be mapped to model Class B 

In addition to mapping I also have Jsr303 validation inside my model class es hence I also want to use @Valid annotation How do I do this

You can receive the payload as a Map<K, V> and use ObjectMapper to deserialize it.

@RestController
@RequestMapping(path = "/my-rest-api")
public class MyController {

    @Autowired
    ClassAValidator classAValidator; // assuming you wrote an validator

    @Autowired
    ClassBValidator classBValidator; // assuming you wrote an validator

    @PostMapping("/{parameter}")
    public ResponseEntity<Object> handleRequest(
            @PathVariable("parameter") String parameter,
            @RequestBody Map<Object, Object> request,
            BindingResult result) {

        ObjectMapper mapper = new ObjectMapper();
        if (parameter.equals("X")) {
           ClassA classA = mapper.convertValue(request, ClassA.class);
           classAValidator.validate(classA, result);
           if(result.hasErrors()) {
                throw new CustomException(result);
           }
        } else if (parameter.equals("Y")) {
            ClassB classB = mapper.convertValue(request, ClassB.class);
            classBValidator.validate(classB, result);
            if(result.hasErrors()) {
                throw new CustomException(result);
            }
        } else {
            // ..
        }

        return ResponseEntity.ok("Ok");
    }

}

I think this one is a simpler solution:

@RestController
@RequestMapping("/my-custom-url")
public class MyController {

    @PostMapping("/param1")
    public ResponseEntity<Object> handleClassA(
            @Valid @RequestBody ClassA classA,
            BindingResult result) {
        ...
        return ResponseEntity.ok("Ok");
    }

    @PostMapping("/param2")
    public ResponseEntity<Object> handleClassB(
            @Valid @RequestBody ClassB classB,
            BindingResult result) {
        ...
        return ResponseEntity.ok("Ok");
    }

}

I am not sure why above answers explaining validators. as I understand you are trying to return two type of responses based on condition. that is not possible. because return type validate on compile time. so if you set return type as classA you must return classA. you cannot return classB. (unless classB is a classA relationship) so if you really want to do this you can use name interface to enforce the type.

@GetMapping(value = "/{id}")
    public Response getRent(@PathVariable int id, @RequestParam(required = false) String type) {

        if(type=="A"){
            return  new ClassA(rentService.findById(id));
        }else{
         return    new ClassB (rentService.findDetailResponse(id));
        }
    }

PS: you may need to return this as

public ResponseEntiry<Response>

but I just used Response directly.

now you need to create those two classes from same interface

public interface Response {
}
public class ClassA implements Response {
// your code goes here
}
public class ClassB implements Response {
// code here
}

this way you can achieve what you are trying.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM