Reputation: 45
I am working on spring REST APIs. In requirements, there are 2 POST requests with same URL but different request body. Since Spring MVC must have unique mappings across controller, I have to pre-process the request body to map to a specific POJO.
On the basis of session_type in request body, I have to map the request to specific POJO (JSON -> JAVA POJO).
For example, if 'session_type' in request body is 'typeX' then the request should map to ClassX POJO. If 'session_type' in request body is 'typeY' then the request should map to ClassY POJO.
If there a way to do it using some kind of requestbody annotation?
Upvotes: 1
Views: 5075
Reputation: 48692
there are 2 POST requests with same URL but different request body
For a RESTful interface, the same URL should always indicate the same resource. The body of a request may contain different representations of that resource. You could create different HttpMessageContverter
classes for the two different kinds of representation.
Upvotes: 0
Reputation: 11363
GETs shouldn't have request bodies, or at least if they do, the server side isn't required to do anything with them. As you describe it, this API isn't RESTful.
Assuming you don't care about that, try creating a controller method that takes a parent class of TypeX and TypeY, or interface that both TypeX and TypeY implement, annotate it with @SomethingMeaningfulToYou, then use a web argument method resolver to instantiate the child class you want.
It's a hack around a broken API though.
Upvotes: 0
Reputation: 4450
If you want to bind typeX
and typeY
, then you definitely need 2 handlers. But, why wouldn't we use param
option of @RequestMapping
:
@RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeX")
public String handleTypeX(@RequestBody @ModelAttribute TypeX typeX){
//TODO implement
}
@RequestMapping(method = RequestMethod.POST,
value = "/url", params = "session_type=typeY")
public String handleTypeY(@RequestBody @ModelAttribute TypeY typeY){
//TODO implement
}
If you need some preparations (f.e. normalize params or perform model binding manually), then the approach above you may combine along with @InitBinder
, but please note, that @InitBinder
needs exact ULR's rules along with @ModelAttribute
parameters in handlers.
EDIT: In Spring MVC there is no possibility to use 2 handlers for exact URL, i.e. when method/URL/params/consumes type are the same.
Thus I suggest use unified handler, where you would check necessary parameter and then manually convert into corresponding class. For finding necessary class I suppose it would be better to use Strategy pattern:
//class resolver according "session_type" parameter
//note, that you can use Spring autowiring capabilities
private final Map<String, Class> TYPES_CONTEXT = new HashMap<String, Class>(){
{
this.put("x", TypeX.class);
this.put("y", TypeY.class);
//TODO probably other classes
}
}
@RequestMapping(method = RequestMethod.POST,
value = "/url")
public @ResponseBody String handleAnyType(@RequestBody Map<String, String> body){
String sessionType = body.get("session_type");
//TODO handle case if sessionType is NULL
Class convertedClass = TYPES_CONTEXT.get(sessionType);
//TODO handle case if class is not found
Object actualObject = objectMapper.convertValue(body, convertedClass);
//now we use reflection for actual handlers, but you may refactor this in the way you want, f.e. again with Strategy pattern
//note that current approach there should be contract for methods names
Method actualHandler = this.getClass().getMethod("handle" + actualObject.getClass().getSimpleName());
return (String)actualHandler.invoke(this, actualObject);
}
public String handleTypeX(TypeX typeX){
//TODO implement
}
public String handleTypeY(TypeY typeY){
//TODO implement
}
//TODO probably other methods
This approach doesn't handle validation and some things were omitted, but I believe this might be helpful.
Upvotes: 5
Reputation: 3775
I think you should created controller with one method for both types, and call required component\method in it depending on typeX
or typeY
.
Upvotes: 0