protected String handleClientError(HttpServletRequest request, HttpServletResponse response, RequestClientErrorException cause)
            throws IOException {
        final boolean beforeHandlingCommitted = response.isCommitted(); // basically false
        processClientErrorCallback(request, response, cause);
        final String title;
        if (response.isCommitted()) {
            title = response.getStatus() + " (thrown as " + cause.getTitle() + ")";
            if (beforeHandlingCommitted) { // basically no way but just in case
                showCliEx(cause, () -> {
                    final StringBuilder sb = new StringBuilder();
                    sb.append("*Cannot send error as '").append(title).append("' because of already committed:");
                    sb.append(" path=").append(request.getRequestURI());
                    return sb.toString();
                });
                return title; // cannot help it
            }
            // committed in callback process
        } else {
            title = cause.getTitle();
        }
        showCliEx(cause, () -> {
            final StringBuilder sb = new StringBuilder();
            sb.append(LF).append("_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/");
            sb.append(LF).append("...Sending error as '").append(title).append("' manually");
            sb.append(" #").append(Integer.toHexString(cause.hashCode()));
            sb.append(LF).append(" Request: ").append(request.getRequestURI());
            final String queryString = request.getQueryString();
            if (queryString != null && !queryString.isEmpty()) {
                sb.append("?").append(queryString);
            }
            sb.append(LF);
            buildRequestHeaders(sb, request);
            buildRequestAttributes(sb, request, /*showErrorFlush*/true);
            buildSessionAttributes(sb, request, /*showErrorFlush*/true);
            sb.append(" Exception: ").append(cause.getClass().getName());
            sb.append(LF).append(" Message: ");
            final String causeMsg = cause.getMessage();
            if (causeMsg != null && causeMsg.contains(LF)) {
                sb.append(LF).append("/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -");
                sb.append(LF).append(causeMsg);
                sb.append(LF).append("- - - - - - - - - -/");
            } else {
                sb.append(causeMsg);
            }
            sb.append(LF).append(" Stack Traces:");
            buildClientErrorStackTrace(cause, sb, 0);
            sb.append(LF);
            sb.append("_/_/_/_/_/_/_/_/_/_/");
            return sb.toString();
        });
        try {
            if (!response.isCommitted()) { // because may be committed in callback process
                response.sendError(cause.getErrorStatus());
            }
            return title;
        } catch (IOException sendEx) {
            final String msg = "Failed to send error as '" + title + "': " + sendEx.getMessage();
            if (errorLogging) {
                logger.error(msg);
            } else {
                showCliEx(cause, () -> msg);
            }
            return title; // cannot help it
        }
    }
protected String handleClientError ( HttpServletRequest request , HttpServletResponse response , RequestClientErrorException cause ) throws IOException { final boolean beforeHandlingCommitted = response . isCommitted ( ) ; processClientErrorCallback ( request , response , cause ) ; final String title ; if ( response . isCommitted ( ) ) { title = response . getStatus ( ) + " (thrown as " + cause . getTitle ( ) + ")" ; if ( beforeHandlingCommitted ) { showCliEx ( cause , ( ) -> { final StringBuilder sb = new StringBuilder ( ) ; sb . append ( "*Cannot send error as '" ) . append ( title ) . append ( "' because of already committed:" ) ; sb . append ( " path=" ) . append ( request . getRequestURI ( ) ) ; return sb . toString ( ) ; } ) ; return title ; } } else { title = cause . getTitle ( ) ; } showCliEx ( cause , ( ) -> { final StringBuilder sb = new StringBuilder ( ) ; sb . append ( LF ) . append ( "_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/_/" ) ; sb . append ( LF ) . append ( "...Sending error as '" ) . append ( title ) . append ( "' manually" ) ; sb . append ( " #" ) . append ( Integer . toHexString ( cause . hashCode ( ) ) ) ; sb . append ( LF ) . append ( " Request: " ) . append ( request . getRequestURI ( ) ) ; final String queryString = request . getQueryString ( ) ; if ( queryString != null && ! queryString . isEmpty ( ) ) { sb . append ( "?" ) . append ( queryString ) ; } sb . append ( LF ) ; buildRequestHeaders ( sb , request ) ; buildRequestAttributes ( sb , request , true ) ; buildSessionAttributes ( sb , request , true ) ; sb . append ( " Exception: " ) . append ( cause . getClass ( ) . getName ( ) ) ; sb . append ( LF ) . append ( " Message: " ) ; final String causeMsg = cause . getMessage ( ) ; if ( causeMsg != null && causeMsg . contains ( LF ) ) { sb . append ( LF ) . append ( "/- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -" ) ; sb . append ( LF ) . append ( causeMsg ) ; sb . append ( LF ) . append ( "- - - - - - - - - -/" ) ; } else { sb . append ( causeMsg ) ; } sb . append ( LF ) . append ( " Stack Traces:" ) ; buildClientErrorStackTrace ( cause , sb , 0 ) ; sb . append ( LF ) ; sb . append ( "_/_/_/_/_/_/_/_/_/_/" ) ; return sb . toString ( ) ; } ) ; try { if ( ! response . isCommitted ( ) ) { response . sendError ( cause . getErrorStatus ( ) ) ; } return title ; } catch ( IOException sendEx ) { final String msg = "Failed to send error as '" + title + "': " + sendEx . getMessage ( ) ; if ( errorLogging ) { logger . error ( msg ) ; } else { showCliEx ( cause , ( ) -> msg ) ; } return title ; } }
=====================