As per my findings, spring does not support content types "application/x-www-form-urlencoded
", "application/json
" and "application/xml
" together.
Reason I figured: Spring processes JSON and XML types by parsing and injecting them into the java pojo marked with @RequestBody
spring annotation. However, x-www-form-urlencoded
must be injected into a MultiValueMap<>
object marked with @RequestBody
. Two different java types marked with @RequestBody
will not be supported simultaneously, as spring may not know where to inject the payload.
A working solution:
"application/x-www-form-urlencoded
" can be supported as it is in the API. That is, it can be injected into spring's MultiValueMap<>
using an @RequestBody annotation.
To support JSON and XML on the same method, we can leverage servlet specification and spring's class built on top of them to extract the payload as stream.
Sample code:
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.util.MultiValueMap;
// usual REST service class
@Autowired
private MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter;
@Autowired
private Jaxb2RootElementHttpMessageConverter jaxb2RootElementHttpMessageConverter;
public ResponseEntity<Object> authorizationRequestPost(HttpServletResponse response, HttpServletRequest request,@RequestBody(required = false) MultiValueMap<String, String> parameters) {
// this MultiValueMap<String,String> will contain key value pairs of "application/x-www-form-urlencoded" parameters.
// payload object to be populated
Authorization authorization = null;
HttpInputMessage inputMessage = new ServletServerHttpRequest(request) {
@Override
public InputStream getBody() throws IOException {
return request.getInputStream();
}
};
if (request.getContentType().equals(MediaType.APPLICATION_JSON_VALUE)) {
authorization = (Authorization) mappingJackson2HttpMessageConverter.read(Authorization.class, inputMessage);
}
else if (request.getContentType().equals(MediaType.APPLICATION_XML_VALUE)) {
authorization = (Authorization)jaxb2RootElementHttpMessageConverter.read(Authorization.class, inputMessage);
}
else{
// extract values from MultiValueMap<String,String> and populate Authorization
}
// remaining method instructions
}
Point to note that any custom data type/markup/format can be supported using this approach. Spring's org.springframework.http.converter.HttpMessageConverter<>
can be extended to write the parsing logic.
Another possible approach could be an AOP style solution which would execute the same logic: parse payload by extracting it from HttpServlet
input stream and inject into the payload object.
A third approach will be to write a filter for executing the logic.