RestTemplate RestClientException Could not extract response: no suitable HttpMessageConverter found - spring

I am getting this error when calling the RestTemplate method
GetStatusRestfulResponse response = restTemplate.getForObject(restRequest.getUrl(), GetStatusRestfulResponse.class,restRequest.getParams());
>org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [class GetStatusRestfulResponse] and content type [application/json]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:108)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:550)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:511)
at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:248)
RestTemplate restTemplate = new RestTemplate();
HttpClient httpClient = HttpClientBuilder.create().setDefaultCredentialsProvider(setupAuthentication(restRequest)).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
requestFactory.setReadTimeout(restRequest.getReqTimeOut());
restTemplate.setRequestFactory(requestFactory);
restTemplate.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
response = restTemplate.getForObject(restRequest.getUrl(), GetStatusRestfulResponse.class,restRequest.getParams());

I was able to solve the issue . the culprit was the java object I was using GetStatusRestfulResponse.
I took the following steps to debug the issue.
Got the source codes for spring-web and jackson-databind.
on debugging in the spring and jackson source code, realized that the issue was with the ObjectMapper not able to deserialize the java object.
The issue was that my Java object had inner classes .
in order to fix the problem with ObjectMapper not able to deserialize the java object , I had to
Add default no parameter constructors for the main java class and inner classes.
Made the inner classes static.
this solved the issue :)

Related

How to do java unit test with protobuf for controller?

I have a spring boot rest controller with requestBody & responseBody both protobuf. like below :
#RequestMapping(value = "/position/open", produces = "application/x-protobuf")
#ResponseBody
public MsgProto.Response positionOpen(#RequestBody MsgProto.Request request)throws Exception {
log.info("start /position/open");
return orderPositionService.addOrder(request);
}
Now I want to do a unit test using mockMvc to test the controller, but it failed every time. I believe it is the code below which is wrong to fire an HTTP request with protobuf, any idea how to resolve it?
mockMvc.perform(post("/position/open").contentType("application/x-protobuf")
.content(ObjectsMock.mockMsgProtoRequest().toByteArray())).andDo(print())
.andExpect(status().isOk());
Exception :
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException
MockHttpServletResponse:
Status = 415
Error message = null
Headers = [Accept:"application/json, application/octet-stream,
application/xml, application/*+json, text/plain, text/xml, application/x-www-
form-urlencoded, application/*+xml, multipart/form-data, multipart/mixed, */*"]
I assume the ProtobufHttpMessageConverter is missing here. Spring MVC can't read/write any messages without this specific converter.
You can create it as the following:
#Bean
public ProtobufHttpMessageConverter protobufHttpMessageConverter() {
return new ProtobufHttpMessageConverter();
}
Next, make sure to add the HTTP Method to your method, as I assume (from reading your test) you want this to be a HTTP POST handler. You can also add the consumes attribute to state that this endpoint also consumes Protobuf.
#RequestMapping(method = RequestMethod.POST, consumes = "application/x-protobuf", value = "/position/open", produces = "application/x-protobuf")
#ResponseBody
public MsgProto.Response positionOpen(#RequestBody MsgProto.Request request)throws Exception {
log.info("start /position/open");
return orderPositionService.addOrder(request);
}
In addition to this, there is an article on the Spring blog available that covers your usecase and explains how to use Protobuf with Spring MVC.
You need to add Protobuf converter to MockMvc builder
MockMvcBuilders.standaloneSetup(controller)
.setMessageConverters(new ProtobufHttpMessageConverter())
.build()
This fixed the issue for me

MessageConverter issue while using RestTemplate with StreamingResponseBody

We have a REST API (server side) implemented using Spring Boot. This API is streaming a PDF file as StreamingResponseBody wrapped in ResponseEntity where content-type is given as MediaType.APPLICATION_OCTET_STREAM.
I am trying to access this API from client application with the help of RestTemplate. This client application is again a Spring Boot app. This client application is existing and this was supporting MappingJackson2HttpMessageConverter with two supportive media types so far.
application/json and application/x-www-form-urlencoded
I followed few suggestions and tried with these items
Added MediaType.APPLICATION_OCTET_STREAM to existing
MappingJackson2HttpMessageConverter
Added ByteArrayHttpMessageConverter which has a default support to MediaType.APPLICATION_OCTET_STREAM
Added ResourceHttpMessageConverter which supporting streaming response.
But with all these suggestions I was facing the following errors. At this point of time I am not really sure if is there anything that I am missing from configuration. Team, it will be of a great help really if you can redirect me to a short examples or solutions in achieving this integration.
org.springframework.web.client.RestClientException: Error while extracting response for type [interface org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody] and content type [application/octet-stream]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('%' (code 37)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false'); nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('%' (code 37)): expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false') at [Source: (PushbackInputStream); line: 1, column: 2]
This following error was when I tried with ByteArrayHttpMessageConverter (or) ResourceHttpMessageConverter
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody] and content type [application/octet-stream]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:123) ~[spring-web-5.2.6.RELEASE.jar!/:5.2.6.RELEASE]
Updating Question with the current implementation:
This is how resttemplate bean I am creating.
#Bean
public RestTemplate restTemplate() {
final RestTemplate restTemplate = new RestTemplate(httpRequestFactory());
final List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
final MappingJackson2HttpMessageConverter converter = new
MappingJackson2HttpMessageConverter();
final List<MediaType> mediaTypes = new ArrayList<>();
mediaTypes.add(MediaType.APPLICATION_JSON);
mediaTypes.add(MediaType.APPLICATION_FORM_URLENCODED);
//mediaTypes.add(MediaType.APPLICATION_OCTET_STREAM)
converter.setSupportedMediaTypes(mediaTypes);
messageConverters.add(converter);
restTemplate.setMessageConverters(messageConverters);
return restTemplate;
}
And my API client call is
ResponseEntity<StreamingResponseBody> response = reportRestTemplate.exchange(builder.buildAndExpand(uriParams).toUriString(),HttpMethod.GET,entity,StreamingResponseBody.class,uriParams);

Could not write request: no suitable HttpMessageConverter found for request type

I have used to RestTemplate class to call a rest service, I am getting the below exception.
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [UmlerUpdateRequest]
The below is my code snippet that I have tried:
RestTemplate restTemplate = new RestTemplate();
UmlerUpdateRequest obj= new UmlerUpdateRequest();
obj.setTrnspEqpId(equipId);
obj.setLstMaintId(lesseeScac);
obj.setRecLseScac(userId);
obj.setTareWgt(tareWeight);
obj.setBldD(builtDate);
String returns = restTemplate.postForObject(url, obj, String.class);
Can anyone help me on this?

406 error while mocking File Download REST API using MockMVC

I am implementing a REST API using Spring framework, which returns
return new ResponseEntity<>(new InputStreamResource(myInputStream),
responseHeaders, HttpStatus.OK);
REST API is declared as:
#RequestMapping(value = "/download", method = RequestMethod.GET,
produces = { MediaType.APPLICATION_OCTET_STREAM_VALUE })
While writing unit test for this API, I am using MockMVC like below:
final MappingJackson2HttpMessageConverter messageConverter =
new MappingJackson2HttpMessageConverter();
messageConverter.setObjectMapper(new ObjectMapper());
messageConverter.getObjectMapper().enable(SerializationFeature.INDENT_OUTPUT);
this.mockMvc =
MockMvcBuilders.standaloneSetup(myController)
.setMessageConverters(messageConverter)
.apply(new RestDocumentationConfigurer()
.withScheme("https").withHost("localhost")
.withPort(443)).build();
And my Test case looks like this:
mockMvc.perform(
org.springframework.test.web.servlet.request.MockMvcRequestBuilders
.get(restUri))
.andExpect(
org.springframework.test.web.servlet.result.MockMvcResultMatchers
.status().isOk())
.andDo(document("myApi")).andReturn();
But I am getting status as error 406.
java.lang.AssertionError: Status expected:<200> but was:<406>
at org.springframework.test.util.AssertionErrors.fail
What I am missing here?
Any help would be much appreciated.
You inject instance of MappingJackson2HttpMessageConverter to MockMvcBuilders which can't deal with converting classes inheriting from Resource. All you need to do is add ResourceHttpMessageConverter to your test specification:
MockMvcBuilders.standaloneSetup(myController)
.setMessageConverters(messageConverter, new ResourceHttpMessageConverter())
Status code 406 means "Not Acceptable", which indicates that the server is missing a header specifying an accepted content type. You'll need to include that in your mockMvc call.

Spring RestTemplate with Jackson throws "Can not resolve BeanPropertyFilter" when using #JsonFilter

Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?
I'm not 100% that's what I need to do but see below for details.
Background:
With help from this StackOverflow post I added #JsonFilter to my domain class and edited my jax-rs web service (implemented in CXF). I'm now successfully able to dynamically select which domain class fields to return in my RESTful API. So far so good.
I'm using Spring's RestTemplate in my JUnit tests to test my RESTful API. This was working fine until I added #JasonFilter to my domain class. Now I'm getting the following exception:
org.springframework.web.client.ResourceAccessException: I/O error: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured; nested exception is org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:453)
rest of stack trace omitted for brevity
Caused by: org.codehaus.jackson.map.JsonMappingException: Can not resolve BeanPropertyFilter with id 'apiFilter'; no FilterProvider configured
at org.codehaus.jackson.map.ser.BeanSerializer.findFilter(BeanSerializer.java:252)
I was getting a similar problem on the server side and was able to resolve it (with help from this post) by giving a FilterProvider to the Jackson ObjectMapper as follows:
ObjectMapper mapper = new ObjectMapper();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.filterOutAllExcept(filterProperties));
Can I do something similar on the RestTemplate side? Any ideas of how to solve this issue are appreciated.
Just to be clear, on the client RestTemplate side I do not want to filter the domain object properties at all.
Can I specify the Jackson ObjectMapper that Spring's RestTemplate uses?
I was able to force RestTemplate to use a customized ObjectMapper by doing the following:
ObjectMapper mapper = new ObjectMapper();
// set a custom filter
Set<String> filterProperties = new HashSet<String>();
FilterProvider filters = new SimpleFilterProvider().addFilter("apiFilter", SimpleBeanPropertyFilter.serializeAllExcept(filterProperties));
mapper.setFilters(filters);
MappingJacksonHttpMessageConverter messageConverter = new MappingJacksonHttpMessageConverter();
messageConverter.setObjectMapper(mapper);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(messageConverter);
restTemplate.setMessageConverters(messageConverters);
This website provided example for part of the above code.
Just adding to the answer. If you are using TestRestTemplate then you can actually get the underlying RestTemplate class and then modify its MappingJackson2HttpMessageConverter to include your filter:
var jackson2HttpMessageConverter = testRestTemplate.getRestTemplate().getMessageConverters().stream()
.filter(mc -> mc instanceof MappingJackson2HttpMessageConverter)
.map(mc -> (MappingJackson2HttpMessageConverter) mc)
.findFirst()
.orElseThrow();
jackson2HttpMessageConverter.getObjectMapper().setFilterProvider(
new SimpleFilterProvider().addFilter("MyFilterName", SimpleBeanPropertyFilter.serializeAll())
);

Resources