Good afternoon,
I am using an Outbound Gateway to call a service that can consume (non-SOAP) XML and produces (non-SOAP) XML. I can marshall the JAXB class to request XML but the I can't unmarshal the response XML back to JAXB classes, the body of the payload is null.
The flow is as follows
.subFlowMapping("SomeRequestType", subflow -> subflow
.transform(someRequestTransformer)
.enrichHeaders(header -> header.header("Content-Type","application/xml"))
.handle(someServiceOutboundGateway)
.transform(someResponseTransformer)
)
From someServiceOutboundGateway
@Bean
public HttpMessageConverter m() {
MarshallingHttpMessageConverter c = new MarshallingHttpMessageConverter();
c.setMarshaller(someMarshaller());
c.setUnmarshaller(someUnMarshaller());
return c;
}
@Bean(name="someServiceOutboundGateway")
public MessageHandler someOutboundGateway() {
return Http.outboundGateway(someUrl, lnquiHttp())
.httpMethod(HttpMethod.POST)
.expectedResponseType(Response.class)
.get();
}
@Bean
public RestTemplate lnquiHttp() {
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(connections);
connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute);
RequestConfig requestConfig = RequestConfig
.custom()
.setConnectionRequestTimeout(timeout) // timeout to get connection from pool
.setSocketTimeout(timeout) // standard connection timeout
.setConnectTimeout(timeout) // standard connection timeout
.build();
HttpClient httpClient = HttpClientBuilder.create()
.setConnectionManager(connectionManager)
.setDefaultRequestConfig(requestConfig).build();
ClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(httpClient);
RestTemplateBuilder restTemplateBuilder = new RestTemplateBuilder();
RestTemplate restTemplate = restTemplateBuilder
.requestFactory(requestFactory)
.basicAuthorization(userName, password)
.messageConverters(m())
.build();
return restTemplate;
}
@Bean
public Marshaller someMarshaller() {
final Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
marshaller.setContextPath(CONTEXTPATH_REQUEST);
marshaller.setSchema(responseSchema);
marshaller.setSupportJaxbElementClass(Boolean.TRUE);
return marshaller;
}
@Bean
public Unmarshaller someUnMarshaller() {
final Jaxb2Marshaller unmarshaller = new Jaxb2Marshaller();
unmarshaller.setContextPath(CONTEXTPATH_RESPONSE);
unmarshaller.setSchema(responseSchema);
unmarshaller.setSupportJaxbElementClass(Boolean.TRUE);
return unmarshaller;
}
@Bean(name = "someJAXBContext")
public JAXBContext someJAXBContext() throws JAXBException {
return JAXBContext.newInstance(Response.class);
}
from someResponseTransformer
@Component
public class SomeResponseTransformer implements GenericHandler<Object> {
@Override
public Object handle(final Object payload, final Map<String, Object> headers) {
ResponseEntity responseEntity = (ResponseEntity)payload;
Object body = responseEntity.getBody();
Response lnqiResponse = (Response)body;
... = buildHeader(lnqiResponse.getHeader());
When I am trying the get the header (lnqiResponse.getHeader()
) I am getting a NullPointerException.
Any idea please how to unmarshall the response to the Response
? Any help would be appreciated!
Thanks!
After unmarshalling the input payload for your SomeResponseTransformer.handle()
method is not going to be a ResponseEntity
, but rather that .expectedResponseType(Response.class)
.
I'm not sure what is CONTEXTPATH_RESPONSE
, but I usually prefer to use setClassesToBeBound()
instead. Also, the Jaxb2Marshaller
by default expects from us an @XmlRootElement
on the class to be bound.
Then, when response arrives from the server, you need to be sure that Content-Type
header is what is supported by that MarshallingHttpMessageConverter
:
/**
* Protected constructor that sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes}
* to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}.
*/
protected AbstractXmlHttpMessageConverter() {
super(MediaType.APPLICATION_XML, MediaType.TEXT_XML, new MediaType("application", "*+xml"));
}
It might be better from here to start debugging your calls and see what RestTemplate
does in its doExecute()
around requestCallback.doWithRequest(request);
and responseExtractor.extractData(response)
.