Weird Behavior When Dealing With POST Request Parameters - java

I'm working on a RESTful API, using Apache CXF as my JAX-RS implementation. I have a POST endpoint that's supposed to receive a request with three parameters. Here's a snippet of my code (modified and shortened):
#Path("endpoint_path")
public class MyResource {
#Context
private HttpServletRequest request;
#POST
#Produces(MediaType.TEXT_HTML)
#Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response postEndpoint(#QueryParam("param1") String param1,
#FormParam("param2") String param2,
#FormParam("param3") String param3) {
(use request as input for some library)
}
}
Inside that method, param2 and param3 both have the expected values, but if I check the request object's parameters (by using request.getParameterNames()), I only get one parameter -param1- instead of all three. I know for sure that I'm receiving all 3 parameters, param1 as a query parameter, and param2 and param3 as form parameters, because as I just said, I get their values passed as method parameters. They just don't seem to exists inside the request object.
This puzzled me so much, that I created a Filter that only does one thing, it peeks inside the request for the parameter names and does nothing else:
public class TestCXFPostParamsFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
servletRequest.getParameterNames();
filterChain.doFilter(servletRequest, servletResponse);
}
(init() and destroy() empty methods)
}
and in my web.xml file, I set the filter to apply to every request to my endpoint. Now here's where things get weird - for some reason, that makes everything work, by which I mean, if I check the request object back in the endpoint method, it'll contain all three expected parameters. What sorcery is this?
As a side note, some of you may be wondering why would I bother to check the request object, when I just said I have access to the parameter values that are passed to the method by CXF's servlet? The answer is that I'm using a library that expects you to pass the request object to it, instead of just the necessary values. So I really need the request to keep its parameters inside (like I always assumed it would).
Finally, I'm using Java 6, and CXF 2.7.10 (which comes with Apache Camel CXF 2.13.0). And yes, those are more or less set in stone for all intents and purposes, so if the reason all of this is happening is because of a bug in one of these pieces, I'm stuck with an useless filter as a "solution".

Related

Java Spring change the response before handle it

Ok, I have been trying to implement a system in which after check the parameters on the request, like the Path, i will actually modify the response to answer with different data. Idea is to create backend demo functionality, in this way client can Demo (NOT TEST) the application without actually making DB requests.
So, my first try was using servlet filters, a very good answer for this can be found here, and also some good document called The Essentials of Filters. But I could not make it work, i think because I'm using spring with #Controller and #ResponseBody, even I follow exactly same sample I would get a null as wrapperResponse.
Then I tried the Interceptors, here there is good example, and a good actually answer here. But the problem with this is that normally people will use the postHandle to modify the body, and I really do not want the handle to even trigger, because this means that the DB calls will be also triggered. And if I use the preHandler as here it will just make a new servlet, and I don't want that.
Finally I try #ControllerAdvice which basically allows you to re-write the body before is sent, but again, the handler gets processed and all DB calls with it.
MY goal, is that I do not have to put repeated code in each handler, I could make a preHandler insert some extra header and check that header in the #ControllerAdvice, but this means that i have to make some IF/ELSE in the handler so it doesn't get processed and I have to repeat that on the 100s of #Controllers that i have in the system, i want to be DRY.
I'm pretty sure the solution is on the filter in the way of this answer
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
System.out.println("BEFORE filter");
PrintWriter out = response.getWriter();
CharResponseWrapper responseWrapper = new CharResponseWrapper(
(HttpServletResponse) response);
chain.doFilter(request, responseWrapper);
String servletResponse = new String(responseWrapper.toString());
out.write(servletResponse + " filtered"); // Here you can change the response
System.out.println("AFTER filter, original response: "
+ servletResponse);
}
But I can't make it work with spring and #ResponseBody calls. And true be told, this doesn't answer my question.
This is the way I manage to do this.
First I created an interceptor, which actually filter the request to pass just the want we want to demo. In the pre handler instead of trying to create a response there using the Response outstream I just used the RequestDispatcher to forward the request to a new controller, which I called Demo controller.
#Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
Pattern pattern = Pattern.compile("someregex");
Matcher matcher = pattern.matcher(request.getPathInfo());
if (matcher.find())
{
if (matcher.group(0).equals("SOMETHING"))
{
HandlerMethod handlerMethod = ((HandlerMethod)handler);
request.setAttribute("methodName", handlerMethod.getBeanType().getSimpleName());
request.getRequestDispatcher("/demo").forward(request, response);
return false;
}
return true;
}
else
{
return true;
}
}
In the Demo controller then you can create a proper response you want to demo. The good thing here is that in the new demo forwarded request will have an attribute for the original request javax.servlet.forward.request_uri, and that you can insert data, as the controllerName on the request before forward. All this data can be extracted in the Demo controller in order to generate the required data.

Understanding request object in servlet-api. Is it a singleton?

I read the servlet-3.0 specification and have got one question about the ServletRequest object. Currenctly I have a filter chain
public class MyFilter implements Filter{
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
//do filter
}
}
after doing filters the javax.servlet.Servlet's
public void service(ServletRequest req, ServletResponse res)
throws ServletException, IOException;
comes into play. Is it reliable that both in the filter's method and the service method operate on the same object reference? The servlet specification said this:
Each request object is valid only within the scope of a servlet’s
service method, or within the scope of a filter ’s doFilter
method, unless the asynchronous processing is enabled for the
component and the startA sync method is invoked on the request object
But it;s not obvious to me that the ServletRequest object is a singleton per one request handling.
Upd: To be more specific, I need to return the HttpSession instance within Filter's doFilter method and Servlet's do_HttpMethod_ method. Is it always the same? I mean httpServletRequest.getSession()
A container uses a single request object for a given request. However any filter can wrapper the request object so your filter or servlet may be getting a wrapper depending on what other filters do. Usually as an app developer you would know if this is the case. If no wrappers are used the filter and servlets get the same request object.
For info on request wrappers see:
http://docs.oracle.com/javaee/7/api/javax/servlet/http/HttpServletRequestWrapper.html
So when you call getSession() you may get the container implementation of the method or that provided by a wrapper. However note that an HttpServletRequestWrapper object provides a getRequest() method which returns the request object it wraps so you can recurse through wrappers until you get the original and then call it. Lots of examples how to do this on the web.
ServletRequest is an interface and the same is used in doFilter method as well as service method. So both are going to return the same session object (if you call getSession()).
Servlet as well as Filter uses same interface so it's going to behave same way. I am not sure why you are curious to know if it's singleton ? May be you can check servlet specification to know more about it.

Returning JSON with spring on 404 in XML free project

I am currently setting up a Spring MVC application (version 4.1.4.RELEASE) and I want the application to return a JSON string on a 404 error rather than the default html response. I am using Tomcat 8 as my server. I have what I think should be correct, however it isn't behaving in the manner that I expect. What I'm trying to do is based off of this answer.
public class SpringWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer{
...
#Override
protected void customizeRegistration(ServletRegistration.Dynamic registration){
registration.setInitParameter("throwExceptionIfNoHandlerFound","true");
}
}
and then I have an exception controller (which is different than the question I based my solution off of, however I don't believe that is an issue as I am under the impression that #ControllerAdvice is an acceptable way to manage this based off of the Spring Docs. It looks something like:
#ControllerAdvice
public class GlobalExceptionController{
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(HttpRequestMethodNotSupportedException.class)
public Message handleMethodNotSupported(HttpServletRequest request){
...
}
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(NoSuchRequestHandlingMethodException.class)
public Message handleBadRequest(HttpServletRequest request){
...
}
#ResponseStatus(value=HttpStatus.NOT_FOUND)
#ExceptionHandler(NoHandlerFoundException.class)
public Message requestHandlingNoHandlerFound(HttpServletRequest request){
...
}
...
}
It continues to send back the default response. I know for a fact that it is hitting my customizeRegistration() function because breakpoints stop it, however, any breakpoints that I have in my GlobalException class are not hit. Also, the GlobalException class is within a package that is hit by a #ComponentScan() annotation, so I am fairly confident that it is also being handled by spring.
I assume I'm missing something obvious, any help would be greatly appreciated.
I don't think the return type you're trying to use is supported. Have you tried changing your return value to ResponseEntity or adding a #ResponseBody annotation?
From the docs:
A ModelAndView object (Servlet MVC or Portlet MVC).
A Model object, with the view name implicitly determined through a RequestToViewNameTranslator.
A Map object for exposing a model, with the view name implicitly determined through a RequestToViewNameTranslator.
A View object.
A String value which is interpreted as view name.
#ResponseBody annotated methods (Servlet-only) to set the response content. The return value will be converted to the response stream
using message converters.
An HttpEntity or ResponseEntity object (Servlet-only) to set response headers and content. The ResponseEntity body will be
converted and written to the response stream using message converters.
void if the method handles the response itself (by writing the response content directly, declaring an argument of type
ServletResponse / HttpServletResponse / RenderResponse for that
purpose) or if the view name is supposed to be implicitly determined
through a RequestToViewNameTranslator (not declaring a response
argument in the handler method signature; only applicable in a Servlet
environment).

How to implement state in command pattern

I am porting my Java servlet front controller from a large if-else if block to the command pattern and have created a command interface with an execute method. Currently, I am instantiating an instance of each command in the init() method of my servlet and storing them in a HashMap. I am wondering how I can run the necessary command.execute() within the context of a given request?
Do I add a setContext(HttpServletRequest request, HttpServletResponse response); method to the interface and call command.setContext(request, response) from my doGet()/doPost() methods before I execute or should I not be instantiating the commands in init() to begin with? instead, having a constructor that takes request and response as args?
Obviously, the aim of the command is to set various attributes for a given user/session and determine the correct JSP to forward to, which it can't really do without the context.
You should use:
command.execute(HttpServletRequest request, HttpServletResponse response);
All state can (and should) be recorded in the request. This is easy to do by storing attributes.
Sometimes you may need to use:
command.execute(this, HttpServletRequest request, HttpServletResponse response);
but probably only if your commands are enum rather than real objects.

How to find the URL of a RESTful API inside of said API

Say I have this endpoint:
#GET
#Path("/{product}")
#Produces(MediaType.APPLICATION_JSON)
public String getProduct(
#PathParam("product") final String product) {
return createSignature(<<PLACE COMPLETE URL HERE>>);
}
How can I know the complete URL that is being called from inside the endpoint in order to maybe create a signature based on that? Thanks
There are several ways.
Generally you can add special parameter to method or a field to your resource class. Special parameter is recognized by type (HttpServletRequest or UriInfo) and should be marked using annotaiton #Context.
#StormBringerX already mentioned that the information may be passed using method parameter (+1). I personally prefer to add this as a field of your class because I think this is clearer and allows creating methods that accept only application level parameters.
You can access the original request by adding #Context HttpServletRequest request as a parameter to your method. You can then access anything you want to do with the request.

Categories