Jersey 2.x issue with MultivaluedMap - rest

I am using Jersey 2.3.1 on Glassfish 4.
My resource method is similar to the following:
#POST
#Consumes("application/x-www-form-urlencoded")
#Path("/update")
public Response update(MultivaluedMap<String, String> formParams){
//business logic
//return appropriate Response object
}
I always get formParams.size() as zero. Why the submitted form parameters are not available in the MultivaluedMap object?
The following warning message in the server log:
WARNING: A servlet request to the URI http://localhost:8080/myApp/resource/update contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.
(I tested before and after disabling all Servlet filters. I am not using any Jersey filters)

You get this message if request body with form data was already consumed by calling HttpServletResponse.getParameter(paramName). This can happen if any registered servlet filter called this method. Jersey ContainerRequestFilter cannot influence it. So I suggest to investigate the configuration of your deployment (web.xml). I have tested injecting Form entity with Jersey 2.5-SNAPSHOT and Glassfish 4 night build (glassfish-4.0.1-b04-12_04_2013) and it works.
If request body is already consumed you can still use form parameters but you cannot inject them as an entity (like in your code). If parameters are consumed, you can inject parameters using #FormParam JAX-RS annotation:
#POST
#Consumes("application/x-www-form-urlencoded")
public String postForm(#FormParam("paramKey") String paramValue) {
return paramValue;
}

Related

Jersey REST service #PathParam decoding

I am using Jersey 1.8 with Tomcat 6 to develop the RESTful server.
I have the following service to receive the HTTP request by GET with parameter Input String.
#GET
#Path("/searchTest/{inputString}")
#Produces(MediaType.APPLICATION_JSON)
#Override
public Response searchTest(#PathParam("inputString") String inputString) throws Exception {
// TODO Auto-generated method stub
System.out.println(inputString);
return Response.status(Status.OK).entity("OK").build();
}
However, if the request parameter included space like : http://localhost:8080/test/service/searchTest/231 2312
The value of the server received is 231%202312
Here mentioned that #PathParam will decode automatically because this not work for me.
Jax-rs automatic decode pathparam
Anyone can help?

Send message to a client when an HTTP method not supported

I've created a REST controller the can handle, as usual, GET, POST, PUT and DELETE HTTP requests using Spring MVC. The web server is Tomcat 8.
If a send request, for instance, with HEAD method, the response is an error page from Tomcat with message
HTTP Status 501 - Method LINK is not is not implemented by this servlet for this URI
I have such exception handler:
#ResponseBody
#ExceptionHandler(Throwable.class)
public ResponseEntity<?> exceptionHandler() {
Error error = createError("error_message.unforeseen_error");
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(error);
}
But it doesn't catch any error in this case.
Is there a way to send back a message wrapped in JSON object as a response instead of this Tomcat page?
The problem is that SpringMVC does not find any method for HEAD in your controller, so it does not use it and your #ExceptionHandler is not used. It would be used for exception arising inside the controller. Extract from Spring Frameword Reference : You use the #ExceptionHandler method annotation within a controller to specify which method is invoked when an exception of a specific type is thrown during the execution of controller methods (emphasis mine).
To process exception outside of any controller, you must register a HandlerExceptionResolver bean that will replace the DefaultHandlerExceptionResolver provided by default by Spring MVC. You could either directly put the Json String in the response and return null from resolve method (my prefered way), or put the elements in a model and use a view to format the Json.

Generating WADL request parameters for #InjectParam

I am using the #InjectParam to inject query parameters into a JAX-RS resource that contains #QueryParam annotated fields on a Jersey 1.12 implementation.
On the Resource:
#Path("query")
#GET
#Produces(MediaType.APPLICATION_XML)
public Query queryParam(#InjectParam Query query) {
return query;
}
And in the pojo that receives the injected parameters I have some JAXB and JAX-RS annotations.
#XmlRootElement
public class Query {
#QueryParam("value1")
String value1;
}
A simple test from a REST client:
http://localhost:8888/sandbox/query?value1=hello3
Produces the correct results:
<query>
<value1>hello3</value1>
</query>
That's great, but I also use the wadl-maven-plugin to generate a client which uses the WADL file to produce client code. The WADL file does not include the necessary request parameters that would be there if the #QueryParam annotation was included in the resource method parameters. Subsequently my client is produced to accept no parameters:
SandboxApi.sandbox().query().getAsQuery()
instead of accepting a populated generated client pojo.
Query queryClient = new Query();
queryClient.setValue1("hello3");
SandboxApi.sandbox().query().getAsQuery(queryClient);
Anyone know of a magic annotation I can put on the Jersey Resource that will produce a WADL with the right information so Wadl2Java could generate a client that will accept the POJO and subsequently send the appropriate fields as query parameters?
A response provided (via a private conversation) from some of the fine people working on Jersey:
#Path("query")
#GET
#Produces(MediaType.APPLICATION_XML)
public Query queryParam(#QueryParam("value1") String value1,
#InjectParam Query query) {
return query;
}
query param "value1" should appear in generated WADL.
In-built WADL generator does not contain support for these cases and I'm not sure whether it will be supported anytime soon.

Url as path parameter in restful api causes bad request

We are developing a restful api using jersey (1.9.1) and tomcat 5.5.
A given resource is identified with a urn and we would like to address a specific instance of that resource. In order to achieve this, we used the following code:
#Path("/XXXs")
public interface XXXResource {
#GET
#Path("{id}")
#Produces({ MediaType.APPLICATION_JSON })
XXXInfo getXXX(#PathParam("id") String id);
}
The idea is to address this resource using the following url:
http://localhost:8080/restapi/XXXs/http%3A%2F%2Fns.something.com%2FXXX%2F2
The decoded path param value should be:
http://ns.something.com/XXX/2
However, when I make the request using the encoded url I get a bad request message from tomcat. So my questions are:
Is it correct to use a Urn as a path parameter?
Why is tomcat considering this request as a bad request?
Just in case, I changed the signature of the method so that the parameter is taken from the query string and it worked fine, but I want the parameter to be part of the path.
Thanks.
Ok, I solved it by adding the following line in catalina.properties:
org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true

How to fix Jersey POST request parameters warning?

I'm building a very simple REST API using Jersey, and I've got a warning in my log files that I'm not sure about.
WARNING: A servlet POST request, to
the URI
http://myserver/mycontext/myapi/users/12345?action=delete,
contains form parameters in the
request body but the request body has
been consumed by the servlet or a
servlet filter accessing the request
parameters. Only resource methods
using #FormParam will work as
expected. Resource methods consuming
the request body by other means will
not work as expected.
My webapp only has the Jersey servlet defined, mapped to /myapi/*
How can I stop these warnings?
For me the warning was showing for POST application/x-www-form-urlencoded. And I am using Spring Boot which has an HiddenHttpMethodFilter that does a getParameter before anything else... So I ended up doing this nasty override:
#Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new HiddenHttpMethodFilter() {
#Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain filterChain) throws ServletException, IOException {
if ("POST".equals(request.getMethod())
&& request.getContentType().equals(MediaType.APPLICATION_FORM_URLENCODED_VALUE)) {
filterChain.doFilter(request, response);
} else {
super.doFilterInternal(request, response, filterChain);
}
}
};
}
This message is meant to warn developers about the fact that the request entity body has been consumed, thus any other attempts to read the message body will fail.
It is safe to ignore the message or filter it out from the logs:
java.util.logging.Logger jerseyLogger =
java.util.logging.Logger.getLogger(WebComponent.class.getName());
jerseyLogger.setFilter(new Filter() {
#Override
public boolean isLoggable(LogRecord record) {
boolean isLoggable = true;
if (record.getMessage().contains("Only resource methods using #FormParam")) {
isLoggable = false;
}
return isLoggable;
}
});
The following thread describes the warning you are receiving. It sounds as though you might have a filter defined in your web.xml that is processing the request before Jersey does.
Finally got rid of this by making sure I had Content-Type: application/json in my request headers (obviously, on the client side)
I just had my ajax-function in JQuery set to contentType: "application/x-www-form-urlencoded; charset=UTF-8" because with a prior solution (without Jersey) I had some encoding problems. When I removed that the message was gone and everything worked fine.
This warning is the only thing the WebComponent logs, so just turn logging up to ERROR level or turn off logging for this component in your logback.xml or wherever you have logging configured. You don't need to write a custom filter to ignore this specific message since there are no other messages logged from this component.
Source code snippet from org.glassfish.jersey.servlet.WebComponent version 2.14:
if(!form.asMap().isEmpty()) {
containerRequest.setProperty("jersey.config.server.representation.decoded.form", form);
if(LOGGER.isLoggable(Level.WARNING)) {
LOGGER.log(Level.WARNING, LocalizationMessages.FORM_PARAM_CONSUMED(containerRequest.getRequestUri()));
}
}
The localized message that is used for this warning message is:
form.param.consumed=A servlet request to the URI {0} contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.
Turn logging off for the WebComponent in your logback.xml like so:
<logger name="org.glassfish.jersey.servlet.WebComponent" level="OFF" additivity="false"/>
Right.
So I've been suffering this issue, and I've been trying to solve it on different ways, but I did't want to change my web.xml settings, just because if I was testing my application with Postman it worked perfect, but when it was being integrated with the webapp it fails with the mentioned issue (A servlet request to the URI {MY_URI} contains form parameters in the request body but the request body has been consumed by the servlet or a servlet filter accessing the request parameters. Only resource methods using #FormParam will work as expected. Resource methods consuming the request body by other means will not work as expected.)
So as #clijk mentioned, you only have to set your headers as:
"Content-Type":"application/json"
"charset":"UTF-8"
and voilá, the warning it's gone.
Thanks
In my case I've fixed this error when I've changed the Object Date to String in the method.
Error:
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
public List<MyObject> myMethod(#FormParam("StartDate") Date date) throws Exception {
Fixed
#POST
#Path("/myPath")
#Produces(MediaType.APPLICATION_JSON)
public List<MyObject> myMethod(#FormParam("StartDate") String date) throws Exception {
Put this to your resource signature. Or find this string in your project someone already use this if #PUT or #POST is used. This should help
import javax.ws.rs.Consumes;
#Consumes(MediaType.APPLICATION_JSON)