Mocking restTemplate returns null - java

For some reason, the following test fails because "response" is null, but it should not, because I use the when() function to return an initialized object. Any idea how to fix it? This is the exact error:
Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
This is the test class:
class UtilsControllerTest {
#Mock
RestTemplate restTemplate=mock(RestTemplate.class);
#Test
void checkPermission() {
boolean permitted = true;
ResponseEntity<PermissionResponseModel> response = ResponseEntity.ok(new PermissionResponseModel(permitted));
when(restTemplate.postForEntity(any(String.class), any(Map.class), any(Class.class)))
.thenReturn(response);
UtilsController utilsController = new UtilsController();
assertTrue(utilsController.checkPermission("69696969", Task.MAKE_REQUEST, restTemplate));
verify(restTemplate, times(1)).postForEntity(any(), any(), any());
}
}
This is the implementation of UtilsController:
public class UtilsController {
private static final String authString = "Authorization";
/**
* Checks if the user is authorised to do a certain task.
*
* #param token the identification token
* #param task the task
* #return true iff user is allowed, false otherwise
*/
public boolean checkPermission(String token, Task task, RestTemplate restTemplate) {
HttpHeaders authHeaders = new HttpHeaders();
authHeaders.setContentType(MediaType.APPLICATION_JSON);
authHeaders.set(authString, token);
String url = "http://localhost:8081/permission";
PermissionRequestModel prm = new PermissionRequestModel();
prm.setTask(task);
HttpEntity<PermissionResponseModel> entity = new HttpEntity(prm, authHeaders);
ResponseEntity<PermissionResponseModel> response =
restTemplate.postForEntity(url, entity, PermissionResponseModel.class);
return response.getBody().isPermitted();
}
}
I tried to mock the returned response entity, it did not work either. Still, the response was null. But in both cases, when I debug it, response has the right value, is not null.

As M. Deinum said, I'm registering the behaviour for a different
postForEntity method. The fix is:
when(restTemplate.postForEntity(anyString(), any(HttpEntity.class), any(Class.class)))
.thenReturn(new ResponseEntity<>(new PermissionResponseModel(permitted), HttpStatus.OK));

Related

How to test InternalServerError using mockito in Repository?

I am writing a test to test the POST method for failure case in the controller.
It returns a 415, I am expecting 500. I have mocked the response using mockito.
ControllerTest
#Test
#DisplayName("POST /customers - Failure")
void createProductShouldFail() throws Exception {
// Setup mocked service
when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/customers").accept(MediaType.APPLICATION_JSON)
.content("{\"name\":\"John\"}");
MvcResult result=mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
// Validate the response code and content type
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
}
Controller
#PostMapping(path = "/customers")
public ResponseEntity<Customer> saveCustomer(#RequestBody Customer customer){
try {
// Create the new product
Customer savedCustomer = customerService.save(customer);
// Build a created response
return ResponseEntity
.created(new URI("/customers/" + savedCustomer.getId()))
.body(savedCustomer);
} catch (URISyntaxException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
Error:
HTTP Method = POST
Request URI = /customers
Parameters = {}
Headers = [Accept:"application/json", Content-Length:"15"]
Body = {"name":"John"}
Session Attrs = {}
Handler:
Type = com.prabhakar.customer.controller.CustomerController
Method = com.prabhakar.customer.controller.CustomerController#saveCustomer(Customer)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.HttpMediaTypeNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 415
Error message = null
Headers = [Accept:"application/json, application/*+json"]
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
org.opentest4j.AssertionFailedError:
Expected :500
Actual :415
But 415-Unsupported Media Type client error response code.
I have used the same payload for this method,it works.
#Test
#DisplayName("POST /customers - Success")
void createProductShouldSucceed() throws Exception {
// Setup mocked service
Customer mockCustomer = new Customer(1L, "John");
when(customerService.save(any(Customer.class))).thenReturn(mockCustomer);
this.mockMvc.perform(post("/customers")
.contentType(MediaType.APPLICATION_JSON)
.content("{\"name\":\"John\"}"))
// Validate the response code and content type
.andExpect(status().isCreated())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
//Validate returned json fields
.andExpect(jsonPath("$.id").value(1L))
.andExpect(jsonPath("$.name").value("John"));
}
Update I have added
#RestController
#EnableWebMvc
this throws an error as mocked But the code breaks near mockmvc.perform.
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError
How can I verify if this is working.
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
There are two thing you must have in account to solve the problem:
First, Instead of use .accept(MediaType.APPLICATION_JSON) you must use .contentType(MediaType.APPLICATION_JSON).
Second, the other thing you must have in account is, if you are not handling the exception (using a controller advice or other way) you must do it, because when you execute the firts step you will receive the following error:
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.springframework.web.client.HttpServerErrorException$InternalServerError
The workaround that I took was use #ExceptionHandler in the CustomerController to test your code (this isn't the best place to do this, depending what you are doing. Instead use a #ControllerAdvice. You can find some examples here https://www.baeldung.com/exception-handling-for-rest-with-spring).
Below the complete code that are used to recreate your case.
Customer.class
public class Customer {
private Long id;
private String name;
public Customer(Long id, String name) {
this.id = id;
this.name = name;
}
// + getter and setter
}
CustomerController.class
#RestController
public class CustomerController {
private final CustomerService customerService;
public CustomerController(CustomerService customerService) {
this.customerService = customerService;
}
#PostMapping(path = "/customers")
public ResponseEntity<Customer> saveCustomer(#RequestBody Customer customer) {
try {
// Create the new product
Customer savedCustomer = customerService.save(customer);
// Build a created response
return ResponseEntity
.created(new URI("/customers/" + savedCustomer.getId()))
.body(savedCustomer);
} catch (URISyntaxException e) {
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
}
}
// Code used to avoid the error explained in the second step
#ExceptionHandler
public ResponseEntity<?> handlingInternalServerError(HttpServerErrorException.InternalServerError ex) {
// code to be executed when the exception is thrown (logs, ...)
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
CustomerService.class
#Service
public class CustomerService {
public Customer save(Customer customer) {
return customer;
}
}
CustomerControllerTest.class
#SpringBootTest
#AutoConfigureMockMvc
class CustomerControllerTest {
#MockBean
private CustomerService customerService;
#Autowired
private MockMvc mockMvc;
#Test
#DisplayName("POST /customers - Failure")
void saveCustomer() throws Exception {
Customer customerMock = new Customer(1L, "John");
// Setup mocked service
when(customerService.save(any(Customer.class))).thenThrow(HttpServerErrorException.InternalServerError.class);
RequestBuilder requestBuilder = post("/customers")
.content("{\"name\":\"John\"}")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON);
MvcResult result = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = result.getResponse();
// Validate the response code and content type
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(), response.getStatus());
}
}
NOTE: This test was executed using Java 8 and JUnit5
Other NOTE based on your comment:
Ok. #prabhakar-maity, my recommendation based in your case is to use a #ExceptionHandler or #ControllerAdvice instead of try...catch. For example, you have 6 methods in your controller or several controllers and want to handle the same exception (Internal Server Error) and return the same info, so you’ll have to implement a try..catch in each method, while using #ControllerAdive (multiple controllers) or #ExceptionHandler (one controller) you implement your logic in one place
Check this question for more info LINK
You can reference Spring MVC Test Framework - Unsupported Media Type
You may be missing #EnableWebMvc annotation in your controller.
EDIT - for Comment:
Instead of
RequestBuilder requestBuilder = MockMvcRequestBuilders.post("/customers").accept(MediaType.APPLICATION_JSON)
.content("{\"name\":\"John\"}");
MockHttpServletResponse response = result.getResponse();
// Validate the response code and content type
assertEquals(HttpStatus.INTERNAL_SERVER_ERROR.value(),
response.getStatus());
Try:
mockMvc.perform(requestBuilder)
.andExpect(status().isInternalServerError());

JUnit test for void method containing a RestTemplate exchange call

I am trying to write a Test class for one of my methods and I am new to JUnit. My class returns a void and has a RestTemplate.exchange call to an external endpoint.
I started off trying this, but this gives me a NullInsteadOfMockException.
#Test
public void service1test() throws IOException{
ResponseEntity<?> responseEntity = new ResponseEntity<>(HttpStatus.ACCEPTED);
RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
Mockito.verify(restTemplate.exchange(Mockito.anyString(), Mockito.<HttpMethod> any(), Mockito.<HttpEntity<?>> any(), Mockito.<Class<?>> any(),
Mockito.<String, String> anyMap()));
}
Here's my method that I want to write unit test for.
#Autowired
private RestTemplate restTemplate;
public void service1(String a, String b) {
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
this.restTemplate = restTemplateBuilder.build();
HttpHeaders headers = new HttpHeaders();
try {
headers.set("ID", ID);
headers.set("secret", secret);
System.out.println(docStoreUrl + itemID);
HttpEntity requestEntity = new HttpEntity<>(null, headers);
ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, requestEntity, Object.class);
log.info("Status code for get : {}", response.getStatusCodeValue());
if(response.getStatusCodeValue() == 200) {
Object document = (Object) response.getBody();
Class2.service2.execute(document);
}
else {
log.info("Failed to retrieve document due to {}", response.getStatusCodeValue());
}
}
I am new to JUnit testing and can't figure out how to write the Test class for this covering all the lines.
If this question is already answered, please point me to the appropriate URL.
Any help will be greatly appreciated.
Its a little bit late, but if anyone else falls over this:
This error will also occur, if you are using mockito wrong.
It should be:
Mockito.verify(restTemplate).exchange(Mockito.anyString() ...
Notice the closing bracket immediately after restTemplate, so exchange is called on top of mockito.

Springboot test how to resolve controller's parameter to object

I have a method signature like this in controller. when i try to write a unit test for it. it returns 500 instead of 404.
it looks like it is not able to convert the {id} to an Optional
is there any setting I need to do so it can auto convert the parameter to an object?
Thanks
#RequestMapping("/propagationStores")
public class PropagationStoreController {
private StoreRepository storeRepository;
private CustomValidator validator;
public PropagationStoreController(StoreRepository storeRepository) {
this.storeRepository = storeRepository;
}
#GetMapping(value = "/{id}")
public Resource<StoreDto> getById(#PathVariable("id") Optional<Store> storeOptional) {
return storeOptional
.map(StoreConverter::toDto)
.map(store -> {
Resource<StoreDto> resource = new Resource<>(store);
resource.add(new Link("http://localhost").withTitle("localhost"));
return resource;
}).orElseThrow(ResourceNotFoundException::new);
}
when I try to test the getById method using the following code. I am getting 500 instead of 400
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class PropagationStoreControllerIT {
#MockBean
StoreRepository storeRepository;
#MockBean
CustomValidator customValidator;
#Autowired
private MockMvc mockMvc;
#Test
public void testGetById() throws Exception {
when(storeRepository.findById(1l)).thenReturn(Optional.empty());
mockMvc.perform(get("/propagationStores/1")).andDo(print()).andExpect(status().is4xxClientError());
}
}
I was expecting status 404, but I am getting 500.
the log as the following.
MockHttpServletRequest:
HTTP Method = GET
Request URI = /propagationStores/1
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = local.tux.propagation.controller.PropagationStoreController
Method = public org.springframework.hateoas.Resource<local.tux.propagation.dto.Store$StoreDto> local.tux.propagation.controller.PropagationStoreController.getById(java.util.Optional<local.tux.propagation.evaluator.domain.Store>)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 500
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
MockHttpServletRequest:
HTTP Method = GET
Request URI = /propagationStores/1
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = local.tux.propagation.controller.PropagationStoreController
Method = public org.springframework.hateoas.Resource<local.tux.propagation.dto.Store$StoreDto> local.tux.propagation.controller.PropagationStoreController.getById(java.util.Optional<local.tux.propagation.evaluator.domain.Store>)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.web.method.annotation.MethodArgumentConversionNotSupportedException
ModelAndView:
View name = null
View = null
Model = null
FlashMap:
Attributes = null
MockHttpServletResponse:
Status = 500
Error message = null
Headers = []
Content type = null
Body =
Forwarded URL = null
Redirected URL = null
Cookies = []
java.lang.AssertionError: Range for response status value 500
Expected :CLIENT_ERROR
Actual :SERVER_ERROR
Define your controller method as:
public Resource<StoreDto> getById(#PathVariable("id") Optional<String> id) {
......
}
id can be converted to a string or a number, not into a Store class.
I was able to solve the issue by using adding the #TestConfiguration. It looks like
#MockBean interrupt the normal spring boot initialization, it doesn't register the converter. In order to make it work, we need to register ourself.
#TestConfiguration
static class InternalConfig {
#Bean
WebMvcConfigurer configurer() {
return new WebMvcConfigurer() {
#Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(String.class, Store.class, id -> staticRepository.getOne(Long.parseLong(id)));
}
};
}
}

HystrixCommand annotation causing ControllerLinkBuilder to break

I'm trying to apply HATEOAS to my spring boot application using spring-hateoas. This worked fine untill I wrapped my REST calls within a HystrixCommand:
#HystrixCommand(fallbackMethod = "myFallbackMethod")
#RequestMapping(method = RequestMethod.GET, value = "/path")
public ResponseEntity<Resources<Resource<Data>>> getAllData() {
String url = "http://localhost:8080/someotherpath"
ParameterizedTypeReference<Iterable<Data>> responseType = new ParameterizedTypeReference<Iterable<Data>>() {};
ResponseEntity<Iterable<Data>> response = restTemplate.exchange(url, HttpMethod.GET, null, responseType);
if (response.getStatusCode().is2xxSuccessful()) {
Iterable<Data> data = response.getBody();
Resources<Resource<Data>> resources = assembler.toResource(data);
return new ResponseEntity<>(resources, response.getHeaders(), response.getStatusCode());
}
return new ResponseEntity<>(response.getHeaders(), response.getStatusCode());
}
My assembler class that wraps the Data object into a Resource object now throws this error: Could not find current request via RequestContextHolder
If I comment the HystrixCommand annotation out the error is gone and everything works fine.
My assembler class just implements Springs' ResourceAssembler<T, D> interface and overrides the toResource method.
Is there any way I can solve this?
I'm not sure if I can see this as an answer, it's more like a work-around:
#RequestMapping(method = RequestMethod.GET, value = "/path")
public ResponseEntity<Resources<Resource<Data>>> getAllData() {
return getAllDataImpl()
}
#HystrixCommand(fallbackMethod = "myFallbackMethod")
public ResponseEntity<Resources<Resource<Data>>> getAllDataImpl() {
String url = "http://localhost:8080/someotherpath"
ParameterizedTypeReference<Iterable<Data>> responseType = new ParameterizedTypeReference<Iterable<Data>>() {};
ResponseEntity<Iterable<Data>> response = restTemplate.exchange(url, HttpMethod.GET, null, responseType);
if (response.getStatusCode().is2xxSuccessful()) {
Iterable<Data> data = response.getBody();
Resources<Resource<Data>> resources = assembler.toResource(data);
return new ResponseEntity<>(resources, response.getHeaders(), response.getStatusCode());
}
return new ResponseEntity<>(response.getHeaders(), response.getStatusCode());
}
I've put the content of the method that actually does the http request (and needs to be wrapped into a HystrixCommand) in another method.
It works this way but it's definitely not a clean way. So if anyone knows how to solve this in a better way..

Spring RestTemplate Behavior when handling responses with a status of NO_CONTENT

Okay, I have a class NamedSystems, that has as its only field a Set of NamedSystem.
I have a method to find NamedSystems by certain criteria. That's not really important. When it gets results, everything works fine. However, when it can't find anything, and thus returns a null (or empty -- I've tried both ways) set, I get problems. Let me explain.
I'm using the Spring RestTemplate class and I'm making a call like this in a unit test:
ResponseEntity<?> responseEntity = template.exchange(BASE_SERVICE_URL + "?
alias={aliasValue}&aliasAuthority={aliasAssigningAuthority}",
HttpMethod.GET, makeHttpEntity("xml"), NamedSystems.class,
alias1.getAlias(), alias1.getAuthority());
Now, since this would normally return a 200, but I want to return a 204, I have an interceptor in my service that determines if a ModelAndView is a NamedSystem and if its set is null. If so, I then the set the status code to NO_CONTENT (204).
When I run my junit test, I get this error:
org.springframework.web.client.RestClientException: Cannot extract response: no Content-Type found
Setting the status to NO_CONTENT seems to wipe the content-type field (which does make sense when I think about it). So why is it even looking at it?
Spring's HttpMessageConverterExtractor extractData method:
public T extractData(ClientHttpResponse response) throws IOException {
MediaType contentType = response.getHeaders().getContentType();
if (contentType == null) {
throw new RestClientException("Cannot extract response: no Content-Type found");
}
for (HttpMessageConverter messageConverter : messageConverters) {
if (messageConverter.canRead(responseType, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + responseType.getName() + "] as \"" + contentType
+"\" using [" + messageConverter + "]");
}
return (T) messageConverter.read(this.responseType, response);
}
}
throw new RestClientException(
"Could not extract response: no suitable HttpMessageConverter found for response type [" +
this.responseType.getName() + "] and content type [" + contentType + "]");
}
Going up the chain a bit to find out where that Extractor is set, I come to RestTemplate's exchange() method that I used in the test:
public <T> ResponseEntity<T> exchange(String url, HttpMethod method,
HttpEntity<?> requestEntity, Class<T> responseType, Object... uriVariables) throws RestClientException {
HttpEntityRequestCallback requestCallback = new HttpEntityRequestCallback(requestEntity, responseType);
ResponseEntityResponseExtractor<T> responseExtractor = new ResponseEntityResponseExtractor<T>(responseType);
return execute(url, method, requestCallback, responseExtractor, uriVariables);
}
So, it's trying to convert what amounts to nothing because of the supplied response type from the exchange call. If I change the responseType from NamedSystems.class to null, it works as expected. It doesn't try to convert anything. If I had tried to set the status code to 404, it also executes fine.
Am I misguided, or does this seem like a flaw in RestTemplate? Sure, I'm using a junit right now so I know what's going to happen, but if someone is using RestTemplate to call this and doesn't know the outcome of the service call, they would naturally have NamedSystems as a response type. However, if they tried a criteria search that came up with no elements, they'd have this nasty error.
Is there a way around this without overriding any RestTemplate stuff? Am I viewing this situation incorrectly? Please help as I'm a bit baffled.
One more way to solve this would be to make response entity as null as shown below.
ResponseEntity<?> response = restTemplate.exchange("http://localhost:8080/myapp/user/{userID}",
HttpMethod.DELETE,
requestEntity,
null,
userID);
If you still need response headers, try implementing the ResponseErrorHandler.
I believe you should probably look at the ResponseExtractor interface & call execute on the RestTemplate providing your implementation of the extractor. To me it looks like a common requirement to do this so have logged this:
https://jira.springsource.org/browse/SPR-8016
Here's one I prepared earlier:
private class MyResponseExtractor extends HttpMessageConverterExtractor<MyEntity> {
public MyResponseExtractor (Class<MyEntity> responseType,
List<HttpMessageConverter<?>> messageConverters) {
super(responseType, messageConverters);
}
#Override
public MyEntity extractData(ClientHttpResponse response) throws IOException {
MyEntity result;
if (response.getStatusCode() == HttpStatus.OK) {
result = super.extractData(response);
} else {
result = null;
}
return result;
}
}
I've tested this & it seems to do what I want.
To create the instance of the ResponseExtractor I call the constructor & pass the converters from a RestTemplate instance that's been injected;
E.g.
ResponseExtractor<MyEntity> responseExtractor =
new MyResponseExtractor(MyEntity.class, restTemplate.getMessageConverters());
Then the call is:
MyEntity responseAsEntity =
restTemplate.execute(urlToCall, HttpMethod.GET, null, responseExtractor);
Your mileage may vary. ;-)
Here's a simple solution where you can set the default Content-Type for use if it is missing in the response. The Content-Type is added to the response header before it is handed back off to the preconfigured ResponseExtractor for extraction.
public class CustomRestTemplate extends RestTemplate {
private MediaType defaultResponseContentType;
public CustomRestTemplate() {
super();
}
public CustomRestTemplate(ClientHttpRequestFactory requestFactory) {
super(requestFactory);
}
public void setDefaultResponseContentType(String defaultResponseContentType) {
this.defaultResponseContentType = MediaType.parseMediaType(defaultResponseContentType);
}
#Override
protected <T> T doExecute(URI url, HttpMethod method, RequestCallback requestCallback, final ResponseExtractor<T> responseExtractor)
throws RestClientException {
return super.doExecute(url, method, requestCallback, new ResponseExtractor<T>() {
public T extractData(ClientHttpResponse response) throws IOException {
if (response.getHeaders().getContentType() == null && defaultResponseContentType != null) {
response.getHeaders().setContentType(defaultResponseContentType);
}
return responseExtractor.extractData(response);
}
});
}
}
This should now be fixed in Spring 3.1 RC1.
https://jira.spring.io/browse/SPR-7911
Or you could extend RestTemplate and override doExecute(..) and check the response body.
For example here is what I implemented and works for us:
#Override
protected <T> T doExecute(final URI url, final HttpMethod method, final RequestCallback requestCallback, final ResponseExtractor<T> responseExtractor)
throws RestClientException
{
Assert.notNull(url, "'url' must not be null");
Assert.notNull(method, "'method' must not be null");
ClientHttpResponse response = null;
try
{
final ClientHttpRequest request = createRequest(url, method);
if (requestCallback != null)
{
requestCallback.doWithRequest(request);
}
response = request.execute();
if (!getErrorHandler().hasError(response))
{
logResponseStatus(method, url, response);
}
else
{
handleResponseError(method, url, response);
}
if ((response.getBody() == null) || (responseExtractor == null))
{
return null;
}
return responseExtractor.extractData(response);
}
catch (final IOException ex)
{
throw new ResourceAccessException("I/O error: " + ex.getMessage(), ex);
}
finally
{
if (response != null)
{
response.close();
}
}
}
I think you are right.
I'm having a similar problem.
I think we should be getting a ResponseEntity with a HttpStatus of NO_CONTENT and a null body.
I came along a workaround (not sure if it meets your case):
First define a custom interceptor class which implements ClientHttpRequestInterceptor. and check if response.getStatusCode() meets your case (my case is != HttpStatus.NOT_FOUND and response.getBody() length is 0), define a custom class (e.x. DefaultResponseForEmptyRestTemplateBody) which has a static method of type MockClientHttpResponse:
public class RequestResponseInterceptor implements ClientHttpRequestInterceptor {
#Override
public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
ClientHttpResponse response = execution.execute(request, body);
if(response.getStatusCode()!=HttpStatus.NOT_FOUND && response.getBody().readAllBytes().length==0){
response = DefaultResponseForEmptyRestTemplateBody.getResponse(response.getStatusCode());
}
return response;
}
}
public static class DefaultResponseForEmptyRestTemplateBody {
MockClientHttpResponse response;
private static byte[] content = new byte[0];
public static MockClientHttpResponse getResponse(HttpStatus statusCode){
content = "response body is empty".getBytes();
return new MockClientHttpResponse(content, statusCode);
}
}
finally add this interceptor to your restTemplate object as below:
restTemplate.setInterceptors(Collections.singletonList(new RequestResponseLoggingInterceptor()));
and call your restTemplate.postForEntity:
ResponseEntity<String> response = this.restTemplate.postForEntity(baseUrl, requestParams,String.class);

Categories