Adding causes java.lang.IllegalStateException:

2018-12-31 14:52发布

问题:

I\'m facing the following exception in a very simple JSF 2 page after adding <h:form>:

java.lang.IllegalStateException: Cannot create a session after the response has been committed
    at org.apache.catalina.connector.Request.doGetSession(Request.java:2758)
    at org.apache.catalina.connector.Request.getSession(Request.java:2268)

I\'m using Mojarra 2.1.3 and PrimeFaces3.0M4, on Tomcat 7.0.22 and JDK 7.

The page is a very basic data table:

<html xmlns=\"http://www.w3.org/1999/xhtml\"
    xmlns:h=\"http://java.sun.com/jsf/html\"
    xmlns:f=\"http://java.sun.com/jsf/core\"
    xmlns:p=\"http://primefaces.org/ui\">
<h:head>

</h:head>
<h:body>
    <h:form>        
        <p:dataTable var=\"car\" value=\"#{tableBean.cars}\">

                 ......
        </p:dataTable>
    </h:form>
</h:body>
</html>

The page shows correctly on the browser, but on the console I see the exception. The Exception does disappear if I remove the <h:form>.

How is this caused and how can I solve it?

回答1:

This is a known problem and has been reported by yours truly as issue 2215. This will occur when the response buffer has overflowed (due to large content) and the response is been committed before the session is been created. This is result of bit overzealous attempts of Mojarra to postpone \"unnecessary\" session creation as much as possible (which is at its own a Good Thing though).

Until they get it fixed, there are several workarounds:

  1. Create a Filter which does HttpServletRequest#getSession() before FilterChain#doFilter(). Advantage: no need to change JSF configuration/code. Disadvantage: when you want to avoid unnecessary session creation yourself as well.

  2. Call ExternalContext#getSession() with true in bean\'s (post)constructor or preRenderView listener. Advantage: actually, nothing. Disadvantage: too hacky.

  3. Add a context parameter with name of com.sun.faces.writeStateAtFormEnd and value of false to web.xml. Advantage: unnecessary session creation will be really avoided as opposed to #1 and #2. Disadvantage: response will now be fully buffered in memory until </h:form> is reached. If your forms are not extremely large, the impact should however be minimal. It would however still fail if your <h:form> starts relatively late in the view. This may be combined with #4.

  4. Add a context parameter with name of javax.faces.FACELETS_BUFFER_SIZE and a value of the Facelets response buffer size in bytes (e.g. 65535 for 64KB) so that the entire HTML output or at least the <h:form> (see #3) fits in the response buffer. Advantage/disadvantage, see #3.

  5. Add a context parameter with name of javax.faces.STATE_SAVING_METHOD and value of client to web.xml. Advantage: session will not be created at all unless you have session scoped beans. It also immediately solves potential ViewExpiredException cases. Disadvantage: increased network bandwidth usage. If you\'re using partial state saving, then the impact should however be minimal.

As to why the problem disappears when you remove <h:form>, this is because no session needs to be created in order to store the view state.


Update: this has as per the duplicate issue 2277 been fixed since Mojarra 2.1.8. So, you can also just upgrade to at least that version.



回答2:

With the new version 2.1.21 released yesterday of javax.faces this problem seems to have disappeared. Declare the new version:

<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>javax.faces</artifactId>
    <version>2.1.21</version>
</dependency>

and replace the javax.faces.jar in the glassfish modules folder replacing the javax.faces.jar for the new version 2.1.21.



回答3:

In my case (myfaces-2.2.8 & Tomcat 8.0.23) the Problem was a typo in the welcome-file of web.xml. While debugging i saw, that Tomcat created as expected a 404, but somehow myfaces tried to access afterwards the Session, which caused then a java.lang.IllegalStateException: Cannot create a session after the response has been committed. Using a valid page in welcome-file of web.xml fixed the Problem for me.



回答4:

You may need to add an <f:view> and </f:view> before and after h:form elements, plus add the link to you html tag for jsf tags

<html xmlns:f=\"http://java.sun.com/jsf/core\">

for this to work.



回答5:

If you are using Spring MVC and call is made by Spring Forms then we should use GET method instead of POST(to fetch data) and there should be no input field we can use intead.