I'm working on this Java Sprint 3.0 application where I'm passing data to a dataTable. Everything works fine, but every so often I see this error:
ERROR [[dispatcher]] Servlet.service() for servlet dispatcher threw exception
java.lang.IllegalStateException: getOutputStream() has already been called
for this response.
Here is my code:
#PreAuthorize("hasRole('ADMIN')")
#RequestMapping(value = "/dataTable", method = RequestMethod.GET)
public void serverSide(Model model, HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("application/json");
response.setHeader("Cache-Control", "no-store");
PrintWriter out = response.getWriter();
out.print(dataTableService.viewUsers(request));
}
I have tried adding the following:
out.flush();
out.close();
return;
I have also tried using response.getOutputStream().print(dataTableService.viewUsers(request)) and response.getWriter().append(dataTableService.viewUsers(request)) instead of using a PrintWriter but nothing seems to fix it.
EDIT:
Here is the stacktrace:
The basics are:
headers must be written first;
then the content must be written using either getOutputStream or getWriter.
What still can go wrong:
Basic errors like using both response.getOutputStream() and response.getWriter() - very unlikely here.
Control flow:
if (...) {
... redirect
// Missing return
}
... normal output
A filter or interceptor: ordinarily unlikely; though here are annotations.
out.flush(); // OKAY
// Probably NOT OKAY: out.close();
Servlet fields being used. The service methods should be stateless in themselves.
Related
public class myServlet extends httpservlet
{
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
{
PrintWriter out = response.getWriter();
out.println(--------"HTML CODE"------);
}
}
I'm new to servlets and web programming. While practicing, I'm stuck at some general doubt. What exactly does the PrintWriter() object do in a servlet? Just directing the HTML code to output stream?
In Java, to handle I/O operations, there are different I/O classes like Reader, Writer, InputStream, OutputStream classes etc. In Servlet, when you want to do output operation i.e., writing HTML content in web page, you need one of these classes. More info on these classes, you can get from this link.
So we create PrintWriter instance from the response and invoke its write() method to write simple HTML contents.
getWriter() method of HttpServletResponse returns a PrintWriter object which can be used to send text to client side, and yes it may be used to send html code to the client side.
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.
I have an ajax method on my servlet that could be running at the same time for the same user. Sorry if I use the wrong words to describe the problem but it's how I understand it so far (don't know much about threading).
Anyways here's the method
private void ajaxPartidas() throws ServletException, IOException {
//Variables necesarias
DataSource pool = (DataSource) session.get().getAttribute("pool");
Recibo registro = null;
int id = -1;
try{ id = Integer.parseInt(request.get().getParameter("id"));}catch(NumberFormatException e){}
if(id > 0){
registro = new Recibo(id);
if(!registro.obtener(pool))
registro = null;
registro.setPartidas(Partida.obtenerRegistros(pool, registro.getId()));
}
response.get().setContentType("application/json");
response.get().setHeader("Content-Type", "application/json; charset=utf-8");
response.get().getWriter().print((new Gson()).toJson(registro.getPartidas()));
}
This method is being called via ajax, it works fine the 1st time it gets called, but second time (on same id) and it returns a NullPointer on the getWriter() line. I've looked around and everyone seems to pinpoint the problem to threads. Now a little bit more of context would be that everytime the servlet enters in the
doPost(request, response)
I assign a threadlocal variable declared like so in the global vars
private static ThreadLocal<HttpServletResponse> response = new ThreadLocal<>();
and I assign it the response
Home.response.set(response);
in the doPost() method.
How would I go about making the getWriter() threadsafe?
Not sure why you're assigning the response to a class level ThreadLocal? Each new user generated request has a clean request and response object. getWriter and all methods on the servlet class are threadsafe as long as you follow the correct guidelines for using a Java Servlet. A general rule with Java Servlets is that as long as you don't use class level variables, you are thread-safe.
Instead of using a ThreadLocal, you need to pass the request and response objects as parameters to your ajaxPartidas method and then call it as you normally would. So your doPost method would look like this
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
ajaxPartidas(request, response);
}
The concurrency issues are already handled by the Servlet class itself, you just need to write the business logic. See this answer in a similar thread for more details on using a Java Servlet with Ajax: https://stackoverflow.com/a/4113258/772385
Tomcat creates a new Request and Response for EVERY user request. So they are already threadsafe (unless you go in and create a new Thread). Besides, make sure you are passing "id" and is getting set properly. I think it's the "registro" object on the same line as getWriter() that's causing the NullPointerException.
Using Spring MVC 3.1.x and spring-test-mvc, I was wondering if there is a way to mock the parameters of a function being mapped using #RequestMapping. Please see the code snippet below. I would like to know if I can use spring-test-mvc and mock out the response method below. I know that I can create an instance of the controller class, and then pass in mocked values of the request/response, but that doesn't test out the annotated portions of the code, which is why I would like to know if there is a way to do this using spring-test-mvc. If that is not possible, then is there another way that I can verify that the OutputStream is returning the correct results?
#RequestMapping(value="/", method = RequestMethod.GET)
public void getRequest(ServletRequest request, ServletResponse response){
try{
String destination = destinationRetrievalService.getDestination(request, response);
InputStream input = httpServletRequestDelegationService.delegateGet(request, destination, response);
response.setContentType("text/html");
response.setCharacterEncoding("UTF-8");
OutputStream output = response.getOutputStream();
IOUtils.copy(input, output);
}catch(IOException ioe){
LOG.error("An exception has been thrown while trying to copy the stream back to the page.", ioe);
}
}
Thanks in advance!
Juan
I want to write an HTML code inside Java, using a servlet. I read about the method doGet() and I wrote this simple example
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter( );
response.setContentType("text/html");
out.println("<H1>Hello from a Servlet</h2>");
But it doesn't give anything in the browser, can someone tell me what's wrong?
The standard PrintWriter which you get by calling response.getWriter(); doesn't automatically flush its buffers. It's a bug/feature.
Add out.flush() at the end of doGet().
Also note that PrintWriter.close() does not flush. It's a bug; PrintWriter/PrintStream are the only output classes which don't flush on close.
[EDIT] To make sure that no other problem confuses you, add a breakpoint in the method and run it in the debugger. You should also add the annotation #Override to make sure your method signature is correct.
It seems you don't actually override doGet. You missed the ServletException exception.