CXF RestFul Service - Get Post Body Parameters - web-services

I have developed a webservice following the below link, however I am unable to get the request parameters from the POST request body.
http://info.appdirect.com/blog/how-to-easily-build-rest-web-services-with-java-spring-and-apache-cxf
I use the Soap UI to invoke the
service, with "Post QueryString in Message Body" option checked.
So far, I have tried below options, but none seem to work:
Tried MultiValued Map, but the map is always empty.
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(MultivaluedMap form){...}
Tried #FormParam() & #QueryParam as well, but still the params are null in webservice method.
Tried creating a POJO bean with #XmlRootElement annotation, however this time I get an exception saying "SEVERE: No message body reader has been found for class com.wcc.LoginInfo, ContentType: application/x-www-form-urlencoded". LoginInfo is my bean class with two parameters:
#XmlRootElement
public class LoginInfo {
String username;
String password;
....
Below is the service method:
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(LoginInfo logininfo){...}
Below is my cxf-beans.xml file:
<bean .....>
<jaxrs:server id="wccservice" address="/">
<jaxrs:serviceBeans>
<ref bean="wccdocumentservice" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<ref bean="formUrlEncodeProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="wccdocumentservice" class="com.wcc.WCCDocumentServiceImpl" />
<bean id="formUrlEncodeProvider" class="org.apache.cxf.jaxrs.provider.FormEncodingProvider" />
<bean id="jsonProvider" class="org.apache.cxf.jaxrs.provider.json.JSONProvider">
<property name="marshallAsJaxbElement" value="true" />
</bean>
Any ideas on how to retrieve the POST parameters in request body, in the Webservice method?

Guess I was dwelling too much into CXF, missed the simple approach. We can get the Post request parameters in CXF service similar to the way we get the parameters in a Servlet.
For Query Parameters in POST request:
#POST
#Path("/getpostfile/{fileName}")
#Produces("application/pdf")
#Consumes("application/x-www-form-urlencoded")
public Response getPostFile(#PathParam("fileName") String fileName, #Context HttpServletRequest request)
{
System.out.println("id is : " + request.getParameter("id")+", password is : " + request.getParameter("password"));
and for Parameters in POST message body, you may use getBody() method from below link:
Getting request payload from POST request in Java servlet
Hope that helps someone!

Related

How to get Request payload content at Response path class mediator using OMElement - WSO2 APIM ver 3.2.0

I am using WSO2 APIM version 3.2.0.
I have a POST request with the request payload.
In the response message mediation of WSO2 APIM I have added the policy that contains the class mediator that tries to get the payload sent during the request.
OMElement element = (OMElement) mc.getEnvelope().getBody().getFirstOMChild();
log.info("payload: " + element.toString());
The above code snippet prints the response payload content but I need the request payload content at the response path.
Response message mediation with a policy added
Below is the sequence with class mediator
sequence with class mediator
Code snippet inside class mediator
OMElement element = (OMElement) mc.getEnvelope().getBody().getFirstOMChild();
log.info("payload: " + element.toString());
Pls let me know what changes to be done, to get the request payload content.
First, we have to store the request payload in a custom property in the Message Context. Then, we can use that property to retrieve the Request Payload in the Response path of the execution.
For example: You are invoking an API with JSON Payload. So, we have to first capture the sent payload and store it in a custom property in the Message Context. Given below is a sample sequence to perform the same
<?xml version="1.0" encoding="UTF-8"?>
<sequence xmlns="http://ws.apache.org/ns/synapse" name="admin--MockAPI:v1.0.0--In">
<property name="RequestPayload" expression="json-eval($)" />
<log level="custom">
<property name="RequestPayload" expression="$ctx:RequestPayload" />
</log>
</sequence>
Then, in the Response path, inside your custom class mediator, you have to access the RequestPayload property from the MessageContext to extract the stored payload. You can achieve this by using the following snippet
synapseContext.getProperty("RequestPayload");

How do I set the WS-Addressing MessageId header when using CXF with Apache Camel?

I'm invoking a web service that requires WS-Addressing SOAP headers. I'm using Apache Camel with CXF to invoke the web service. When I configure the CXF endpoint with the web service's WSDL, it's smart enough to automatically add WS-Adressing SOAP headers, but I need to set a custom MessageId.
Here is the message that is currently being sent:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope">
<soap:Header>
<ws:international xmlns:ws="http://www.w3.org/2005/09/ws-i18n">
<ws:locale xmlns:ws="http://www.w3.org/2005/09/ws-i18n">en_CA</ws:locale>
</ws:international>
<fram:user wsa:IsReferenceParameter="true" xmlns:fram="http://wsbo.webservice.ephs.pdc.ibm.com/Framework/" xmlns:wsa="http://www.w3.org/2005/08/addressing">BESTSystem</fram:user>
<Action soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">http://webservice.ephs.pdc.ibm.com/Client/QueryHumanSubjects</Action>
<MessageID soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">urn:uuid:945cfd10-9fd2-48f9-80b4-ac1b9f3293c6</MessageID>
<To soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">https://panweb5.panorama.gov.bc.ca:8081/ClientWebServicesWeb/ClientProvider</To>
<ReplyTo soap:mustUnderstand="true" xmlns="http://www.w3.org/2005/08/addressing">
<Address>http://www.w3.org/2005/08/addressing/anonymous</Address>
</ReplyTo>
</soap:Header>
<soap:Body>
<ns2:queryHumanSubjectsRequest xmlns:ns2="http://wsbo.webservice.ephs.pdc.ibm.com/Client/" xmlns:ns3="http://wsbo.webservice.ephs.pdc.ibm.com/FamilyHealth/">
<!-- stuff -->
</ns2:queryHumanSubjectsRequest>
</soap:Body>
</soap:Envelope>
As you can see, the MessageId value is "urn:uuid:945cfd10-9fd2-48f9-80b4-ac1b9f3293c6". I need to set a custom value.
I tried adding the MessageId header they way I add the other headers like "international" and "user", but some part of the framework overrides the value.
// Note this doesn't work! Something overrides the value. It works for other headers.
#Override
public void process(Exchange exchange) throws Exception {
Message in = exchange.getIn();
List<SoapHeader> headers = CastUtils.cast((List<?>) in.getHeader(Header.HEADER_LIST));
SOAPFactory sf = SOAPFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
QName MESSAGE_ID_HEADER = new QName("http://www.w3.org/2005/08/addressing", "MessageID", "wsa");
SOAPElement messageId = sf.createElement(MESSAGE_ID_HEADER);
messageId.setTextContent("customValue");
SoapHeader soapHeader = new SoapHeader(MESSAGE_ID_HEADER, messageId);
headers.add(soapHeader);
}
The CXF website has some documentation on how to set WS-Addressing headers, but I don't see how to apply it to Apache Camel. The Apache Camel CXF documentation doesn't specifically mention WS-Addressing either.
The documentation links you posted actually do have the information you need, although it's not immediately obvious how to apply it to Camel.
The CXF documentation says that:
The CXF org.apache.cxf.ws.addressing.impl.AddressingPropertiesImpl object can be used to control many aspects of WS-Addressing including the Reply-To:
AddressingProperties maps = new AddressingPropertiesImpl();
EndpointReferenceType ref = new EndpointReferenceType();
AttributedURIType add = new AttributedURIType();
add.setValue("http://localhost:9090/decoupled_endpoint");
ref.setAddress(add);
maps.setReplyTo(ref);
maps.setFaultTo(ref);
((BindingProvider)port).getRequestContext()
.put("javax.xml.ws.addressing.context", maps);
Note that it sets the addressing properties on the "RequestContext".
The Apache Camel documentation says that:
How to propagate a camel-cxf endpoint’s request and response context
CXF client API provides a way to invoke the operation with request and response context. If you are using a camel-cxf endpoint producer to invoke the outside web service, you can set the request context and get response context with the following code:
CxfExchange exchange = (CxfExchange)template.send(getJaxwsEndpointUri(), new Processor() {
public void process(final Exchange exchange) {
final List<String> params = new ArrayList<String>();
params.add(TEST_MESSAGE);
// Set the request context to the inMessage
Map<String, Object> requestContext = new HashMap<String, Object>();
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, JAXWS_SERVER_ADDRESS);
exchange.getIn().setBody(params);
exchange.getIn().setHeader(Client.REQUEST_CONTEXT , requestContext);
exchange.getIn().setHeader(CxfConstants.OPERATION_NAME, GREET_ME_OPERATION);
}
});
The above example has some stuff we don't need, but the important thing is that it shows us how to set the CXF Request Context.
Put them together and you get:
#Override
public void process(Exchange exchange) throws Exception {
AttributedURIType messageIDAttr = new AttributedURIType();
messageIDAttr.setValue("customValue");
AddressingProperties maps = new AddressingProperties();
maps.setMessageID(messageIDAttr);
Map<String, Object> requestContext = new HashMap<>();
requestContext.put(JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES, maps);
exchange.getIn().setHeader(Client.REQUEST_CONTEXT, requestContext);
}
// org.apache.cxf.ws.addressing.JAXWSAConstants.CLIENT_ADDRESSING_PROPERTIES = "javax.xml.ws.addressing.context"
// org.apache.cxf.endpoint.Client.REQUEST_CONTEXT = "RequestContext"
Warning: In my route, I invoke multiple different web services sequentially. I discovered that after setting the RequestContext as shown above, Camel started using the same RequestContext for all web services, which resulted in an error: "A header representing a Message Addressing Property is not valid and the message cannot be processed". This is because the incorrect "Action" header was used for all web service invocations after the first.
I traced this back to Apache Camel using a "RequestContext" Exchange property, separate from the header we set, which apparently takes priority over the header. If I remove this property prior to calling subsequent web services, CXF automatically fills in the correct Action header.
if your problem not solved, I suggest you to combine your cxf service with custom interceptor. it easy to work with your soap message. like this:
<bean id="TAXWSS4JOutInterceptorBean" name="TAXWSS4JOutInterceptorBean" class="com.javainuse.beans.SetDetailAnswerInterceptor " />
<cxf:cxfEndpoint id="CXFTest" address="/javainuse/learn"
endpointName="a:SOATestEndpoint" serviceName="a:SOATestEndpointService"
serviceClass="com.javainuse.SOATestEndpoint"
xmlns:a ="http://javainuse.com">
<cxf:binding>
<soap:soapBinding mtomEnabled="false" version="1.2" />
</cxf:binding>
<cxf:features>
<wsa:addressing xmlns:wsa="http://cxf.apache.org/ws/addressing"/>
</cxf:features>
<cxf:inInterceptors>
<ref bean="TAXWSS4JInInterceptorBean" />
</cxf:inInterceptors>
<cxf:inFaultInterceptors>
</cxf:inFaultInterceptors>
<cxf:outInterceptors>
<ref bean="TAXWSS4JOutInterceptorBean" />
</cxf:outInterceptors>
<cxf:outFaultInterceptors>
</cxf:outFaultInterceptors>
</cxf:cxfEndpoint>
and in the interceptor you can set soap headers like this:
public class SetDetailAnswerInterceptor extends WSS4JOutInterceptor {
public SetDetailAnswerInterceptor() {
}
#Override
public void handleMessage(SoapMessage mc) {
AttributedURIType value = new AttributedURIType();
value.setValue("test");
((AddressingProperties) mc.get("javax.xml.ws.addressing.context.outbound")).setMessageID(value);
}
}

JaxWS : Externalize Http Conduit name Attribute

I have the WSDL file for the SOAP webservice that i need to invoke over http. Using cxf wsdl2java plugin i have created the stub methods.
I have created the webservice client using jaxws. The webservice has basic authentication enabled. I am trying to configure http conduit
my application.properties
--------------------------
webservices.http.auth.username=username
webservices.http.auth.password=password
fold.webservices.http.auth.authtype=Basic
webservices.http.conduit.property.name=https://fixed_deposits-test.co.in/fold-webservices/services.*
fold.updateservice.soap.address=https://fixed_deposits-test.co.in/fold-webservices/services/UpdateService
----------------------------
My Spring Context...
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxws="http://cxf.apache.org/jaxws"
xmlns:http-conf="http://cxf.apache.org/transports/http/configuration"
xmlns:sec="http://cxf.apache.org/configuration/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/transports/http/configuration http://cxf.apache.org/schemas/configuration/http-conf.xsd
http://cxf.apache.org/configuration/security http://cxf.apache.org/schemas/configuration/security.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd">
<bean id="properties" class="org.apache.camel.spring.spi.BridgePropertyPlaceholderConfigurer">
<property name="locations">
<util:list>
<value>file:${config.dir}/application.properties</value>
</util:list>
</property>
<property name="systemPropertiesModeName" value="SYSTEM_PROPERTIES_MODE_OVERRIDE" />
</bean>
<jaxws:client id="updateServiceClient" serviceClass="com.fold.facade.v1.UpdateService" address="${fold.updateservice.soap.address}" >
<jaxws:inInterceptors>
<bean id="loggingInInterceptor" class="org.apache.cxf.interceptor.LoggingInInterceptor" >
<property name="prettyLogging" value="true" />
</bean>
</jaxws:inInterceptors>
<jaxws:outInterceptors>
<bean id="loggingOutInterceptor" class="org.apache.cxf.interceptor.LoggingOutInterceptor" >
<property name="prettyLogging" value="true" />
</bean>
</jaxws:outInterceptors>
</jaxws:client>
<http-conf:conduit name="***?????????***">
<http-conf:authorization>
<sec:UserName>${fold.webservices.http.auth.username}</sec:UserName>
<sec:Password>${fold.webservices.http.auth.password}</sec:Password>
<sec:AuthorizationType>${fold.webservices.http.auth.authtype}</sec:AuthorizationType>
</http-conf:authorization>
</http-conf:conduit>
I have done a lot of searching online so as to what should be the valid value for name attribute..
accouring to CXF documentation it should be...
{WSDL_endpoint_target_namespace}PortName.http-conduit
my WSDL File has..
...
targetNamespace="http://facade.fold.com/" and
...
<wsdl:port binding="tns:UpdateServiceImplServiceSoapBinding"
name="UpdateServiceImplPort">
<soap:address
location="https://fixed_deposits-test.co.in/fold-webservices/services/UpdateService" />
</wsdl:port>
so i tried with these..
<http-conf:conduit name="{http://facade.fold.com/}UpdateServiceImplPort.http_conduit">
or
<http-conf:conduit name="*UpdateServiceImplPort.http_conduit">
or
<http-conf:conduit name="{http://facade.fold.com/}*.http_conduit">
But none of them work as i get 401 unauthorized exception..
org.apache.cxf.transport.http.HTTPException: HTTP response '401: Unauthorized' when communicating with https://fixed_deposits-test.co.in/fold-webservices/services/UpdateService
THERE ARE COUPLE OF WAYS I GOT IT TO WORK
a) <http-conf:conduit name="*.http_conduit">
but i really don't want to do it this way...
b) <http-conf:conduit name="https://fixed_deposits-test.co.in/fold-webservices/services/UpdateService">
this is hardcoding the SOAP service URL... which i don't want as i am looking for externalizing URL as my SOAP URL's are different for different environment..(dev /test /prod etc)
Below is my best shot at externalization, but it failed with 401 Unauthorized Exception...
properties were replaced in all other instances in my spring context, but not for http-conf:conduit name attribute :(
<http-conf:conduit name="${webservices.http.conduit.property.name}">
As a workaround i am currently using the regex approach which works..
<http-conf:conduit name="*.*/fold-webservices/services/UpdateService">
But i really want to figure out if it possible to externalize it and read from properties file. And i want to do it the Spring
configuration way. Please help me !!!
We had the same issue with JBoss Fuse 6.1 (Camel CXF 2.12.0).
You can see what the http-conf:conduit name is set to by enabling DEBUG log level and looking at your log, there should be a log line such as:
DEBUG 10:40:41,437 [Camel (cnpms-as-mnp-ctx) thread #0 - JmsConsumer[cnpms-queue]] org.apache.cxf.transport.http.HTTPConduit.setTlsClientParameters(HTTPConduit.java:901) - Conduit '{http://acme.com/manageporting/v1}ManageportingPortPort.http-conduit' has been (re)configured for plain http.
So in this case you would set the name as:
<http-conf:conduit name="{http://acme.com/manageporting/v1}ManageportingPortPort.http-conduit"
But the Web Service (WS) Interface Class is defined as:
#WebService(targetNamespace = "http://acme.com/manageporting/v1", name = "ManageportingPort")
#SOAPBinding(parameterStyle = SOAPBinding.ParameterStyle.BARE)
public interface ManageportingPort {
Generated from WSDL:
<wsdl:portType name="ManageportingPort">
Note that by following the CXF documentation you would expect the port name component to be "ManageportingPort" NOT "ManageportingPortPort" i.e. with "Port" appended to it.
However looking at how the portQName is resolved in org.apache.cxf.jaxws.support.JaxWsImplementorInfo.getEndpointName(), if the port name is not set in the WS Interface Class, and the name is not null or blank, it sets the port name to portName = name + "Port" otherwise it sets it to portName = implementorClass.getSimpleName() + "Port".
I had the same problem...
In my case the following 2 changes helped:
1) add "Port" postfix to the port name, despite it is not defined in the wsdl this was
e.g wsdl:
<wsdl:port name="XXXSoap">
will be "XXXSoapPort" in the conduit definition
2) remove the "\" at the end of the target namespace name
==> therefore try
<http-conf:conduit name="{http://facade.fold.com}UpdateServiceImplPort.http_conduit">
or
<http-conf:conduit name="{http://facade.fold.com}UpdateServiceImplPortPort.http_conduit">
I came across the same challenge and found no existing solution. Spring doesn't seem to resolve placeholders in bean names (make lots of sense). However, this is a valid case unless cxf allows conduit matching using another attribute.
There are a few ways to solve this problem:
Define conduit beans programmatically (lose the neat of xml declaration)
Find a way to resolve the bean names which contains placeholders
I prefer option 1 and this is the implementation which I'm happy with. Please note that PropertyPlaceholderResolver is our own utility which uses the same defined resolver bean.
public class NameWithPlaceholderBeanFactoryPostProcessor implements BeanFactoryPostProcessor
{
#Override
public void postProcessBeanFactory(final ConfigurableListableBeanFactory beanFactory) throws BeansException
{
if (!(beanFactory instanceof DefaultListableBeanFactory))
return;
DefaultListableBeanFactory bf = (DefaultListableBeanFactory) beanFactory;
String[] names = bf.getBeanDefinitionNames();
for (String name : names)
{
if (name.indexOf('$') < 0)
continue;
BeanDefinition bd = bf.getBeanDefinition(name);
bf.removeBeanDefinition(name);
bf.registerBeanDefinition(PropertyPlaceholderResolver.resolvePlaceHolders(name), bd);
}
}
}
The final step is to define this as a spring bean.

How to access a huge JSON coming (from a spring RESTful Service) in a spring MVC app using RestTemplate

My Spring RESTful web service is returning a JSON form of-
[{"key1":"value1","key2":"value2","key3":"value3"},{"key4":"value4","key5":"value5","key6":"value6"}]
Now when my spring MVC app, try to access it, to show in a JSP then Exception occurs saying-no suitable HttpMessageConverter found Please help me where I going wrong.Here is my code-
Inside #Controller class of my spring MVC app calling the RESTful service
//**com.songs.controllers.FrontSongController.java**
</*
author Rohit Tiwari
*/>
#RequestMapping(value="/alls",method=RequestMethod.POST)
public String getAllSongs(ModelMap md)
{
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>(headers);
String url="http://localhost:7001/SongAppWS/songappWS/allsongsWS";
RestTemplate rt=new RestTemplate();
//SongResource.class is for representation on incoming JSON see below for its code
//This is the line no 48 that you will see in below browser logs
ResponseEntity<SongResource> listofallsongs=rt.exchange(url,HttpMethod.GET,entity, SongResource.class);
md.addAttribute("listname", "Songs available in the repository:");
System.out.println("Response Entity object= "+listofallsongs);
System.out.println("Response Entity body= "+listofallsongs.getBody().toString());
return "Sucess";
}
Inside config-servlet.xml of my spring MVC app calling the RESTful service
<context:component-scan base-package="com.songs.controllers" />
<mvc:annotation-driven />
<context:annotation-config/>
<bean class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping"></bean>
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"></bean>
<bean class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter"/>
</list>
</property>
</bean>
<bean id="viewResolver" class="org.springframework.web.servlet.view.UrlBasedViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
Inside SongResource.java of my spring MVC app, which I am trying to use for converting the coming JSON to my SongResource.class object, that my spring MVC app can use in a jsp
//**com.songs.service.resource.SongResource.java**
public class SongResource
{
private String name;
private String film;
private String singer;
public SongResource(String name,String film,String singer)
{
this.name=name;
this.film=film;
this.singer=singer;
}
//setter & getters of all above
}
On calling the spring REST service from my spring MVC app the browser is saying as below-
Error 500--Internal Server Error
org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [com.songs.service.resource.SongResource] and content type [application/json]
at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java :77)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:619)
at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:1)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:446)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
at com.songs.controllers.FrontSongController.getAllSongs(FrontSongController.java:48)
//and so on
Try this, hope it will help you
#RequestMapping(value="/alls",method=RequestMethod.POST)
public String getAllSongs(ModelMap md)
{
String url="http://localhost:7001/SongAppWS/songappWS/allsongsWS";
RestTemplate rt=new RestTemplate();
SongResource[] songRs = template.getForObject(url, SongResource[].class);
List<SongResource> songs = Arrays.asList(songRs);
md.addAttribute("listname", "Songs available in the repository:");
md.addAttribute("listValues", songs);
return "Sucess";
}

How to unmarshall to different #RequestBody object types?

I'm using Spring in my web service which receives XML as input. It can be XML embebed in the HTTP request or as a plain text in the request attribute.
Currently my web service is handling two different XML schemas so my unmarshaller can unmarshall the XML files to two object types (for example: Foo and Bar).
In my Controller, I have the next code to handler the request attribute:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=application/x-www-form-urlencoded"})
#ResponseBody
public ResponseObject getResponse(#RequestParam("request") String request, HttpServletRequest req) {
It works perfectly, with the request string I can unmarshall to Foo object or Bar object.
The problem comes with the XML embebed:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=text/xml"})
#ResponseBody
public ResponseObject getResponse(#RequestBody Foo request, HttpServletRequest req) {
and
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, headers={"content-type=text/xml"})
#ResponseBody
public ResponseObject getResponse(#RequestBody Bar request, HttpServletRequest req) {
and here is the MessageConverter:
<bean id="marshallingHttpMessageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxb2Marshaller" />
<property name="unmarshaller" ref="jaxb2Marshaller" />
</bean>
<oxm:jaxb2-marshaller id="jaxb2Marshaller" contextPath="path.to.Foo:path.to.Bar"/>
I think that the MessageConverter should do the unmarshall automagically but I receive the next error:
java.lang.IllegalStateException: Ambiguous handler methods mapped for HTTP path '/ws/mypath.ws': [...] If you intend to handle the same path in multiple methods, then factor them out into a dedicated handler class with that path mapped at the type level!
How can I unmarshall automatically to different #RequestBody object types? (with the same web service path)
There has to be something in the #RequestMapping which makes each request method unique, in your case both the xml based request mappings exactly the same - the type of the parameters is figured out after the framework has found the correct method with the #RequestMapping. So essentially what you are saying is not feasible unless you have something more in the annotation to help the framework with finding the correct method.
One small simplification that you can make is the following, if you are on Spring 3.1+:
#RequestMapping(value={"/mypath"}, method={RequestMethod.POST}, consumes=text/xml)