Background
I have the following code that uses RestTemplate to publish requests to a web service.
public class Service {
public static OutputDTO calculate(InputDTO inputDTO) throws ProcessException {
OutputDTO outputDto = null;
try {
RequestProperties props = RequestProperties.getPropsInstance();
String requestProcessorUrl = props.getRequestProcessorUrl();
RestTemplate restTemplate = new RestTemplate();
MappingJackson2HttpMessageConverter httpMessageconvertor = new MappingJackson2HttpMessageConverter();
restTemplate.getMessageConverters().add(httpMessageconvertor);
List<MediaType> mediaTypeList = new ArrayList<>();
mediaTypeList.add(MediaType.APPLICATION_JSON);
httpMessageconvertor.setSupportedMediaTypes(mediaTypeList);
outputDto = restTemplate.postForObject(requestProcessorUrl, inputDTO, OutputDTO.class);
} catch (ApplicationPropertiesException e) {
throw new ProcessException("PublisherService calculate() caught ApplicationPropertiesException", e, 1);
} catch (Exception e) {
throw new ProcessException("PublisherService calculate() caught unexpected Exception", e, 1);
}
return outputDto;
}
}
The above code is called concurrently by multiple threads each passing an InputDTO
that is the input request object to be sent to the Web Service. The problem I am facing is that I sometimes get a 400 bad request when one of the threads calls the calculate
method for the same input data set. That is, the code works perfectly fine for one end to end run but fails with a 400 bad request with the same input data set for other end to end runs.
Stack Trace
Caused by: com.mycompany.adapter.processor.ProcessException: Service calculate() caught unexpected Exception at com.mycompany.adapter.service.Service.calculate(Service.java:42)
at com.mycompany.adapter.processor.Processor$RequestSender.send(Processor.java:430) ... 6 more Caused by: org.springframework.web.client.HttpClientErrorException: 400 Bad Request at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91) at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:641) at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:597) at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:557) at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:357) at com.mycompany.adapter.service.Service.calculate(Service.java:38)
Edit : What I have tried so far
I added the following code in the catch(Exception e)
block shown in the code above :
catch (Exception e) {
ObjectMapper mapper = new ObjectMapper();
String jsonInString="";
try {
jsonInString = mapper.writeValueAsString(inputDTO);
} catch (JsonProcessingException e) {
logger.log(Level.SEVERE, "Exception while trying to convert dto to json ", ((Throwable)e));
}
try(BufferedWriter br = new BufferedWriter(new FileWriter("json.txt",true))) {
br.write("jsonstring is --> "+jsonInString);
} catch(Exception e) {
logger.log(Level.SEVERE, "Exception while trying to write json ", ((Throwable)e));
}
}
My expectation here was that in case of a "bad request error", the call to mapper.writeValueAsString(inputDTO)
would have thrown an exception but this was not the case as the corresponding log statement in the catch
block surrounding this statement was not printed.
Next, as you can see, I dumped the json string that was causing the bad request issue into a file to investigate if it is malformed. I tried parsing the json string into a JSON object/array using this approach it and it came out as a valid JSON string.
Question(s)
- Are the
RestTamplate
and related Spring APIs that I am using in my code above thread-safe? - What could be the reason behind a bad request error occurring for one run whereas other runs with the same input data set work fine?
- What further investigation can I carry to narrow down the issue? I tried finding the
InputDTO
objects for which I get the bad request exception. I then ran my code only for those records but the bad request error is not reproducible when I take the same records and run the code only for these records. - One of the comments to this answer states that this is a concurrency issue but as explained earlier, the JSON string causing the bad request is apparently a valid string if you try parsing it. Moreover, I am absolutely sure that the
inputDTO
is not modified by any other thread as each thread creates it's owninputDTO
locally in itsrun/call
method and passes it to thecalculate
method. TheinputDTO
is not shared across threads.