Content type blank is not supported - spring

I want to handle the POST request when there is empty content-type.
When I add consumes = MediaType.APPLICATION_JSON_VALUE
and make a request in postman with Content-type blank I get the following error
{
"timestamp": 1581594986909,
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type '' not supported",
"path": "/test"
}
Here is the code
#PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity create(#RequestBody TestRequest testRequest) throws TestException {
LOG.debug("Starting...");
//code
return createtest(testRequest);
}
when i remove consumes = MediaType.APPLICATION_JSON_VALUE
and make a request with content-type = blank
i get the following error
{
"timestamp": 1581595348209,
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'application/octet-stream' not supported",
"path": "/test"
}
Here is the code
#PostMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity create(#RequestBody TestRequest testRequest) throws TestException {
LOG.debug("Starting...");
//code
return createtest(testRequest);
}
Here is the POstMan request
I want to handle this scenario and assume as if content-Type= application/json is sent

To handle empty Content-Type as if application/json, you need to configure MappingJackson2HttpMessageConverter to support application/octet-stream and controller's method (i.e. your create method) consumes both application/octet-stream and application/json.
For example:
[CONFIGURATION]
#Configuration(proxyBeanMethods = false)
public class MyConfigurer {
#Bean
public HttpMessageConverters customConverters() {
Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(builder.build());
List<MediaType> supportedMediaTypes = new ArrayList<>();
supportedMediaTypes.addAll(converter.getSupportedMediaTypes());
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
converter.setSupportedMediaTypes(supportedMediaTypes);
return new HttpMessageConverters(converter);
}
}
[CONTROLLER'S METHOD]
#PostMapping(produces = MediaType.APPLICATION_JSON_VALUE, consumes = {
MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE })
public ResponseEntity create(#RequestBody TestRequest testRequest) throws TestException {
LOG.debug("Starting...");
//code
return createtest(testRequest);
}
Spring seems to assume that Content-Type is application/octet-stream when Content-Type is empty and by default configuration MappingJackson2HttpMessageConverter supports application/json and application/*+json only. Therefore you need to modify your configuration and controller's method like above.
Following references are helpful for you:
Javadoc of MappingJackson2HttpMessageConverter
Spring boot documents

I finally configured it and it is working. Here is the correct configuration for MappingJackson2HttpMessageConverter
#Configuration(proxyBeanMethods = false)
public class WebMvcConfig implements WebMvcConfigurer {
#Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
converters.add(jacksonMessageConverter());
WebMvcConfigurer.super.configureMessageConverters(converters);
}
#Bean
public MappingJackson2HttpMessageConverter jacksonMessageConverter() {
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
List<MediaType> supportedMediaTypes=new ArrayList<>();
supportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
messageConverter.setSupportedMediaTypes(supportedMediaTypes);
supportedMediaTypes.add(MediaType.APPLICATION_OCTET_STREAM);
messageConverter.setSupportedMediaTypes(supportedMediaTypes);
messageConverter.setPrettyPrint(true);
return messageConverter;
}
Aso add the APPLICATION_OCTET_STREAM_VALUE } in the controller method you want to support the octet-stream.
consumes = { MediaType.APPLICATION_JSON_VALUE, MediaType.APPLICATION_OCTET_STREAM_VALUE
}

Related

Jackson failed to convert request element

I'm using Spring to craft a REST API which exposes a POST endpoint. I'm able to reach the endpoint, but I'm having trouble reading the request body.
The following code works: payload contains the object sent.
#RestController
public class RestController {
#RequestMapping(value = "/endpoint")
public ResponseEntity endpoint(#RequestParam("payload") String str) throws IOException {
ObjectMapper objectMapper = new ObjectMapper();
Payload payload = objectMapper.readValue(str, Payload.class);
return ResponseEntity.status(HttpStatus.OK).build();
}
}
However, the following code DOES NOT works: it throws an exception.
#RestController
public class RestController {
#RequestMapping(value = "/endpoint")
public ResponseEntity endpoint(#RequestParam("payload") Payload payload) throws IOException {
return ResponseEntity.status(HttpStatus.OK).build();
}
}
The exception:
Failed to convert request element: org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException: Failed to convert value of type 'java.lang.String' to required type 'beans.Payload'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'beans.Payload': no matching editors or conversion strategy found
Why the latter doesn't work? I thought Spring decode request parameters in the same way...
UPDATE: my Payload class:
#JsonIgnoreProperties(ignoreUnknown = true)
public class Payload {
#JsonProperty("type")
private String type;
#JsonProperty("callback_id")
private String callbackId;
#JsonProperty("message_ts")
private String message_ts;
#JsonProperty("response_url")
private String responseUrl;
protected Payload() {}
public String getType() {
return type;
}
public String getCallbackId() {
return callbackId;
}
public String getMessage_ts() {
return message_ts;
}
public String getResponseUrl() {
return responseUrl;
}
}
UPDATE: I'm testing the endpoint with Postman. This is what I'm sending:
KEY VALUE
payload { "type": "test" }
and this is the error I got:
{
"timestamp": "2018-08-28T10:38:33.133+0000",
"status": 415,
"error": "Unsupported Media Type",
"message": "Content type 'multipart/form-data;boundary=--------------------------586093407866564427326096;charset=UTF-8' not supported",
"path": "/endpoint"
}
Payload constructor should not be protected. It should be public.
Change it to
Public PayLoad(){}
Otherwise, controllers cant create a payload object when mapping is done.
Use #RequestBody instead of #RequestParam. Your Payload is in post body and #RequestBody annotation will deserialize it to payload.
Just get rid of protected Payload() {} . As you don't have any parameterized constructer you are fine, Java compiler will take care of adding the default constructer to the compiled byte code.
And you need to change this
Controller method
#RestController
public class RestController {
#RequestMapping(value = "/endpoint")
public ResponseEntity endpoint(#RequestParam("payload") Payload payload) throws IOException {
return ResponseEntity.status(HttpStatus.OK).build();
}
}
Changes
a. Change HTTP request method to POST it, instead of GET . (method = RequestMethod.POST) .
b. Change Payload to a message body insteda of request param (#RequestParam("payload") Payload payload --> #RequestBody Payload payload ).
Change it as
#RequestMapping(value = "/endpoint", method = RequestMethod.POST)
public ResponseEntity endpoint(#RequestBody Payload payload) throws IOException {
return ResponseEntity.status(HttpStatus.OK).build();
}
Your URL patterns are mal-configured. Try,
#RestController
#RequestMapping(value = "/")
public class PayLoadController {
#RequestMapping(value = "endpoint/",method = RequestMethod.POST)
public ResponseEntity endpoint(#RequestBody Payload payload) throws IOException {
return ResponseEntity.status(HttpStatus.OK).build();
}}
Just copy paste this code and rename controller file name.
Then post your data to,
localhost:8080/endpoint/

Deserialize text/plain after making request with restTemplate

I'm trying to integrate my app with ebay Finding API, after getting familiar with api, I tried making some requests to see if it's working as expected, but one thing got me stuck. The ebay service even though I explicitly set RESPONSE-DATA-FORMAT to JSON, returns response in json format but the content-type is text/plain. I set my restTemplate message converters as follows:
#Bean
public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter(ObjectMapper objectMapper)
{
MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(objectMapper);
messageConverter.setSupportedMediaTypes(
ImmutableList
.of(
new MediaType("application", "json", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET),
new MediaType("text", "plain", MappingJackson2HttpMessageConverter.DEFAULT_CHARSET)
));
return messageConverter;
}
#Bean
RestTemplate restTemplate(MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter)
{
RestTemplate restTemplate = new RestTemplate();
restTemplate.setMessageConverters(Collections.singletonList(mappingJackson2HttpMessageConverter));
return new RestTemplate();
}
Even though when I try to deserialize response which looks like this:
json data
And object:
public class Response
{
private String version;
public Response()
{
}
public String getVersion()
{
return version;
}
public void setVersion(String version)
{
this.version = version;
}
}
My Api call:
String url = uriBuilder.formEndpoint("iphone").toString();
Response response = restTemplate.getForObject(url, Response.class);
Is finishing with exception like this:
Could not extract response: no suitable HttpMessageConverter found for
response type [class com.domain.Response]
and content type [text/plain;charset=UTF-8]

Spring Boot integration test - TestRestTemplate how to set response Content-Type to UTF-8

I tried to integrate test Spring Boot application, now I got one issue
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class org.springframework.http.ResponseEntity] and content type [application/x-json;charset=iso-8859-1]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:109)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:917)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:901)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:655)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at org.springframework.boot.test.web.client.TestRestTemplate.exchange(TestRestTemplate.java:735)
If I do below
#Before
public void init() {
List<HttpMessageConverter<?>> converters = restTemplate.getRestTemplate().getMessageConverters();
for (HttpMessageConverter converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
jsonConverter.setSupportedMediaTypes(ImmutableList
.of(new MediaType("application", "x-json", Charset.forName("iso-8859-1"))));
}
}
}
I added the application/x-json and iso8859-1 support to MappingJackson2HttpMessageConverter, it can works well.
This is an workaround, but I want to know why the response content-type is application/x-json;charset=iso-8859-1? I have the produces configuration in my controller
#RequestMapping(method = RequestMethod.GET, value = "/{id}", produces = "application/json;charset=UTF-8")
Does someone know how to config it and let the response use "application/json;charset=UTF-8" content type?
Below is my test method
#Autowired
protected TestRestTemplate restTemplate;
#Test
public void testGetPerformanceObligationById() {
PerformanceObligationEntity entity = restTemplate.getForObject("/performance-obligations/{id}", PerformanceObligationEntity.class, "InvalidId");
Assert.assertNull(entity.getId());
}
I added one filter
#TestConfiguration
static class Config {
#Bean
public CharacterEncodingFilter characterEncodingFilter() {
final CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceEncoding(true);
return characterEncodingFilter;
}
}
Also modify the converter to
#Before
public void init() {
List<HttpMessageConverter<?>> converters =
restTemplate.getRestTemplate().getMessageConverters();
for (HttpMessageConverter converter : converters) {
if (converter instanceof MappingJackson2HttpMessageConverter) {
MappingJackson2HttpMessageConverter jsonConverter = (MappingJackson2HttpMessageConverter) converter;
jsonConverter.setObjectMapper(new ObjectMapper());
jsonConverter.setSupportedMediaTypes(ImmutableList
.of(new MediaType("application", "x-json", Charset.forName("UTF-8"))));
}
}
}
Now I got application/x-json;charset=utf-8, so just remain how to config from application/x-json to application/json

File upload Restful API: Spring-boot

I'm trying to make image uploading but I get this error, and I don't know why. I've already tried many things but I'm still getting errors.
Firstly, this:
{
"timestamp": 1454645660390
"status": 405
"error": "Method Not Allowed"
"exception": "org.springframework.web.HttpRequestMethodNotSupportedException"
"message": "Request method 'POST' not supported"
"path": "/usuarios/update"
}
This is my controller:
Note: returns null for testing.
#RequestMapping(value = "/update", method = RequestMethod.POST, headers = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Usuarios> updateUsuario(
OAuth2Authentication authentication,
HttpServletRequest req,
#RequestBody Usuarios usuarios,
#RequestParam("file") MultipartFile file) {
req.getHeaderNames();
file.getName();
return null;
}
And this is my MultipartResolver:
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(1000000);
return resolver;
}
Any suggestions what I'm doing wrong? Thank you so much!
UPDATE
I've updated my #Bean:
#Configuration
#ComponentScan
#EnableAutoConfiguration
public class TierraApplication {
public static void main(String[] args) {
SpringApplication.run(TierraApplication.class, args);
}
#Bean
public MultipartConfigElement multipartConfigElement() {
return new MultipartConfigElement("");
}
#Bean
public MultipartResolver multipartResolver() {
CommonsMultipartResolver resolver = new CommonsMultipartResolver();
resolver.setMaxUploadSize(1000000);
return resolver;
}
}
and the method on my #RestController:
#RestController
#RequestMapping("/usuarios")
public class UsuariosController implements Serializable {
#RequestMapping(value = "/update", method = RequestMethod.POST, headers = "content-type=multipart/form-data")
public ResponseEntity<Usuarios> updateUsuario(
#RequestBody Usuarios usuarios,
#RequestParam("file") MultipartFile file) {
file.getName();
return null;
}
}
but now i'm getting this error:
{
"timestamp": 1454683574928
"status": 415
"error": "Unsupported Media Type"
"exception": "org.springframework.web.HttpMediaTypeNotSupportedException"
"message": "Content type 'multipart/form-data;boundary=----WebKitFormBoundary6GTTqiBmiacyW0xb;charset=UTF-8' not supported"
"path": "/usuarios/update"
}
EDIT 2
Ok, I've deleted the #Bean of multipartResolver and #RequestBody and all works fine.
#RequestMapping(value = "/update", method = RequestMethod.POST)
public ResponseEntity<?> updateUsuario(#RequestParam("file") MultipartFile file,
OAuth2Authentication authentication,
HttpServletRequest req) {
try {
} catch (Exception e) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(name, HttpStatus.OK);
}
But now I can't reach my body in the request. If I put it got again all the same errors. So how can I pass or reach the body with a JSON like this?
{
"idUsuario": 1,
"roles":{"idRol": 1, "nombreRol": "ADMINISTRADOR", "fechaCreacion": "2016-01-31", "fechaModificacion": null,…},
"nombre": "User",
"apellido": "Test",
"fechaNacimiento": "1992-04-04",
"dni": 38078020,
"email": "test#hotmail.com",
"telefono": 155797919,
"domicilio": "test 972",
"provincia": "San Salvador de Jujuy",
"username": "tester",
"imagen": null,
"estado": true,
"fechaCreacion": "2016-02-03",
"fechaModificacion": null,
"idUsuarioCreacion": 1,
"idUsuarioModificacion": 0,
"passwordUsuario": "$2a$10$SGueYkRnMkL43Ns1nmA9NeONLLrqjChHtYwO8eh/LrMJlTkFHielW"
}
OK. That's the problem.
#RestController("/usarios")
sets the name of the controller not the urlmapping. You should annotate you class with
#RestController
#RequestMapping("/usarios")
to set the correct urlmapping for your service.

The specified HTTP method is not allowed for the requested resource

I am using spring 4.1 and my Rest Controller signature looks like:
#RestController
#RequestMapping("/api/device")
public class ApiRestController {
public ResponseEntity<Response> singleResponse() {
System.out.println("SDR GET");
SingleDataResponse res = new SingleDataResponse();
res.setCmd("8028");
res.setData("xyz");
res.setRfu("rfu");
res.setSid("99");
return new ResponseEntity<Response>(res, HttpStatus.OK);
}
#RequestMapping(value = "/single-res-post", method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Response> singleResponsePost(
#RequestBody SingleDataRequest req, HttpServletRequest request,
HttpServletResponse response) {
System.out.println("SDR Post");
SingleDataResponse res = new SingleDataResponse();
res.setCmd(req.getCmd());
res.setRfu(req.getRfu());
res.setSid(req.getSid());
res.setData("0");
return new ResponseEntity<Response>(res, HttpStatus.OK);
}
}
I have added the below Bean in my WebMvcConfig
#Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
adapter.setCacheSecondsForSessionAttributeHandlers(0);
final MappingJackson2HttpMessageConverter mappingJacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
List<HttpMessageConverter<?>> httpMessageConverter = new ArrayList<HttpMessageConverter<?>>();
httpMessageConverter.add(mappingJacksonHttpMessageConverter);
String[] supportedHttpMethods = { "POST", "GET", "HEAD" };
adapter.setMessageConverters(httpMessageConverter);
adapter.setSupportedMethods(supportedHttpMethods);
return adapter;
}
I am using HttpClient for Get and Post to access the above rest api
I able to acess the Get Request but while sending the Post request I am getting the response
<!DOCTYPE html>
<html><head><title>Apache Tomcat/8.0.12 - Error report</title></head>
<body>
<h1>HTTP Status 405 - Request method 'POST' not supported</h1>
<p><b>message</b> <u>Request method 'POST' not supported</u></p>
<p><b>description</b> <u>The specified HTTP method is not allowed for the requested resource.</u></p>
</body></html>
Kindly suggest
The code used to send the post request
public static void verifyIreoWSPost() throws Exception {
String wms = "http://localhost:8080/test-rest/api/device/single-res-post";
Map<String, String> headers = new HashMap<String, String>();
String json = "{\"sid\":\"99\",\"rfu\":\"rfu\",\"cmd\":\"8028\",\"data\":\"xyz\"}";
headers.put(HttpHeaders.CONTENT_TYPE, "application/json");
headers.put("username", "admin");
headers.put("password", "admin");
String response = HttpUtils.sendPost(wms, headers, json);
System.out.println("post response: " + response);
}

Resources