Spring asyncRestTemplate for SOAP Services - spring

I am trying to call a soap service using Spring's AsyncRestTemplate.
I know that AsyncRestTemplate supports only rest call and spring-ws is there if we need to make soap calls. But Spring-ws doesn't support Async calls and uses JDK's HttpURLConnection class for doing http call and I wanted to make async soap webservices call.
Below is my code for creating the soapenvelop using JDKs saaj api.
public SOAPEnvelope createSoapEnvelope(Employee obj){
MessageFactory factory = MessageFactory.newInstance();
SOAPMessage message = factory.createMessage();
SOAPPart soapPart = message.getSOAPPart();
try {
SOAPEnvelope envelope = soapPart.getEnvelope();
SOAPBody body = envelope.getBody();
QName bodyName = new QName(Constants.SERVICE_NAMESPACE);
SOAPBodyElement bodyElement = body.addBodyElement(bodyName);
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
Document document = db.newDocument();
// Marshal the Object to a Document
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(obj, document);
body.addDocument(document);
return envelope;
}catch (SOAPException | JAXBException | ParserConfigurationException e){
LOGGER.error("Unable to marshal ",e);
}
return null;
}
I set this soap envelop in HttpEntity to make the call though rest template like below
MultiValueMap headers = new HttpHeaders();
headers.set(HttpHeaders.ACCEPT,"text/xml;charset=UTF-8");
headers.set(HttpHeaders.CONTENT_TYPE,"text/xml;charset=UTF-8");
headers.set(HttpHeaders.ACCEPT_ENCODING,"gzip,deflate");
headers.set("SOAPAction", Constants.SOAP_ACTION);
HttpEntity<SOAPEnvelope> soapEntity = new HttpEntity<>(soapEnvelope,headers);
ListenableFuture<ResponseEntity<SOAPEnvelope>> future=
restTemplate.postForEntity(url,
,soapEntity,SOAPEnvelope.class);
After doing this I get exception org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [com.sun.xml.internal.messaging.saaj.soap.ver1_1.Envelope1_1Impl] and content type [text/xml;charset=UTF-8]
I understood from this exception that Spring's HttpMessageConverters are not able to marshal SoapEnvelop and that's why this client is not able to submit the request.
I need help in writing custom message converter and registering it with rest template. All suggestions are welcome.
Thanks

Related

REST API call from spring boot not working

I am trying to fetch live data from NSE options trading. Below code is not working and the request made is stuck without any response.
Any workaround on this?
public void getLiveBankNiftyData() {
String RESOURCE_PATH = "https://www.nseindia.com/api/option-chain-indices?symbol=BANKNIFTY";
ResponseEntity<Object[]> responseEntity = restTemplate.getForEntity(RESOURCE_PATH, Object[].class);
Object[] objects = responseEntity.getBody();
}
i tried this
// request url
String url = "https://www.nseindia.com/api/option-chain-indices?symbol=BANKNIFTY";
// create an instance of RestTemplate
RestTemplate restTemplate = new RestTemplate();
// make an HTTP GET request
String json = restTemplate.getForObject(url, String.class);
// print json
System.out.println(json);
I found a way out. Instead of using RestTemplate I used WebClient and this solved the issue.

Instantiate IWebContext inside JmsListener in Spring

I have a Spring app running as a rest api.
Let's assume that at some point, a message with some info is generated and stored in a AWS SQS queue.
When JMSListener is called, Im trying to generate a pdf report with thymeleaf and openhtmltopdf. I'm having troubles while instantiating IWebContext because it needs HttpServletRequest, HttpServletResponse, and Locale as params. Locale is not a problem as I could include it as a part of the SQS message, but I'm stuck with REQ and RES.
Code i'm using:
IWebContext ctx = new WebContext(¿REQUEST?, ¿RESPONSE?, servletContext, locale, mapParams);
String processedHtml = templateEngine.process(template, ctx);
try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useSVGDrawer(new BatikSVGDrawer());
builder.useFastMode();
builder.withHtmlContent(processedHtml, baseUrl);
builder.toStream(bos);
builder.run();
return bos.toByteArray();
} catch (Exception e) {
logger.error("xxx");
}
As it is being called inside #JmsListener(destination = "${aws.sqs.queue.name}") annotated method, I cannot use none of the following options:
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
Because:
RequestContextHolder.getRequestAttributes()
is always null.
Thanks and regards.
I don't think you should be using an IWebContext for this. Instead, just use org.thymeleaf.context.Context.

How can SOAP be used with Spring Reactor's WebClient?

I've managed to build an SSL connection to the sandbox server and to send the object as a serialised XML object by applying the content type MediaType.APPLICATION_XML. However, this is not enough as the target service only supports SOAP and expects the message properly wrapped in an envelope.
final var webClient = WebClient.builder()
.baseUrl(fmdConfiguration.getSinglePackUrl())
.clientConnector(connector)
.exchangeStrategies(exchangeStrategies)
.filter(logResponseStatus())
.filter(logRequest())
.build();
return webClient
.method(GET)
.contentType(MediaType.APPLICATION_XML)
.body(BodyInserters.fromObject(request))
.retrieve()
.bodyToMono(SinglePackPingResponse.class);
This is the response from the service:
Unable to create envelope from given source because the root element is not named "Envelope"
Unfortunately the the WebClient doesn't support the media type application/soap+xml. When I try to use it, then the WebClient throws the following error:
org.springframework.web.reactive.function.UnsupportedMediaTypeException: Content type 'application/soap+xml;charset=UTF-8' not supported for bodyType=eu.nmvs.SinglePackPingRequest
at org.springframework.web.reactive.function.BodyInserters.unsupportedError(BodyInserters.java:300)
I use:
private void acceptedCodecs(ClientCodecConfigurer clientCodecConfigurer) {
clientCodecConfigurer.customCodecs().encoder(new Jackson2JsonEncoder(new ObjectMapper(), TEXT_XML));
clientCodecConfigurer.customCodecs().decoder(new Jackson2JsonDecoder(new ObjectMapper(), TEXT_XML));
}
and:
webClient = webClientBuilder
.baseUrl(baseUrL)
.filter(logRequest())
.exchangeStrategies(ExchangeStrategies.builder().codecs(this::acceptedCodecs).build()).build();

How to handle exceptions with Swagger?

I am building some test APIs using swagger (1.5) and JAX-rs with Jersey (1.13) and I m trying to implement exception handling. For example I have the following code when receiving the results from my DB (Elasticsearch)
#POST
#Path("/category")
#ApiOperation(value="returns products")
#Produces({ "application/json" })
public Response getPostCategories(
#ApiParam(value="keyphrase, required=true) #QueryParam("keyphrase") String keyphrase,
#ApiParam(value="category) #QueryParam("category") String category,
#Context SecurityContext securityContext)
throws WebApplicationException {
SearchRequest searchRequest = new SearchRequest();
searchRequest.setKeyphrase(keyphrase);
searchRequest.setCategory(category);
SearchCategoryQuery categoryQuery = new SearchCategoryQuery();
String searchResponse = null;
try
{
searchResponse = categoryQuery.searchCategory(searchRequest);
}
catch (WebApplicationException ex)
{
throw new WebApplicationException(Response.status(Status.BAD_REQUEST).entity("results no found").type(javax.ws.rs.core.MediaType.APPLICATION_JSON).build());
}
return Response.ok(searchResponse).build();
}
However, in the output swagger always prints the same response
What I need instead is to receive the error messages I specify in each exception. Any ideas?
Swagger by itself does not handle application exceptions as yet.
You will either need to create custom Exception classes (that extend java.lang.exception) or use the existing ones (like WebApplicationException that you are already using) and make the API definition throw these errors. So basically you need to use Java/J2EE/Jersey to throw proper exceptions. Swagger UI will display them for you.
Check this link for details on REST exception handling with Spring.

Spring Rest Template to send JsonArray

I am using spring rest template to send json array as request. Source code to send request is as follow:
JSONArray jsonArray = new JSONArray();
for (Iterator iterator = itemlist.iterator(); iterator.hasNext();) {
Item item = (Item)iterator.next();
JSONObject formDetailsJson = new JSONObject();
formDetailsJson.put("id", item.getItemConfId());
formDetailsJson.put("name", item.getItems().getItemName());
formDetailsJson.put("price", item.getPrice());
formDetailsJson.put("Cost",item.getCost());
jsonArray.put(formDetailsJson);
}
List<MediaType> acceptableMediaTypes = new ArrayList<MediaType>();
acceptableMediaTypes.add(MediaType.APPLICATION_JSON);
// Prepare header
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
// Pass the new person and header
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
System.out.println("Json Object : "+entity);
// Send the request as POST
try {
ResponseEntity<String> result = restTemplate.exchange("my url", HttpMethod.POST, entity, String.class);
} catch (Exception e) {
logger.error(e);
return "Connection not avilable please try again";
}
And to accept request:
#RequestMapping(value = "/testStock", method = RequestMethod.POST,headers="Accept=application/xml, application/json")
public #ResponseBody int testStock(#RequestBody List<ItemList> jsonArray) {
logger.debug("Received request to connect ms access : "+jsonArray.size());
//int returnSizecount = stockList.getStocklst().size();
return 1;
}
The problem is that it giving me following error:
Could not write request: no suitable HttpMessageConverter found for request type [org.json.JSONArray].Any suggestion is greatly acceptable.
There are no MessageConverter for JSONArray, so I suggest do the following.
HttpEntity<JSONArray> entity = new HttpEntity<JSONArray>(jsonArray, headers);
Convert Class JSONArray to String, and add that to HttpEntity, you know use toString
java.lang.String toString()
Make a JSON text of this JSONArray.
HttpEntity entity = new HttpEntity(jsonArray.toString(), headers);
Or change to Jackson implementation Spring have support to that. XD
If you dont want to do the above, consider create your own implementation of messageConverter, that will work but is harder
update
HttpHeaders headers = new HttpHeaders();
headers.setAccept(acceptableMediaTypes);
headers.setContentType(MediaType.APPLICATION_JSON);
update 2 Change endpoint to.
#RequestMapping(value = "/testStock", method = RequestMethod.POST)
public #ResponseBody int testStock(#RequestBody String jsonArray) {
you need to have httpmessageconverter configured for your resttemplate, please read my post for configuring http message conveter for you webservice
http://stackoverflow.com/questions/19963127/new-to-spring-and-jackson-2-what-does-this-bean-declaration-allow-for-in-a-spri/19973636#19973636.
and for you problem to convert your http request to json you might add this entry in your restemplate configuration
<bean id="jsonMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter"/>
The error is quite straightforward. You do not have a converter for the JSONArray. Converting the array to a String (using toString) did help you here, but there is a better way:
Just add a converter for the json.org objects:
Add this to your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-json-org</artifactId>
</dependency>
And then on your ObjectMapper add the JsonOrgModule:
mapper.registerModule(new JsonOrgModule());

Resources