How to pass object/json to post method using int-http:outbound-gateway in Spring Integration - spring

How we can pass an object or json from Activator to int-http:outbound-gateway.
Below are my configs
<int:channel id="preparedData"/>
<int:service-activator input-channel="preparedData" ref="writer" method="writeData" output-channel="CallbackChannel">
</int:service-activator>
<int:channel id="CallbackChannel" />
<int-http:outbound-gateway
request-channel="CallbackChannel"
http-method="POST" url="{url}"
extract-request-payload="true">
<int-http:uri-variable name="url" expression="headers['url']" />
</int-http:outbound-gateway>
And my activator is returning one Object which is being expected in the POST API in one controller in #RequestBody
With above config getting below error.
13:58:41.202 [task-scheduler-1] ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.messaging.MessageHandlingException: HTTP request execution failed for URI [http://**myUrl**]; nested exception is org.springframework.web.client.HttpClientErrorException: 400 Bad Request
Kindly suggest.
EDIT1
If I am converting my returned MyObject in JSON format in Activator then I am getting below error.
nested exception is java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Map
Edit 2
When I changed my returntype of my Activator to Map with one of key value pair as 'input' and Object then it complains as below.
HTTP request execution failed for URI [http://MYURL]; nested exception is java.lang.ClassCastException: com.******.MyObject cannot be cast to java.lang.String

The <int-http:outbound-gateway> delegates all the hard work to the RestTemplate, which comes with this set of HttpMessageConverters by default:
this.messageConverters.add(new ByteArrayHttpMessageConverter());
this.messageConverters.add(new StringHttpMessageConverter());
this.messageConverters.add(new ResourceHttpMessageConverter());
this.messageConverters.add(new SourceHttpMessageConverter<>());
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());
if (romePresent) {
this.messageConverters.add(new AtomFeedHttpMessageConverter());
this.messageConverters.add(new RssChannelHttpMessageConverter());
}
if (jackson2XmlPresent) {
this.messageConverters.add(new MappingJackson2XmlHttpMessageConverter());
}
else if (jaxb2Present) {
this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
}
if (jackson2Present) {
this.messageConverters.add(new MappingJackson2HttpMessageConverter());
}
else if (gsonPresent) {
this.messageConverters.add(new GsonHttpMessageConverter());
}
if (jackson2SmilePresent) {
this.messageConverters.add(new MappingJackson2SmileHttpMessageConverter());
}
if (jackson2CborPresent) {
this.messageConverters.add(new MappingJackson2CborHttpMessageConverter());
}
I think your Object is converted somehow to the wire bytes, you only should be sure that the proper and appropriate converted is used. And that is really depends of the server (#RequestBody) requirements.

Below is my solution that worked.
<int:channel id="preparedData"/>
<int:service-activator input-channel="preparedData" ref="writer" method="writeData" output-channel="CallbackChannel"/>
<int:channel id="CallbackChannel"/>
<int:transformer input-channel="CallbackChannel"
output-channel="registrationQueue"
ref="transformer" method="doTransform"/>
<int:channel id="registrationQueue" />
<int:header-enricher input-channel="registrationQueue" output-channel="enricherOutput">
<int:header name="contentType" value="application/json"/>
</int:header-enricher>
<int:channel id="enricherOutput" />
<int-http:outbound-gateway
request-channel="enricherOutput"
http-method="POST" url="{url}"
extract-request-payload="true"
reply-channel="replyChannel"
message-converters="converter"
<int-http:uri-variable name="url" expression="headers['url']" />
</int-http:outbound-gateway>
<util:list id="converter">
<bean id="test" class="com.xx.rr.ttt.MyMessageConvertor" />
</util:list>
<int:channel id="replyChannel" />
<int:service-activator input-channel="replyChannel" ref="lastActivator"/>
Had to add converter with below code.
public class MyMessageConvertor extends AbstractHttpMessageConverter<MyMessageConvertor> {
public static final Charset DEFAULT_CHARSET = Charset.forName("ISO-8859-1");
public MyMessageConvertor() {
this(DEFAULT_CHARSET);
}
public MyMessageConvertor(Charset defaultCharset) {
super(defaultCharset, new MediaType("application", "json"), MediaType.ALL);
}
#Override
protected boolean supports(Class<?> clazz) {
return true;
}
#Override
protected MyResponse readInternal(Class<? extends MyResponse > clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return null;
}
#Override
protected void writeInternal(MyResponse t, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
ObjectMapper mapperObj = new ObjectMapper();
String jsonStr = null;
try {
jsonStr = mapperObj.writeValueAsString(t);
} catch (IOException e) {
e.printStackTrace();
}
Charset charset = getContentTypeCharset(outputMessage.getHeaders().getContentType());
StreamUtils.copy(jsonStr, charset, outputMessage.getBody());
//System.out.println("outputMessage.getBody()" + outputMessage.getBody());
}
private Charset getContentTypeCharset(MediaType contentType) {
if (contentType != null && contentType.getCharset() != null) {
return contentType.getCharset();
}
else {
return getDefaultCharset();
}
}
}
I did not implement readInternal because the url that I am hitting is not returning anything but reply-channel in http:outbound-gateway is mandatory attribute thtswhy I had to add one and add one more activator which is finishing the flow.

Related

Spring AOP with RequestDispatcher causes recursive calls

Spring-servlet.xml:
<aop:config>
<aop:advisor advice-ref="interceptor" pointcut="#annotation(Validator)"/>
</aop:config>
<bean id="interceptor" class="org.aopalliance.intercept.MethodInterceptor" />
MethodInterceptor invoke():
if (!valid){
RequestDispatcher rd = request.getRequestDispatcher(errorView);
rd.forward(request, response);
}
Working flow of control:
My interceptor is called before any Spring controller method that is annotated with the Validator annotation. The intention is to validate the request, if validation fails, forward the request to a different view. This is usually working. If there is an error (!valid), the RequestDispatcher.forward is called. This causes another Spring controller method to be called which ultimately shows the error view. This normally works.
Issue:
For some Spring controllers, my RequestDispatcher's errorView causes the request to be forwarded back to the same method causing an infinite loop (invoke()gets called over and over). I think this is because of how the Spring controller's request mappings (see below) are set up.
Error view: #RequestMapping(value = URL, params="error")
Normal view: #RequestMapping(value = URL, params="proceed")
So when the first request is routed it's got 'proceed' in the request params. Then when there's an error and the RequestDispatcher forwards to the view with the 'error' param in the query string, it should forward to the "Error view" method above, but it doesn't. It always forwards to the 'proceed' method causing an infinite loop on the MethodInterceptor invoke(). This seems to be because the 'proceed' parameter is still in the HttpServletRequest. However this isn't easy to fix because the whole point of the interceptor is that it has no knowledge of the Spring controller itself - it only knows if an error occurred, and that it should forward to the error view if an error occurred.
Workaround:
Using the request mappings below, it fixes the issue. This is probably because the HttpServletRequest parameter is overwritten when using the key=value notation.
Error view: #RequestMapping(value = URL, params="view=error")
Normal view: #RequestMapping(value = URL, params="view=proceed")
Question
How can I "properly" fix the issue without resorting to the workaround shown above? Is there a more standard way to forward to the correct spring controller?
Solution#1:
Having configured as following:
Error view: #RequestMapping(value = URL, params="error")
Normal view: #RequestMapping(value = URL, params="proceed")
You could try for redirect as follows:
MethodInterceptor invoke():
if (!valid){
// RequestDispatcher rd = request.getRequestDispatcher(errorView);
// rd.forward(request, response);
response.sendRedirect(errorView);
}
Drawback: the browser would make a second request, therefore the old method parameters are no longer in the httpservletrequest.
WorkArround: To Avoid drawback, You could use Spring MVC Flash Attribute. You could follow this tutorial to know how Flash Attribute works.
Refs:FlashAttributesExample
Solution#2:
How can I "properly" fix the issue without resorting to the workaround
shown above? Is there a more standard way to forward to the correct
spring controller?
You could incorporate by implementing you own RequestMappingHandlerAdapter.
Solution#3:
Here is the code for the aspect:
public class RequestBodyValidatorAspect {
private Validator validator;
#Pointcut("#annotation(org.springframework.web.bind.annotation.RequestMapping)")
private void controllerInvocation() {
}
#Around("controllerInvocation()")
public Object aroundController(ProceedingJoinPoint joinPoint) throws Throwable {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
Annotation[][] argAnnotations = method.getParameterAnnotations();
String[] argNames = methodSignature.getParameterNames();
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
if (hasRequestBodyAndValidAnnotations(argAnnotations[i])) {
validateArg(args[i], argNames[i]);
}
}
return joinPoint.proceed(args);
}
private boolean hasRequestBodyAndValidAnnotations(Annotation[] annotations) {
if (annotations.length < 2)
return false;
boolean hasValid = false;
boolean hasRequestBody = false;
for (Annotation annotation : annotations) {
if (Valid.class.isInstance(annotation))
hasValid = true;
else if (RequestBody.class.isInstance(annotation))
hasRequestBody = true;
if (hasValid && hasRequestBody)
return true;
}
return false;
}
#SuppressWarnings({"ThrowableInstanceNeverThrown"})
private void validateArg(Object arg, String argName) {
BindingResult result = getBindingResult(arg, argName);
validator.validate(arg, result);
if (result.hasErrors()) {
throw new HttpMessageConversionException("Validation of controller input parameter failed",
new BindException(result));
}
}
private BindingResult getBindingResult(Object target, String targetName) {
return new BeanPropertyBindingResult(target, targetName);
}
#Required
public void setValidator(Validator validator) {
this.validator = validator;
}
}
One limitation with this work-around is that it can only apply a single validator to all controllers. You can also avoid it.
public class TypeMatchingValidator implements Validator, InitializingBean, ApplicationContextAware {
private ApplicationContext context;
private Collection<Validator> validators;
public void afterPropertiesSet() throws Exception {
findAllValidatorBeans();
}
public boolean supports(Class clazz) {
for (Validator validator : validators) {
if (validator.supports(clazz)) {
return true;
}
}
return false;
}
public void validate(Object target, Errors errors) {
for (Validator validator : validators) {
if (validator.supports(target.getClass())) {
validator.validate(target, errors);
}
}
}
private void findAllValidatorBeans() {
Map<String, Validator> validatorBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, Validator.class, true, false);
validators = validatorBeans.values();
validators.remove(this);
}
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
}
Spring XML configuration file using the validator aspect and the meta-validator together:
<!-- enable Spring AOP support -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- declare the validator aspect and inject the validator into it -->
<bean id="validatorAspect" class="com.something.RequestBodyValidatorAspect">
<property name="validator" ref="validator"/>
</bean>
<!-- inject the validator into the DataBinder framework -->
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="webBindingInitializer">
<bean class="org.springframework.web.bind.support.ConfigurableWebBindingInitializer" p:validator-ref="validator"/>
</property>
</bean>
<!-- declare the meta-validator bean -->
<bean id="validator" class="com.something.TypeMatchingValidator"/>
<!-- declare all Validator beans, these will be discovered by TypeMatchingValidator -->
<bean class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
<bean class="com.something.PersonValidator"/>
<bean class="com.something.AccountValidator"/>
Resources Refs:scottfrederick:pring-3-Validation-Aspect
Solution#4:
Yet another solution for form validation using aop , you can check the blog: form-validation-using-aspect-oriented-programming-aop-in-spring-framework

How to return JSON response for unauthorized AJAX calls instead of login page as AJAX response?

I have implemented Spring Security in my application. Whenever someone tries to access any url if authentication is required for these urls user will be redirected to login page. Now, if AJAX call is made for any such url I would like to return JSON response instead of login page's HTML as AJAX response. How can I do that ?
You have to create json for this i am doing here with .net
var url="url";
$.ajax({
type: "get",
dataType: "json",
data:url,
async: true,
url: "testCall",//this can be your api or any server side call
success: function (data) {
},
failure: function () {
alert(textStatus);
}
});
//here is server side code for creating json
[WebMethod(EnableSession = true)]
[ScriptMethod(UseHttpGet = true)]
public void testCall(string url)
{
Context.Response.Write()//here your will just hard code the json data
//it will receive by ajax success method.
}
Faced the same thing not long ago, came out with this solution.
You'll have to redefine the authentication entry point to handle the exception and returning a proper JSON response.
First create a class for your response. Needs to be a POJO.
public class MyErrorResponse {
// your stuff here, and getters / setters
}
Then go define the authentication entry point
public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {
private List<HttpMessageConverter<Object>> messageConverters = new ArrayList<>();
private MediaType retrieveRequestMediaType(HttpServletRequest request) {
String accept = request.getHeader("accept");
if(Strings.isNullOrEmpty(accept))
accept = MediaType.APPLICATION_JSON_VALUE;
MediaType requestMediaType = MediaType.valueOf(accept);
return requestMediaType;
}
private HttpMessageConverter<Object> retrieveMessageConverter(List<HttpMessageConverter<Object>> messageConverters, Class<?> clazz, MediaType mediaType) {
for (HttpMessageConverter<Object> httpMessageConverter : messageConverters) {
if(httpMessageConverter.canWrite(clazz, mediaType)) {
return httpMessageConverter;
}
}
}
#Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
log.warn(String.format("Unauthorized access with session id '%s'", request.getSession().getId()));
MyErrorResponse esponse = new MyErrorResponse();
// populate your response object with all the info you need
MediaType mediaType = MediaType.APPLICATION_JSON;
try{
mediaType = retrieveRequestMediaType(request);
} catch(InvalidMediaTypeException imte) {
// log, do nothing
}
// getting the best fitting message converter, according to the "accept" header of the request
HttpMessageConverter<Object> httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, mediaType);
if(httpMessageConverter == null) {
log.info("Could not find specific handler. Using JSON.");
httpMessageConverter = retrieveMessageConverter(messageConverters, MyErrorResponse.class, MediaType.APPLICATION_JSON);
}
response.setStatus(HttpStatus.UNAUTHORIZED.value());
ServletServerHttpResponse serverHttpResponse = new ServletServerHttpResponse(errorResponse);
httpMessageConverter.write(response, mediaType, serverHttpResponse);
}
}
Once you got your bean set up, time to wire it up in the security context:
<beans:bean class="[fully qualified name of the entry point class]" id="myBasicAuthenticationEntryPoint">
<beans:property name="messageConverters">
<beans:list>
<!-- add message converters here -->
<!-- Spring provide lots of them, google it -->
</beans:list>
</beans:property>
</beans:bean>
<http use-expressions="true">
<http-basic entry-point-ref="myBasicAuthenticationEntryPoint" />
<!-- add other stuff here, if needed -->
</http>
Hope it helps

how to include error page in spring MVC 3.0?

how to include error page in spring MVC 3.0 ?
How show error page on exception occurrence .
<http auto-config="true">
<access-denied-handler ref="my403" />
<intercept-url pattern="/admin**" access="ROLE_ADMIN" />
</http>
<beans:bean id="my403" class="com.mkyong.web.exception.MyAccessDeniedHandler">
<beans:property name="errorPage" value="403" />
</beans:bean>
See either this thread on stackoverflow or work with #ControllerAdvice.
You can build your own error controller quite easy:
#ControllerAdvice
public class ExceptionHandlingController {
public static final String DEFAULT_ERROR_VIEW = "generalError";
final String NEW_LINE = System.getProperty("line.separator");
StringBuilder stackTraceString = new StringBuilder("");
#ExceptionHandler(Exception.class)
public ModelAndView handleError(HttpServletRequest req, Exception exception) {
//System.out.println("Request: " + req.getRequestURL() + " raised " + exception);
ModelAndView mav = new ModelAndView(DEFAULT_ERROR_VIEW);
mav.addObject("errorMessage", exception.getMessage());
for (StackTraceElement element : exception.getStackTrace() ){
stackTraceString.append( element );
stackTraceString.append( NEW_LINE );
}
mav.addObject("stackTrace", stackTraceString);
mav.addObject("url", req.getRequestURL());
return mav;
}
}

400 Bad Request when uploading byte[] with Spring RestTemplate to SpringMVC rest endpoint

I am trying to upload a byte[] that contains an image to my Spring rest service (running in Spring Boot, btw) as a MultipartFile with my client running Spring RestTemplate and am getting HttpClientErrorException: 400 Bad Request.
My endpoint:
#RequestMapping(value="/scale/{percent}", method= RequestMethod.POST)
public ResponseEntity scaleImage(#PathVariable("percent") float percent,
#RequestParam("file") MultipartFile file) {
try {
if (!file.isEmpty()) {
byte [] result = transformService.scaleImage(percent, file.getBytes());
return getResponseEntityFromBytes(result);
} else {
return generateBadRequestError();
}
} catch (Exception e) {
if (e instanceof InvalidOperationParameterException) {
// TODO - populate message with bad parameters
LOGGER.log(Level.FINE, "Invalid Parameters: ");
return generateBadRequestError();
} else {
LOGGER.log(Level.SEVERE, "Exception caught: " + e.getMessage(), e);
return generateServerError(e.getMessage());
}
}
}
My Spring RestTemplate client:
public void scaleImage(byte[] image, float percent) throws Exception {
String url = "http://localhost:8080/scale/" + percent;
this.testNumberThreads=10;
this.testNumberThreads=10;
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<>();
mvm.add("file", image);
TransformedResponse r = doPost(url, mvm);
}
private TransformedResponse doPost(String url, MultiValueMap<String, Object> mvm) {
RestTemplate restTemplate = new RestTemplate();
TransformedResponse xr = null;
try {
xr = restTemplate.postForObject(url, mvm, TransformedResponse.class);
} catch (RestClientException e) {
e.printStackTrace();
}
return xr;
}
...
public class TransformedResponse {
byte[] image;
public byte[] getImage() {
return image;
}
public void setImage(byte[] image) {
this.image = image;
}
}
Here is the exception I'm seeing in the client (nothing hitting server yet):
org.springframework.web.client.HttpClientErrorException: 400 Bad Request
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:91)
at org.springframework.web.client.RestTemplate.handleResponseError(RestTemplate.java:588)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:546)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502)
at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:330)
at com.me.image.xform.LoadTest.doPost(LoadTest.java:110)
at com.me.image.xform.LoadTest.loadTestScalePercent(LoadTest.java:75)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:232)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:89)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:175)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:74)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:211)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:67)
Why won't this request post correctly?
I found my problem. I needed to add an AbstractResource (in this case a ByteArrayResource) to my MultiValueMap instead of the raw byte array. Here's the code that fixed it:
public void scaleImage(byte[] image, float percent) throws Exception {
String url = "http://localhost:8080/scale/" + percent;
final byte[] rawBytes = image.clone();
MultiValueMap<String, Object> mvm = new LinkedMultiValueMap<>();
ByteArrayResource bar = new ByteArrayResource(rawBytes) {
#Override
public String getFilename() {
return "Test-"+rawBytes.length + ".jpg";
}
};
mvm.add("file", bar);
TransformedResponse r = doPost(url, mvm);
}
First of all, when using Spring, make sure that you have proper MultiPartFile resolver defined in your servlet context:
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="52428800"/>
<property name="maxInMemorySize" value="52428800"/>
</bean>
If you're using maven, this resolver is located in spring-web artifact:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${your.spring.version}</version>
</dependency>
Then, create form and make sure you're using proper enctype:
<form method="post" action="upload.form" enctype="multipart/form-data">
<input type="file" name="file"/>
<input type="submit"/>
</form>
Finally, handle file upload in your controller
#RequestMapping(value="/path", method= RequestMethod.POST)
public StringscaleImage(#RequestParam("file") MultipartFile file) {
//....
}
Remember that asynch file upload is supported only with HTML5, with others you'd need to use some workarounds (like flash or iframes).
If you're still facing 400 Error, add to your logging service this logger (or similar, depending on logging framework):
<appender name="console" class="org.apache.log4j.ConsoleAppender">
<param name="Target" value="System.out"/>
<param name="threshold" value="TRACE"/>
<layout class="org.apache.log4j.PatternLayout">
<param name="ConversionPattern" value="%d{HH:mm:ss,SSS} %-5p [%c] %m%n"/>
</layout>
</appender>
<logger name="org.springframework.web.method.HandlerMethod">
<level value="TRACE"/>
</logger>
<root>
<priority value="info"/>
<appender-ref ref="console"/>
</root>
It should output exception thrown during request handling
Instead of trying to pass the MultipartFile in as a request parameter, try the following:
#RequestMapping(value="/scale/{percent}", method= RequestMethod.POST)
public ResponseEntity scaleImage(#PathVariable("percent") float percent,
MultipartHttpServletRequest request) {
Iterator<String> fileNames = request.getFileNames();
MultipartFile uploadedFile = request.getFile(fileNames.next());
String fileName = uploadedFile.getName();
This is the only way I could actually get my multipart file to be accepted.
If you are still getting an empty file from this process, it must be something to do with how you are POST'ing the data.

Getting error to unmarshalling object from xml using resttemplate

I am using resttemplate of spring to invoke rest api getting error to unmarshall xml to object my code is:-
String uri = "http://devd.webservice.com/devpl/api/1.0/credential?apiKey=" + apiKey + "&signature=" + signature + "&timeStamp=" + timeStamp;
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.set("accountName", accountName);
requestHeaders.set("containerName", containerName);
requestHeaders.set("folderPath", folderPath);
requestHeaders.set("Content-Type","application/xml");
requestHeaders.set("Accept","application/xml");
RestTemplate template = getRestTemplate();
HttpEntity<String> requestEntity = new HttpEntity<String>(requestHeaders);
Credential result =(Credential)template.postForObject(uri,requestEntity,Credential.class);
Object classs bean on which i consume object:-
package com.simplidrivechn.netmagicsolutions.bean;
import com.thoughtworks.xstream.annotations.*;
#XStreamAlias("credential")
public class Credential
{
private String DestinationUrl;
private String AuthToken;
private String StorageUrl;
public String getAuthToken() {
return AuthToken;
}
public void setAuthToken(String AuthToken) {
this.AuthToken = AuthToken;
}
public String getDestinationUrl() {
return DestinationUrl;
}
public void setDestinationUrl(String DestinationUrl) {
this.DestinationUrl = DestinationUrl;
}
public String getStorageUrl() {
return StorageUrl;
}
public void setStorageUrl(String StorageUrl) {
this.StorageUrl = StorageUrl;
}
}
My spring configuration file:-
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<property name="messageConverters">
<list>
<bean id="messageConverter" class="org.springframework.http.converter.xml.MarshallingHttpMessageConverter">
<property name="marshaller" ref="xstreamMarshaller" />
<property name="unmarshaller" ref="xstreamMarshaller" />
</bean>
</list>
</property>
</bean>
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="aliases">
<props>
<prop key="credential">com.simplidrivechn.netmagicsolutions.bean.Credential</prop>
</props>
</property>
</bean>
</beans>
I am getting error:-
Exception in thread "main" org.springframework.http.converter.HttpMessageNotReadableException: Could not read [class com.simplidrivechn.netmagicsolutions.bean.Credential]; nested exception is org.springframework.oxm.UnmarshallingFailureException: XStream unmarshalling exception; nested exception is com.thoughtworks.xstream.mapper.CannotResolveClassException: Credential : Credential
please help me to resolve this error
Looking at your exception, it looks like that XStreamMarshaller's aliases are not set correctly in your spring context. You must make sure that your keys are 'aliases', i.e. root element in your case. Is 'credential' the root element of the xml response you are trying to deserialize? Note that aliases are case sensitive. Following code works for me. Note aliases.put("person", Person.class);My xml response has root element 'person'. If I change this key to lets say 'Person' like aliases.put("Person", Person.class); I exactly get the exception like you.
XStreamMarshaller marshaller = new XStreamMarshaller();
Map<String, Class> aliases = new HashMap<String, Class>();
aliases.put("person", Person.class);
marshaller.setAliases(aliases);
MarshallingHttpMessageConverter converter = new MarshallingHttpMessageConverter(
marshaller, marshaller);
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(converter);
template.setMessageConverters(converters);
HttpEntity request = new HttpEntity(null, headers);
ResponseEntity<Person> response = template.exchange(url,
HttpMethod.GET, request, Person.class);
Another way to define aliases is autoscan.
<bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
<property name="autodetectAnnotations" value="true"/>
<property name="annotatedClasses">
<array>
<value>com.simplidrivechn.netmagicsolutions.bean.Credential</value>
</array>
</property>
</bean>

Resources