Consider following function:
#POST
#Path("/handle_response")
#Produces(MediaType.APPLICATION_JSON)
public ResponseJsonBean handle(#FormParam("first") Integer first, #FormParam("second") Integer second)
{
////// bla bla
}
The above function is called when I make a POST x-www-form-urlencoded request. But the function is not called when I make POST form data request. Why it is not called in the latter case? and how can I make such function which works for latter request.
Yeah application/x-www-form-urlencoded and multipart/form-data are complete different types and formats. The correct provider to read the request is discovered through the type sent.
For multipart support, you should add the Jersey multipart dependency
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-multipart</artifactId>
<version>${jersey2.version}</version>
</dependency>
Then in your resource method do something like
#POST
#Path("/upload")
#Produces(MediaType.APPLICATION_JSON)
#Consumes({MediaType.MULTIPART_FORM_DATA})
public Response uploadFile(
#FormDataParam("file") InputStream fileInputStream,
#FormDataParam("file") FormDataContentDisposition cdh) throws Exception{
}
See Also:
An example with the client side also
Jersey Multipart Documentation
In case you are using Jersey 1.x
Related
On my REST API, I've got a POST that did not previously need any input expect from a path parameter. However, I now want to expand by accepting an optional form parameter. I tried this out with #FormParam, but it turns out that (at least) one of the clients are not setting content type application/x-www-form-urlencoded, and Jersey fails with this:
The #FormParam is utilized when the content type of the request entity
is not application/x-www-form-urlencoded
Can I solve this? I want to allow the new clients to send in the form and still accept whatever content type the old clients are setting.
A bad solution would be to use query parameter.
Edit:
Tried adding a new resource with a separate #Consumes
#POST
#Path("/something")
#Consumes(MediaType.WILDCARD)
public Response thisDoesNotWork(){
and
#POST
#Path("/something")
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response thisWorks(#FormParam("input") String input){
In my tests, when actually sending a form, it works. When I don't send set a content type, it fails with the same error as above. So it seems it selects the thisWorks(..) resource.
Edit2:
I figured out a work-around
#POST
#Path("/something")
#Consumes(MediaType.WILDCARD)
public Response thisDoesNotWork(
MultivaluedMap<String, String> formParams
){
Using this as the only resource, formParam will be null if no content type is set, and will contain the form parameters if form is set. It will mess up the documentation probably but at least it will work.
I have a Spring Boot Rest Service which uploads a file via the RestTemplate exchange method. The upload is working as it should but there is a problem with utf-8 filenames which for example contain german umlauts like äöü.
When uploading a file from a HTML5 App it is working without any problem so it is not a problem at the receiving service.
Without setting any encoding for the MultipartCharset the umlauts are replaced by "?" (e.g. Überschrift.txt gets ?berschrift.txt), as US-ASCII is used for the filename encoding. I tried setting the MultipartCharset to UTF-8 with this code:
((AllEncompassingFormHttpMessageConverter)restTemplate.getMessageConverters().get(4)).setMultipartCharset(Charset.forName("UTF-8"));
Then the filename is put like this into the request:
Content-Disposition: form-data; name="file"; filename="=?UTF-8?Q?=C3=9Cberschrift.txt?="
The umlauts are encoded but the filename is transfered exactly like this and not with the correct umlauts. I think I am missing some property to set so the umlauts are really set as umlauts in the request.
The relevant part of my code is this:
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(uploadFile),"UTF-8")); bw.append(capturedDocument.getText());
bw.newLine();
bw.flush();
bw.close();
String complianceServiceUrl = complianceBackendRestSettings.getComplianceServiceURL();
RestTemplate restTemplate = new RestTemplate();
((AllEncompassingFormHttpMessageConverter)restTemplate.getMessageConverters().get(4)).setMultipartCharset(Charset.forName("UTF-8"));
ResponseEntity<JSONBoolean> responseEntity = null;
HttpHeaders uploadHeaders = new HttpHeaders();
uploadHeaders.set("Authorization", authorization);
uploadHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
LinkedMultiValueMap<String, Object> uploadMap = new LinkedMultiValueMap<String, Object>();
uploadMap.add("file", new FileSystemResource(uploadFile.getAbsolutePath()));
uploadMap.add("abonnementId", abos.toString());
HttpEntity<LinkedMultiValueMap<String, Object>> uploadRequestEntity = new HttpEntity<LinkedMultiValueMap<String, Object>>(
uploadMap, uploadHeaders);
responseEntity = restTemplate.exchange(complianceServiceUrl + "/uploadandassign", HttpMethod.POST,
uploadRequestEntity, JSONBoolean.class);
The umlauts in the files are complete correctly, so it's only the problem with the filename encoding.
I would appreciate any hint for a solution to this problem.
I also faced same issue, problem is that Spring's RestTemplate follows RFC 2047, but StandardMultipartHttpServletRequest supports only RFC 6266 format, or headers needs to be in UTF-8 already (what is some browsers behavior).
I've already filled bug request. I've just verified that commons-fileupload library will handle this correctly. If you are using Spring Boot, you will need:
Add commons-fileupload 1.3.2 on classpath
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.2</version>
</dependency>
Disable MultipartAutoConfiguration - for example by property spring.http.multipart.enabled=false or by #EnableAutoConfiguration(exclude={MultipartAutoConfiguration.class})
Define MultipartResolver in your configuration class
#Bean
public MultipartResolver multipartResolver() {
return new CommonsMultipartResolver();
}
I was facing the same problem, but setting the multipartCharset fixed it for me. Your client code looks correct, and the filename is correctly encoded in RFC 2047 format. This encoding is necessary because HTTP only accepts ascii in its headers. (What character encoding should I use for a HTTP header?)
On the server it should then be decoded back to Überschrift.txt. I'm not completely sure which spring component does this (assuming your serverside is also written in Spring), but I assume it's the multipart resolver
I'm using GWT RPC Calls for Server Side Request so far and it's pretty good. I'm planning on separating my Code into Servlets and GWT Client Side. Since i'm using RPC calls, it seems impossible. The Reason i want to do like this is , i'm planning to provide white labeling option for my App. So if i could separate the code to client code and servlets, i can simply provide the White Labeled client code to my Partners to host on their server. I have checked with GWT RequestBuilder and Access-Control Allow-Origin : Origin from Client Header and it works fine.
However i need to implement gwt-serialization over RequestBuilder request and Servlet Responses. How can i do this ..?
Scenario I like to make:
RequestBuilder sending Serializable String(Which is a IsSerialiazible object) to Servlet.
Servlet deserializes the String to Java Object,Processes and Returns the String Response of a 'IsSerialiazable' Object.
The Response String recieved in GWT RequestBuilder deserialzes it back to a Java Object(JS after Compiling).
I have checked on RemoteServiceServlet class which seems to have some info on serializing and deserializing request and response. But i couldn't get it right to get it to work with RequestBuilder. Any ideas , Hope it will be helpful for everyone.
public final void processPost(HttpServletRequest request,HttpServletResponse response)
throws IOException, ServletException,SerializationException
{
// Read the request fully.
//
String requestPayload = readContent(request);
// Let subclasses see the serialized request.
//
onBeforeRequestDeserialized(requestPayload);
// Invoke the core dispatching logic, which returns the serialized
// result.
//
String responsePayload = processCall(requestPayload);
// Let subclasses see the serialized response.
//
onAfterResponseSerialized(responsePayload);
// Write the response.
//
writeResponse(request, response, responsePayload);
}
GWT RPC and RequestBuilder serve different purposes. We cannot mix/match them.
GWT RPC - Services which fetch Data
GWT Request Builder - fire requests for static resources like js,css, json objects, querying soap services etc
The only feasible solution at the top of my mind for your approach of servicing requests is by using JSON - https://developers.google.com/web-toolkit/doc/latest/tutorial/JSON
You can keep your servlets code as is and then use RequestBuilder to query URL mapped to these servlets for JSON objects. Process the JSON objects using JSNI or Overlay concepts.
I'm trying to get the GWT Serialization & Deserialization source.Unfortunately, i have been stuck with other works and couldn't look on this right now. When i get the GWT Serialization Classes , i will update.
On client side I'm using Ajax.post (jquery 1.5) with json. On server side I'm using rest resteasy-jaxrs-2.0.1.GA. I found somewhere that i should add couple of headers to server response and I've done with following filter:
public void doFilter( ServletRequest req,
ServletResponse res,
FilterChain filterChain)
throws IOException, ServletException {
MyServletRequestWrapper httpReq = new MyServletRequestWrapper((HttpServletRequest)req);
HttpServletResponse httpRes = (HttpServletResponse)res;
HttpSession session = httpReq.getSession();
httpRes.addHeader(ACCESS_CONTROL_ALLOW_ORIGIN, "*");
httpRes.addHeader(ACCESS_CONTROL_ALLOW_CREDENTIALS, "true");
if (((HttpServletRequest) req).getMethod().equals("OPTIONS")){
httpRes.addHeader(ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, OPTIONS, PUT, DELETE");
httpRes.addHeader(ACCESS_CONTROL_ALLOW_HEADERS, "content-type, x-requested-with, x-requested-by");
}
filterChain.doFilter(httpReq, httpRes);
}
It works fine cause to every single GET response above headers are added. Problem appears when I want to use POST request. When I use Ajax.post, at first server gets OPTIONS request and I've got following error:
Failed executing OPTIONS [REST_PATH]
org.jboss.resteasy.spi.DefaultOptionsMethodException: No resource method found for options, return OK with Allow header
To solve above error I was trying to add method invoke with the same path as POST ([REST_PATH]) but with #OPTION annotation. In that case javac told me that symbol :class OPTIONS could not be found, even there is a OPTION.class in attached jaxrs library.
Any ideas to fix it? I would be very grateful for any clues.
This question is quite old, but as a reference for others with similar problems - just recently i came across a nice "CORS Filter" you may want to consider using. It's just a matter of adding the following lines to your web.xml and it works like a charm.
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<servlet-name>MyServletNameGoesHere</servlet-name>
</filter-mapping>
and the maven dependency:
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.5.1</version>
</dependency>
When I was trying to call my service with an Angular 2 client RestEasy was responding to the preflight requests with the HTTP status 500 and the following error.
RESTEASY003655: No resource method found for options, return OK with
Allow header
I tried RestEasy's CorsFilter but I'd like to propose a simple alternative. What if you don't want to write code handling the OPTIONS call for each of your endpoints ?
I implemented a simple filter that:
Applies the CORS header you need to the response.
Returns the HTTP status code 200 when calling an endpoint with the OPTIONS method. You tell the client that its CORS preflight requests were accepted.
Here is the code. Feel free to refine the filter if you only want to send back a 200 when querying a "real" endpoint.
#Provider
public class CorsFilter implements ContainerResponseFilter {
#Override
public void filter(ContainerRequestContext requestContext, ContainerResponseContext responseContext) throws IOException {
MultivaluedMap<String, Object> headers = responseContext.getHeaders();
headers.add("Access-Control-Allow-Origin", "*"); // If you want to be more restrictive it could be localhost:4200
headers.add("Access-Control-Allow-Methods", "GET, PUT, POST, OPTIONS"); // You can add HEAD, DELETE, TRACE, PATCH
headers.add("Access-Control-Allow-Headers", "Content-Type, Authorization, Accept, Accept-Language"); // You can add many more
if (requestContext.getMethod().equals("OPTIONS"))
responseContext.setStatus(200);
}}
Make sure to understand CORS too.
The CORS filter may be fine. I would like to point out as you wrote "To solve above error I was trying to add method invoke with the same path as POST ([REST_PATH]) but with #OPTION annotation. In that case javac told me that symbol :class OPTIONS could not be found, " that you had a typo there instead of #OPTIONS you wrote #OPTION without the S :)
There is a built in CORS filter in tomcat.
http://tomcat.apache.org/tomcat-7.0-doc/config/filter.html
<filter>
<filter-name>CorsFilter</filter-name>
<filter-class>org.apache.catalina.filters.CorsFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CorsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
I know this is not quite "restful" but, I want to learn if and how I can handle all requests which do not match any of the methods in my REST resource (I want to proxy these requests to another server). For example, it could be a method like:
#GET
#Path("*")
public Response defaultMethod(#Context HttpServletRequest request, #Context HttpServletResponse response)
{
// do proxying here
}
how can I achieve this?
BR,
SerkanC
#Path("/{default: .*}")
This works for:
http://example.com/someUnexpectedPath
http://example.com/someUnexpectedPath/withAdditionalSubPaths
http://example.com/someUnexpectedPath/withAdditionalSubPaths?andParams=whatever
One possible option would be to define a custom 404 mapping. Since 404s handles all unmatched requests it should catch all undefined urls.
I added the following this to my web.xml file
<error-page>
<error-code>404</error-code>
<location>/error/404</location>
</error-page>
Where location is the path you want to direct the request to. Then just define that the call as normal.