restTemplate java.lang.IllegalArgumentException: "None" does not contain '/' - java

Ok first of all code (its mega simple):
#Controller
#RequestMapping("/")
public class HelloController {
private final static Logger logger = Logger.getLogger(HelloController.class);
#RequestMapping(method = RequestMethod.GET)
public String printWelcome(ModelMap model) {
logger.info("ELO ELO");
model.addAttribute("message", "Hello world!");
RestTemplate restTemplate = new RestTemplate();
String url = "http://192.168.0.200:8000/GPIO/11/function/in";
//String url = "http://192.168.0.200:8000/GPIO/11/function";
//restTemplate.getForObject(url, String.class);
String test = "";
restTemplate.postForObject(url, null, String.class);
logger.info(test);
return "hello";
}
Next example that I'm not a crazy man here is response from postman (chrome):
And at the end full error log:
type Exception report
message Request processing failed; nested exception is
java.lang.IllegalArgumentException: "None" does not contain '/'
description The server encountered an internal error that prevented it
from fulfilling this request.
exception
org.springframework.web.util.NestedServletException: Request
processing failed; nested exception is
java.lang.IllegalArgumentException: "None" does not contain '/'
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:927)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
root cause
java.lang.IllegalArgumentException: "None" does not contain '/'
org.springframework.http.MediaType.parseMediaType(MediaType.java:697)
org.springframework.http.HttpHeaders.getContentType(HttpHeaders.java:305)
org.springframework.web.client.HttpMessageConverterExtractor.getContentType(HttpMessageConverterExtractor.java:113)
org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:84)
org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:492)
org.springframework.web.client.RestTemplate.execute(RestTemplate.java:447)
org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:295)
pl.piquarium.mvc.HelloController.printWelcome(HelloController.java:35)
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
java.lang.reflect.Method.invoke(Method.java:606)
org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:176)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:439)
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:427)
org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:925)
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:915)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:811)
javax.servlet.http.HttpServlet.service(HttpServlet.java:618)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:796)
javax.servlet.http.HttpServlet.service(HttpServlet.java:725)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
note The full stack trace of the root cause is available in the Apache
Tomcat/8.0.3 logs.
Request headers:
Accept:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Encoding:gzip,deflate,sdch
Accept-Language:pl-PL,pl;q=0.8,en-US;q=0.6,en;q=0.4
Cache-Control:max-age=0
Connection:keep-alive
Cookie:__utma=212787668.2094541430.1400264829.1400264829.1400268775.2; __utmz=212787668.1400264829.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none)
Host:192.168.0.200:8000
User-Agent:Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.137 Safari/537.36
Response Headers:
Cache-Control:no-cache
Content-Length:2
Content-Type:None
Date:Fri, 16 May 2014 22:37:16 GMT
Server:WebIOPi/0.7.0/Python3.2

Did you try setting headers like below,
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);//or any other required
HttpEntity request = new HttpEntity(null, headers);
RestTemplate restTemplate = new RestTemplate();
String url = "http://192.168.0.200:8000/GPIO/11/function/in";
String response = restTemplate.postForObject(url,request,String.class);

The problem is that the server is returning an invalid content type of None instead of something like text/plain, and Spring REST is choking on it. You will need to add a custom message converter for the None type, not use a typed query and parse the response object yourself, or get the Pi people to fix their broken Web server.

Related

Intermittently receiving StackOverflowError on spring boot restTemplate.exchange

Below is the logic that I used for RestTemplate. For 1000 requests made, 50 requests fail intermittently. I have to trigger a GET request which sends List<Students> in the response. Hence used ParameterizedTypeReference.
The logger "Outbound request" displays in the logs and after that I received:org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError.
The logger "Inbound response" is not displaying.
Code:
private RestTemplate restTemplate;
public List<Students> getConsents(Long managementid) {
List<Students> studentList = new ArrayList<>();
RequestEntity<String> requestEntity = buildRequestEntity(managementid);
ResponseEntity<List<Students>> response = null;
LOGGER.info("Outbound request");
response = restTemplate.exchange(requestEntity, new ParameterizedTypeReference<List<Students>>() {});
LOGGER.info("Inbound response");
if(null != response && response.getStatusCode().is2xxSuccessful())
studentList = response.getBody();
return studentList;
}
private RequestEntity<String> buildRequestEntity(Long managementid) {
HttpHeaders headers = new HttpHeaders();
headers.set("Accept", MediaType.APPLICATION_JSON_VALUE);
URI uri = UriComponentsBuilder.fromHttpUrl(url)
.queryParam("managementid", managementid)
.build()
.toUri();
return new RequestEntity<>(headers, HttpMethod.GET, uri);
}
Stack Trace:
org.springframework.web.util.NestedServletException: Handler dispatch failed; nested exception is java.lang.StackOverflowError
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1053)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at ....
.....
at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219)
at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.StackOverflowError: null
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
at java.base/java.util.Collections$UnmodifiableCollection.isEmpty(Collections.java:1033)
......
Please help me if I have used the RestTemplate wrong or if you know why I am receiving this error. This occurs in our production environment and I'm not able to reproduce it in our test environment. All the exception handling is done, I just did not paste it here.

Feign Client Throwing Unauthorized Exception for Url, where authentication is not needed

I have followed this blog and have created few microservices: Eureka-server,Auth-service,Zuul-service,Gallery-service,Image-service.
From the gallery service I wanted to invoke auth-service API using Feign-Client
The url doesn't require authentication but the client throws FeignException$Unauthorized
I'm using JWT tokens for authentication.
//AuthServerProxy.java
#FeignClient(name = "auth-service")
#RibbonClient(name = "auth-service")
public interface AuthServiceProxy {
#PostMapping("/auth/authenticate")
public ResponseEntity<?> authenticate(#RequestBody UserEntity userEntity);
#GetMapping("/auth/register")
public String test();
}
Controller - Gallery Service
#Autowired
AuthServiceProxy authServiceProxy;
#GetMapping("/test")
public String test(){
UserEntity userEntity = new UserEntity();
userEntity.setUsername("admin");
userEntity.setPassword("admin");
ResponseEntity<?> responseEntity = authServiceProxy.authenticate(userEntity);
System.out.println(responseEntity.getStatusCode());
return responseEntity.toString();
}
#GetMapping("/test/str")
public String testStr(){
return authServiceProxy.test();
}
Security Config - ZuulServer, Auth-Service
.antMatchers(HttpMethod.POST, "/auth/authenticate").permitAll()
This is the error log
ERROR 1123 --- [nio-8100-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)] with root cause
feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)
at feign.FeignException.errorStatus(FeignException.java:94) ~[feign-core-10.2.3.jar:na]
at feign.FeignException.errorStatus(FeignException.java:86) ~[feign-core-10.2.3.jar:na]
at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149) ~[feign-core-10.2.3.jar:na]
at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78) ~[feign-core-10.2.3.jar:na]
at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-10.2.3.jar:na]
at com.sun.proxy.$Proxy101.authenticate(Unknown Source) ~[na:na]
at com.test.gallery.Controller.test(Controller.java:47) ~[classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
...
Any help much appreciated.
TIA
Looks like the Authentication header is not passing with FeignClient
try to add this config:
#Bean
public RequestInterceptor requestInterceptor() {
return requestTemplate -> {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", details.getTokenValue()));
}
};
}
Feign is not aware of the Authorization that should be passed to the target service .Unfortunately, you need to handle this yourself.Below is a java class that can help
#Component
public class FeignClientInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
#Override
public void apply(RequestTemplate template) {
SecurityContext securityContext = SecurityContextHolder.getContext();
Authentication authentication = securityContext.getAuthentication();
if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
}
}
It sounds like the problem could be that you don't have the #EnableResourceServer attached to your Auth-Service.
Without that annotation any endpoint that isn't apart of the spring security package (eg. /oauth/token, /oauth/check_token) will automatically require Authorization.
Furthermore you may need to add in a ResourceServerConfigurerAdapter similar to this to make sure that the resource endpoints are configured to permit all like so:
#Configuration
#EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
private final TokenStore tokenStore;
public ResourceServerConfig(TokenStore tokenStore) {
this.tokenStore = tokenStore;
}
#Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenStore(tokenStore);
}
#Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(HttpMethod.POST).permitAll()
.and()
.logout().disable()
.csrf().disable();
}
}
*******EDIT*********
If you’re able to get an ok response from a request in the browser but not feign then your problem most likely is that your Feign client isn’t pointing to the correct endpoint. Normally you would expect a 404 error but since the API is secured you get a 401 because it doesn’t even allow you to know what’s a valid endpoint unless you’re authenticated or it’s an unsecured endpoint
If you have your AuthServiceProxy feign client use your zuul-server instead of the auth-service, you can then add logging to your zuul filter to see what both successful and unsuccessful requests looks like. From there make the necessary changes to have your proxy request match the request you made from the browser and you should be good to go

org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type

response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
PrintWriter out = response.getWriter();
String Empcode="10743";
String password="IsaiVanan";
final String uri = "https://vtop9.vit.ac.in/vtoplogin/employeeLoginPost";
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
MultiValueMap<String, String> postParams = new LinkedMultiValueMap<String, String>();
postParams.add("userid",Empcode);
postParams.add("pwd",password);
HttpEntity<MultiValueMap<String, String>> entity = new HttpEntity<> (postParams,headers);
System.out.println("Try coming1..!");
ResponseEntity<UserValidation> result = restTemplate.exchange(uri, HttpMethod.POST,entity, UserValidation.class);
System.out.print("result..."+result.getBody().getResponseMsg());
I did everything which i add dependency of rest api,
this witch i did response content in application/json still; it not working i find that solution only in some stackoverflow verify..!
public class UserValidation {
private String responseMsg ;
private Integer responseCode;
public String getResponseMsg() {
return responseMsg;
}
public void setResponseMsg(String responseMsg) {
this.responseMsg = responseMsg;
}
public Integer getResponseCode() {
return responseCode;
}
public void setResponseCode(Integer responseCode) {
this.responseCode = responseCode;
}
}
org.springframework.web.client.RestClientException: Could not write request: no suitable HttpMessageConverter found for request type [org.springframework.util.LinkedMultiValueMap] and content type [application/json]
at org.springframework.web.client.RestTemplate$HttpEntityRequestCallback.doWithRequest(RestTemplate.java:597)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:436)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:401)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:377)
at sample.doGet(sample.java:82)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:475)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:80)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:625)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:498)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:796)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1372)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)
error occurs when i add jar files in project of build path, namely rest api jar, spring frameworks...
error shows and consult with everyone which they did know about rest api.
which someone please find the solution and get the corrected output please
For retrieving a resource with application/json Accept Header, you need MappingJackson2HttpMessageConverter, which is one of the special HttpMessageConverters which looks like you're missing.
Try adding below just after initializing RestTemplate as :
RestTemplate restTemplate = new RestTemplate();
List<HttpMessageConverter<?>> converters = new ArrayList<HttpMessageConverter<?>>();
converters.add(new MappingJackson2HttpMessageConverter());
restTemplate.setMessageConverters(converters);
// carry on with your code
Spring is not able to parse your request payload (LinkedMultiValueMap) to JSON. Please make sure that you use a converter that can do this. So your request is not sent to the target system.
Please read this for more information: https://www.baeldung.com/spring-httpmessageconverter-rest
Try this -
private HttpEntity<MultiValueMap<String, Object>> makeExportRequestEntity(RequestObject requestObject ) throws IOException {
MultiValueMap<String, Object> bodyMap = new LinkedMultiValueMap<>();
bodyMap.add("DataOne", requestObject .getDataOne());
bodyMap.add("DataTwo", requestObject .getDataTwo());
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(bodyMap, headers);
return requestEntity;
}

Deserialization of the Java object in using Apache HttpClient Api is not working

I am new to the Spring MVC. I am using the Spring release 4.1.6 and deployed my two web applications A and B on tomcat 7 for the development environment. But in the actual production environment the application A will be deployed on weblogic and application B will be deployed on websphere. Below is the scenario occuring on the development environment.
From the Application A , I am submitting the jsp page and invoked the below method of the controller. From this method I am creating the HttpPost request and sending the RequestDetails domain object to the another controller's method using ApacheHttpClient api.This is the code from the sender's side or from Application A's controller.
#RequestMapping(value="/httprequestJinesh.cvr",method = RequestMethod.POST)
public #ResponseBody String createMediaRequest(#RequestBody RequestDetails requestDetails ,HttpServletRequest request, HttpServletResponse response ) throws Exception{
System.out.println("****************** createMediaRequest Method of the controller gets invoked 123 *****************");
if(requestDetails!=null){
System.out.println("******************* Requestdetails Is Been Object is been received ***************" + requestDetails.getRequestId());
}
//Sending the HttpPostRequest
StringBuilder url = new StringBuilder();
String serverUrl = "http://localhost:8080/raws/createMediaRequest.raws"; //get it from app_properpties table
url.append(serverUrl);
System.out.println("************** Started creating the Httpost request ********************");
final HttpParams httpParams = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParams, 10000);
HttpClient httpClient = new DefaultHttpClient(httpParams);
HttpPost httppostRequest = new HttpPost(serverUrl);
httppostRequest.setEntity(new SerializableEntity(requestDetails,false));
System.out.println("************** Finished creating the Http Post request ********************");
System.out.println("*********** Before sending the Httppost Request ******************");
HttpResponse httpResponse = httpClient.execute(httppostRequest);
System.out.println("*********** After sending teh Httppost Request ******************");
return "SUCCESS";
}
On the receiver application's controller I am trying to deserialize the domain object received in the POST request. Both of the Application A and B have the RequestDetails class available in the workspace but in both of the case the package hierachy for the domain object is different.Say for example in Application A RequestDetails object is available in com.test and in application B it is available in the com.test123. Below is the code on the receiver application's controller.
RequestMapping(value = "/createMediaRequest.raws", method = RequestMethod.POST)
public Object createMediaRequest(HttpServletRequest request, HttpServletResponse response){
System.out.println("***************** MediaWorkflowController Received Media Request *******************");
try{
ObjectInputStream in = new ObjectInputStream(request.getInputStream());
RequestDetails requestDetails=(RequestDetails)in.readObject();
if(requestDetails!=null){
System.out.println("requestdetails object is not null *******************" + requestDetails.getRequestId());
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
Below is the code for the RequestDetails.java on Application A
package com.test;
public class RequestDetails implements java.io.Serializable{
String requestId;
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}
Below is the code for the RequestDetails.java on Application B
package com.test123;
public class RequestDetails implements java.io.Serializable{
String requestId;
public String getRequestId() {
return requestId;
}
public void setRequestId(String requestId) {
this.requestId = requestId;
}
}
I am getting the below exception when the code for the receiver application's controller get executed.
****************** createMediaRequest Method of the controller gets invoked 123 *****************
******************* Requestdetails Is Been Object is been received ***************12345
************** Started creating the Httpost request ********************
************** Finished creating the Http Post request ********************
*********** Before sending the Httppost Request ******************
***************** MediaWorkflowController Received Media Request *******************
java.lang.ClassNotFoundException: com.test.RequestDetails
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1720)
at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1571)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:274)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:625)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1612)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1517)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1350)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:370)
at com.cira.raws.mediawf.api.services.controller.MediaWFController.createMediaRequest(MediaWFController.java:38)
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.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:137)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandleMethod(RequestMappingHandlerAdapter.java:776)
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:705)
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:959)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:893)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:868)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:650)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:731)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:303)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:505)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:316)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:745)
*********** After sending teh Httppost Request ******************
As per my understanding the issue has occured while deserializing the object. If I am keeping the same package hierachy on both of the sides for the RequestDetails class the code is working fine.Is it compulsory to have the same package hierarchy for the RequestDetails domain object? If no how to resolve the issue I am facing?
To deserialise the object you need to have the same class in both instances. This includes the package name of the class.
As you have said the packages are different then the failure you are seeing is easy to understand.

Spring MVC - AngularJS - File Upload - org.apache.commons.fileupload.FileUploadException

I have a Java Spring MVC Web application as server. And AngularJS based application as client.
In AngularJS, I have to upload a file and send to server.
Here is my html
<form ng-submit="uploadFile()" class="form-horizontal" enctype="multipart/form-data">
<input type="file" name="file" ng-model="document.fileInput" id="file" onchange="angular.element(this).scope().setTitle(this)" />
<input type="text" class="col-sm-4" ng-model="document.title" id="title" />
<button class="btn btn-primary" type="submit">
Submit
</button>
</form>
Here is my UploadController.js
'use strict';
var mainApp=angular.module('mainApp', ['ngCookies']);
mainApp.controller('FileUploadController', function($scope, $http) {
$scope.document = {};
$scope.setTitle = function(fileInput) {
var file=fileInput.value;
var filename = file.replace(/^.*[\\\/]/, '');
var title = filename.substr(0, filename.lastIndexOf('.'));
$("#title").val(title);
$("#title").focus();
$scope.document.title=title;
};
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http({
method: 'POST',
url: '/serverApp/rest/newDocument',
headers: { 'Content-Type': 'multipart/form-data'},
data: formData
})
.success(function(data, status) {
alert("Success ... " + status);
})
.error(function(data, status) {
alert("Error ... " + status);
});
};
});
It is going to the server. Here is my DocumentUploadController.java
#Controller
public class DocumentUploadController {
#RequestMapping(value="/newDocument", headers = "'Content-Type': 'multipart/form-data'", method = RequestMethod.POST)
public void UploadFile(MultipartHttpServletRequest request, HttpServletResponse response) {
Iterator<String> itr=request.getFileNames();
MultipartFile file=request.getFile(itr.next());
String fileName=file.getOriginalFilename();
System.out.println(fileName);
}
}
When I run this I get the following exception
org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found] with root cause
org.apache.commons.fileupload.FileUploadException: the request was rejected because no multipart boundary was found
at org.apache.commons.fileupload.FileUploadBase$FileItemIteratorImpl.<init>(FileUploadBase.java:954)
at org.apache.commons.fileupload.FileUploadBase.getItemIterator(FileUploadBase.java:331)
at org.apache.commons.fileupload.FileUploadBase.parseRequest(FileUploadBase.java:351)
at org.apache.commons.fileupload.servlet.ServletFileUpload.parseRequest(ServletFileUpload.java:126)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.parseRequest(CommonsMultipartResolver.java:156)
at org.springframework.web.multipart.commons.CommonsMultipartResolver.resolveMultipart(CommonsMultipartResolver.java:139)
at org.springframework.web.servlet.DispatcherServlet.checkMultipart(DispatcherServlet.java:1047)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:892)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:856)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:920)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:827)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:801)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1023)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
In my applicationContext.xml, I have mentioned
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000" />
</bean>
I am using
spring - 3.2.1.RELAESE
commons-fileupload - 1.2.2
commons-io - 2.4
How to solve this?
It would be great if anyone tel me how to send file and other formdata from angularJS and get it in server.
UPDATE 1
#Michael : I can see this only in the console, when I click submit.
POST http://localhost:9000/serverApp/rest/newDocument 500 (Internal Server Error) angular.js:9499
(anonymous function) angular.js:9499
sendReq angular.js:9333
$http angular.js:9124
$scope.uploadFile invoice.js:113
(anonymous function) angular.js:6541
(anonymous function) angular.js:13256
Scope.$eval angular.js:8218
Scope.$apply angular.js:8298
(anonymous function) angular.js:13255
jQuery.event.dispatch jquery.js:3074
elemData.handle
My server is running in other port 8080. I am uisng yeoman,grunt and bower. So thin gruntfile.js I have mentioned the server port. So it goes to server and running that and throws the exception
UPDATE 2
The boundary is not setting
Request URL:http://localhost:9000/serverApp/rest/newDocument
Request Method:POST
Status Code:500 Internal Server Error
Request Headers view source
Accept:application/json, text/plain, */*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8
Connection:keep-alive
Content-Length:792
Content-Type:multipart/form-data
Cookie:ace.settings=%7B%22sidebar-collapsed%22%3A-1%7D; isLoggedIn=true; loggedUser=%7B%22name%22%3A%22admin%22%2C%22password%22%3A%22admin23%22%7D
Host:localhost:9000
Origin:http://localhost:9000
Referer:http://localhost:9000/
User-Agent:Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36
X-Requested-With:XMLHttpRequest
Request Payload
------WebKitFormBoundaryCWaRAlfQoZEBGofY
Content-Disposition: form-data; name="file"; filename="csv.csv"
Content-Type: text/csv
------WebKitFormBoundaryCWaRAlfQoZEBGofY--
Response Headers view source
connection:close
content-length:5007
content-type:text/html;charset=utf-8
date:Thu, 09 Jan 2014 11:46:53 GMT
server:Apache-Coyote/1.1
I faced the same issue and encountered the same issue even after updating the transformRequest. 'Some how, the header boundary doesn't seem to have set correctly.
Following http://uncorkedstudios.com/blog/multipartformdata-file-upload-with-angularjs, the problem is resolved. Extract from the location....
By setting ‘Content-Type’: undefined, the browser sets the Content-Type to multipart/form-data for us and fills in the correct boundary. Manually setting ‘Content-Type’: multipart/form-data will fail to fill in the boundary parameter of the request.
Not sure if this helps any one but perhaps makes it easy for people looking at this post... At least, it makes it less difficult.
Introduction
I have had the same problem and found a complete solution to send both json and file from angular based page to a Spring MVC method.
The main problem is the $http which doesn't send the proper Content-type header (I will explain why).
The theory about multipart/form-data
To send both json and file we need to send a multipart/form-data, which means "we send different items in the body separated by a special separator". This special separator is called "boundary", which is a string that is not present in any of the elements that are going to be sent.
The server needs to know which boundary is being used so it has to be indicated in the Content-type header (Content-Type multipart/form-data; boundary=$the_boundary_used).
So... two things are needed:
In the header --> indicate multipart/form-data AND which boundary is used (here is where $http fails)
In the body --> separate each request parameter with the boundary
Example of a good request:
header
Content-Type multipart/form-data; boundary=---------------------------129291770317552
Which is telling the server "I send a multipart message with the next separator (boundary): ---------------------------129291770317552
body
-----------------------------129291770317552 Content-Disposition: form-data; name="clientInfo"
{ "name": "Johny", "surname":"Cash"}
-----------------------------129291770317552
Content-Disposition: form-data; name="file"; filename="yourFile.pdf"
Content-Type: application/pdf
%PDF-1.4
%õäöü
-----------------------------129291770317552 --
Where we are sending 2 arguments, "clientInfo" and "file" separated by the boundary.
The problem
If the request is sent with $http, the boundary is not sent in the header (point 1), so Spring is not able to process the data (it doesn't know how to split the "parts" of the request).
The other problem is that the boundary is only known by the FormData... but FormData has no accesors so it's impossible to know which boundary is being used!!!
The solution
Instead of using $http in js you should use standard XMLHttpRequest, something like:
//create form data to send via POST
var formData=new FormData();
console.log('loading json info');
formData.append('infoClient',angular.toJson(client,true));
// !!! when calling formData.append the boundary is auto generated!!!
// but... there is no way to know which boundary is being used !!!
console.log('loading file);
var file= ...; // you should load the fileDomElement[0].files[0]
formData.append('file',file);
//create the ajax request (traditional way)
var request = new XMLHttpRequest();
request.open('POST', uploadUrl);
request.send(formData);
Then, in your Spring method you could have something like:
#RequestMapping(value = "/", method = RequestMethod.POST)
public #ResponseBody Object newClient(
#RequestParam(value = "infoClient") String infoClientString,
#RequestParam(value = "file") MultipartFile file) {
// parse the json string into a valid DTO
ClientDTO infoClient = gson.fromJson(infoClientString, ClientDTO.class);
//call the proper service method
this.clientService.newClient(infoClient,file);
return null;
}
Carlos Verdes's answer failed to work with my $http interceptor, which adds authorization headers and so on. So I decided to add to his solution and create mine using $http.
Clientside Angular (1.3.15)
My form (using the controllerAs syntax) is assuming a file and a simple object containing the information we need to send to the server. In this case I'm using a simple name and type String property.
<form>
<input type="text" ng-model="myController.myObject.name" />
<select class="form-control input-sm" ng-model="myController.myObject.type"
ng-options="type as type for type in myController.types"></select>
<input class="input-file" file-model="myController.file" type="file">
</form>
The first step was to create a directive that binds my file to the scope of the designated controller (in this case myController) so I can access it. Binding it directly to a model in your controller won't work as the input type=file isn't a built-in feature.
.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function(){
scope.$apply(function(){
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
Secondly I created a factory called myObject with an instance method create that allows me to transform the data upon invoking create on the server. This method adds everything to a FormData object and converts it using the transformRequest method (angular.identity). It is crucial to set your header to undefined. (Older Angular versions might require something than undefined to be set). This will allow the multidata/boundary marker to be set automatically (see Carlos's post).
myObject.prototype.create = function(myObject, file) {
var formData = new FormData();
formData.append('refTemplateDTO', angular.toJson(myObject));
formData.append('file', file);
return $http.post(url, formData, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined }
});
}
All that is left to do client side is instantiating a new myObject in myController and invoking the create method in the controller's create function upon submitting my form.
this.myObject = new myObject();
this.create = function() {
//Some pre handling/verification
this.myObject.create(this.myObject, this.file).then(
//Do some post success/error handling
);
}.bind(this);
Serverside Spring (4.0)
On the RestController I can now simply do the following: (Assuming we have a POJO MyObject)
#RequestMapping(method = RequestMethod.POST)
#Secured({ "ROLE_ADMIN" }) //This is why I needed my $httpInterceptor
public void create(MyObject myObject, MultipartFile file) {
//delegation to the correct service
}
Notice, I'm not using requestparameters but just letting spring do the JSON to POJO/DTO conversion. Make sure you got the MultiPartResolver bean set up correctly too and added to your pom.xml. (And Jackson-Mapper if needed)
spring-context.xml
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="268435456" /> <!-- 256 megs -->
</bean>
pom.xml
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>${commons-fileupload.version}</version>
</dependency>
You can try this
.js
$scope.uploadFile=function(){
var formData=new FormData();
formData.append("file",file.files[0]);
$http.post('/serverApp/rest/newDocument', formData, {
transformRequest: function(data, headersGetterFunction) {
return data;
},
headers: { 'Content-Type': undefined }
}).success(function(data, status) {
alert("Success ... " + status);
}).error(function(data, status) {
alert("Error ... " + status);
});
.java
#Controller
public class DocumentUploadController {
#RequestMapping(value="/newDocument", method = RequestMethod.POST)
public #ResponseBody void UploadFile(#RequestParam(value="file", required=true) MultipartFile file) {
String fileName=file.getOriginalFilename();
System.out.println(fileName);
}
}
That's based on https://github.com/murygin/rest-document-archive
There is a good example of file upload
https://murygin.wordpress.com/2014/10/13/rest-web-service-file-uploads-spring-boot/

Categories

Resources