Spring REST Form Data PUT method - rest

I have given below my spring controller and .xml file congif info .
class TestingController
{
#RequestMapping(value="/addinfo",method=RequestMethod.PUT)
public void addInfo(#RequestBody Userinfo user){
}
context
<mvc:annotation-driven/>
<bean id="contentNegotiationManager" class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="ignoreAcceptHeader" value="true"/>
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="xml" value="application/xml" />
</map>
</property>
This is working fine as i am expecting for the JSON and XML Request using REST Client.
for example : {"user":"test","cval":"12","mval":"12} JSON working fine .
when i try to pass the data like user=test&cval=12&mval=12 using in request body using REST client with header "Content-Type:application/x-www-form-urlencoded"
I am getting 415 error message.
My Requirement is
SPring RESTfull Webservice need to handle the below Content-Type
1.application/json
2.application/xml
3.application/x-www-form-urlencoded
Regards
Vasanth D

Related

Spring Integration: Mail error and HTTP gateway response

My use case is simple. I want to handle an exception caused by a system being unreachable, perform a retry based upon a configured retry policy, send an email when the retry threshold has been met, and return a custom response back the caller.
The challenges I am facing is that I cannot both send an email and return a response back to the caller. Since I was using a int-mail:outbound-channel-adapter initially, I would expect this behavior since this is a one-way component:
<int:chain input-channel="defaultErrorChannel">
<int:service-activator id="mailMessageActivator" expression="#mailHandler.process(payload)" />
<int-mail:outbound-channel-adapter mail-sender="mailSender" />
</int:chain>
However, if I introduce a int-amqp:outbound-gateway in front of the int-mail:outbound-channel-adapter (see the Error Handling config below), I would expect to be able to invoke a int:service-activator to construct and return a response to the caller.
Am I thinking about this the wrong way? I see that someone else had a similar question which is still unanswered. Both of the configurations I mentioned send emails, but always block from the caller without receiving a response upon timeout.
Here are the relevant parts of my configuration:
Gateway
<int:gateway id="customerGateway" service-interface="com.uscs.crm.integration.CustomerGateway"
default-request-channel="syncCustomers" default-reply-channel="replySyncCustomers" default-reply-timeout="30000">
</int:gateway>
<int:object-to-json-transformer input-channel="syncCustomers" output-channel="outboundRequestChannel" />
<int-http:outbound-gateway request-channel="outboundRequestChannel" reply-channel="replySyncCustomers"
url="http://voorhees148.uscold.com:9595/web/customerSync/createCustomer"
http-method="POST"
rest-template="restTemplate"
expected-response-type="com.uscs.crm.model.CustSyncResponseVO"
mapped-request-headers="Authorization, HTTP_REQUEST_HEADERS">
<int-http:request-handler-advice-chain>
<ref bean="retryWithBackoffAdviceSession" />
</int-http:request-handler-advice-chain>
</int-http:outbound-gateway>
Error Handling
<int:channel id="defaultErrorChannel"/>
<int:channel id="errorResponses"/>
<!--
ExponentialBackOffPolicy.multipler is applied to wait time over each retry attempt
with a ExponentialBackOffPolicy.maximum configured.
-->
<bean id="retryWithBackoffAdviceSession" class="org.springframework.integration.handler.advice.RequestHandlerRetryAdvice">
<property name="retryTemplate">
<bean class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="2000" />
<property name="multiplier" value="2" />
<property name="maxInterval" value="30000"/>
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="3"/>
</bean>
</property>
</bean>
</property>
<property name="recoveryCallback">
<bean class="org.springframework.integration.handler.advice.ErrorMessageSendingRecoverer">
<constructor-arg ref="defaultErrorChannel"/>
</bean>
</property>
</bean>
<bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler"></bean>
<int:chain input-channel="defaultErrorChannel" output-channel="replySyncCustomers">
<int:service-activator id="mailMessageActivator" expression="#mailHandler.process(payload)" />
<int:header-enricher>
<int:header name="ERROR_ID" expression="T(java.lang.System).currentTimeMillis()"/>
</int:header-enricher>
<int-amqp:outbound-gateway
exchange-name="error-responses-exchange"
routing-key-expression="'error.response.'+headers.ERROR_ID"
amqp-template="amqpTemplate" />
<!-- Will this service-activator return a response to the caller (int:gateway) using channel `replySyncCustomers`? -->
<int:service-activator id="custSyncResponseActivator" expression="#custSyncResponseHandler.process(payload)" />
</int:chain>
<int-amqp:inbound-gateway queue-names="error-responses" request-channel="errorResponses"
connection-factory="rabbitConnectionFactory" acknowledge-mode="AUTO" />
<int-mail:outbound-channel-adapter channel="errorResponses" mail-sender="mailSender" />
<!-- (Outbound Channel Adapter/Gateway) rabbit exchanges, queues, and bindings used by this app -->
<rabbit:topic-exchange name="error-responses-exchange" auto-delete="false" durable="true">
<rabbit:bindings>
<rabbit:binding queue="error-responses" pattern="error.response.*"/>
</rabbit:bindings>
</rabbit:topic-exchange>
<rabbit:queue name="error-responses" auto-delete="false" durable="true"/>
SOLUTION: I was able to get this working with help from #Artem. Below are the changes I made.
Service Activator Implementation (handling ErrorMessage)
The key is the line which returns the reconstructed Message with all of the header information from the ErrorMessage.
#Override
public Message<CustSyncResponseVO> process(Message<MessagingException> errorMessage) {
MessagingException errorException = errorMessage.getPayload();
CustSyncResponseVO custSyncResponse = new CustSyncResponseVO();
custSyncResponse.setResponseMessage(ExceptionUtils
.convertToString(errorMessage.getPayload()));
return MessageBuilder.withPayload(custSyncResponse)
.copyHeaders(errorMessage.getHeaders())
.copyHeadersIfAbsent(errorException.getFailedMessage().getHeaders()).build();
}
Service Activator Config
Used SpEL to reference the #root context to retrieve the ErrorMessage instead of the default which would be MessagingException (payload) and passed it to my process method on the POJO.
<bean id="custSyncResponseHandler" class="com.uscs.crm.integration.handler.CustSyncResponseHandler" />
<int:chain id="errorGatewayResponseChain" input-channel="defaultErrorChannel" output-channel="replySyncCustomers">
<int:service-activator id="custSyncResponseActivator" expression="#custSyncResponseHandler.process(#root)" />
</int:chain>
I don't see reason to introduce the AMQP middleware complexity there just for sending email in the end.
What only you need is <publish-subscribe-channel id="defaultErrorChannel"> with to endpoints as subscribers to it.
The first one is one-way email sending <chain> and the second one is custSyncResponseActivator to reply something to your <int-http:outbound-gateway>.
You can find more info on the matter in the Spring Integration Reference Manual.

WARNING: No mapping found for HTTP request with URI [/PMC/] in DispatcherServlet with name 'spring-dispatcher'

I got warning message as follows:
WARNING: No mapping found for HTTP request with URI [/PMC/] in DispatcherServlet with name 'spring-dispatcher'
This is my spring bean definition:
<beans xmlns="springframework.org/schema/beans"; xmlns:context="springframework.org/schema/context"; xmlns:xsi="w3.org/2001/XMLSchema-instance"; xsi:schemaLocation="springframework.org/schema/beans springframework.org/schema/beans/spring-beans-2.5.xsd springframework.org/schema/context springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.PMC.hellocontroller" />
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" >
<property name="prefix">
<value>/WEB-INF/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
</beans>
Please, show me your controller code.
It seems there is no mapped controller method at root path.
Please, refer to Map / (root URL) in Spring MVC.

How to add message converter to restTemplate in xml configuration

I am using restTemplate for consuming json data from remote server, and then parsing the json in my java objects using jackson. I have added required message converters to my restTemplate by java code as:
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
messageConverters.add(new FormHttpMessageConverter());
messageConverters.add(new StringHttpMessageConverter());
messageConverters.add(new MappingJacksonHttpMessageConverter());
restTemplate.setMessageConverters(messageConverters);
restTemplate.setRequestFactory(new CommonsClientHttpRequestFactory());
MyResponse myResponse = restTemplate.getForObject(caasUrl, MyResponse.class);
And my restTemplate is defined in my spring-config file as:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<constructor-arg>
<bean class="org.springframework.http.client.HttpComponentsClientHttpRequestFactory">
<property name="readTimeout" value="630000" />
<property name="connectTimeout" value="30000" />
</bean>
</constructor-arg>
</bean>
And its working fine, now my question is how can we pass the list of message converters to restTemplate in xml configuration as I do not want to do the same by java code. any Help please
Try this...sample code below shows only 2 converters.
<property name="messageConverters">
<list>
<bean class="org.springframework.http.converter.FormHttpMessageConverter"/>
<bean class="org.springframework.http.converter.StringHttpMessageConverter"/>
......more....
</list>
</property>

How to perform JAXB2 marshalling of input request in REST with Spring MVC3?

I am new to Spring MVC (Spring 3) and REST, and I am trying out a little toy app to try out GET and POST web services. I have read the Spring's official reference, and found these questions in Stackoverflow, RequestBody of a REST application , Pass a request parameter in Spring MVC 3 but I am still stucked in making it works. Can anyone give me hints on what I missed?
My Controller is like this:
#Controller
#RequestMapping(value = "/echo")
public class EchoControllerImpl implements EchoController {
#RequestMapping(method = RequestMethod.POST, value = "/echoByPost")
public ModelAndView echoByPost(#ModelAttribute EchoDto input) {
// ...
}
}
I have putted corresponding converter in the app ctx:
<mvc:annotation-driven />
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller" >
<property name="classesToBeBound">
<list>
<value>foo.EchoDto</value>
</list>
</property>
</bean>
<bean class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<property name="messageConverters">
<list>
<ref bean="marshallingHttpMessageConverter" />
<ref bean="stringHttpMessageConverter" />
</list>
</property>
</bean>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean id="marshallingHttpMessageConverter"
class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="jaxb2Marshaller" />
<property name="unmarshaller" ref="jaxb2Marshaller" />
</bean>
<!-- other beans like ViewResolvers -->
I even tried to add these to web.xml as I saw somewhere mentioning about it (though I don't really know what does it means)
<filter>
<filter-name>httpPutFormFilter</filter-name>
<filter-class>org.springframework.web.filter.HttpPutFormContentFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>httpPutFormFilter</filter-name>
<servlet-name>spring-rest</servlet-name>
</filter-mapping>
Then I tried to invoke my web service by Curl:
curl -d "echoDto=<EchoDto><message>adrian</message></EchoDto>" http://localhost:8001/foo/rest/echo/echoByPost.xml
I found that my incoming object is not created through unmarshalling of JAXB2. Instead, seems that the ctor EchoDto(String) is called which the contains whole request xml message.
(I also tried annotating the parameter with #RequestBody instead but it is even worse, that I cannot even invoke the controller method)
Can someone tell me what I have missed?
The Jaxb2Marshaller is setup correctly with the DTO class, coz I am able to use it as returned model object in case of another GET REST webserivce call.
You need to set the content type of the request and you don't need the echoDto=:
curl -H "Content-Type: application/xml" -d "<EchoDto><message>adrian</message></EchoDto>" http://localhost:8001/foo/rest/echo/echoByPost.xml

How do i change the property of jaxrs endpoint to support "mtom"

I created a RESTful web service, and I want to send binary files to this service without SOAP.
There are some information on CXF website:
XOP
But I can't find a way to get the CXF JAX-RS endpoints, and set an mtom-enabled property.
My Spring config is:
<jaxrs:server id="fis" address="http://172.20.41.40:8080/fis">
<jaxrs:serviceBeans>
<ref bean="FaultInfoResource" />
<ref bean="ExplorationResultResource" />
</jaxrs:serviceBeans>
</jaxrs:server>
<bean id="FaultInfoService" parent="baseService" class="com.dfe.demo.FaultInfoService">
</bean>
<bean id="FaultInfoResource" class="com.dfe.demo.FaultInfoResource">
<property name="faultInfoService" ref="FaultInfoService"/>
</bean>
<bean id="ExplorationResultService" parent="baseService" class="com.dfe.demo.ExplorationResultService">
</bean>
<bean id="ExplorationResultResource" class="com.dfe.demo.ExplorationResultResource">
<property name="explorationResultService" ref="ExplorationResultService"/>
</bean>
And my server class is:
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(new String[]{"com/dfe/iss/config/applicationContext.xml","com/dfe/demo/yearlyplan/cxf-servlet.xml"});
JAXRSServerFactoryBean fib = (JAXRSServerFactoryBean) ctx.getBean("fis");
fib.create();
Try this:
<beans>
<jaxrs:server id="bookstore1">
<jaxrs:properties>
<entry key="mtom-enabled" value="true"/>
</jaxrs:properties>
</jaxrs:server>
</beans>