Search code examples
javajspspring-mvchttp-status-code-400

SimpleMappingExceptionResolver only works on some Exceptions


Using Spring 2.5.6, I have SimpleMappingExceptionResolver configured thusly

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
    <property name="exceptionMappings">
        <props>
            <prop key="MismatchException">error/mismatch-error</prop>
            <prop key="Exception">error/${module.render.error.logical.page}</prop>
            <prop key="IllegalArgumentException">error/module-illegal-arg</prop>
            <prop key="MissingServletRequestParameterException">error/module-illegal-arg</prop>
        </props>
    </property>
</bean>

The idea is that for IllegalArgumentException and MissingServletRequestParameterException, I want a slightly different error screen and also the HTTP Status code of 400 returned.

The IllegalArgumentException works great, the referenced JSP properly sets the status to 400. The MissingServletRequestParameterException does not work, instead I am getting a generic 500 error.


Solution

  • After several hours, thinking that there might be bugs in error/module-illegal-arg.jsp or perhaps additional configuration was needed in web.xml, I jumped into the debugger and traced things down to the getDepth() method in SimpleMappingExceptionResolver.java.

    Basically, it was matching the Exception entry to a MissingServletRequestParameterException. While Exception is the super class, one would think that approach would prefer a direct match to one that is several levels deep. In fact, that is the whole purpose of getDepth(). On line 366 gives the final clue:

    if (exceptionClass.getName().indexOf(exceptionMapping) != -1) {
    

    So basically, Exception would match at a depth level of 0 any class with the work Exception in its name.

    So why did IllegalArgumentException work and MissingServletRequestParameterException did not? The underlying storage is a HashTable. IllegalArgumentException hashed to an earlier value than Exception. Exception hashed to an earlier value than MissingServletRequestParameterException.

    The final fix:

    <bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
        <property name="exceptionMappings">
            <props>
                <prop key="MismatchException">error/mismatch-error</prop>
                <!--
                  The full path is here in order to prevent matches on every class with the word
                   'Exception' in its class name.  The resolver will go up the class hierarchy and will
                   still match all derived classes from Exception.
                 -->
                <prop key="java.lang.Exception">error/${module.render.error.logical.page}</prop>
                <prop key="IllegalArgumentException">error/module-illegal-arg</prop>
                <prop key="MissingServletRequestParameterException">error/module-illegal-arg</prop>
            </props>
        </property>
    </bean>