{"id":223,"date":"2012-10-04T18:58:08","date_gmt":"2012-10-04T21:58:08","guid":{"rendered":"https:\/\/www.erudio.com.br\/blog\/?p=223"},"modified":"2022-12-21T18:06:18","modified_gmt":"2022-12-21T21:06:18","slug":"manipulado-de-excecoes-no-javaserver-faces-jsf-2-x","status":"publish","type":"post","link":"https:\/\/www.erudio.com.br\/blog\/manipulado-de-excecoes-no-javaserver-faces-jsf-2-x\/","title":{"rendered":"Manipulando de Exce\u00e7\u00f5es no JavaServer Faces (JSF) 2.x"},"content":{"rendered":"<p>Uma das funcionalidades mais simples e legais introduzidas pela especifica\u00e7\u00e3o 2.0 do JSF \u00e9 a possibilidade de se criar um manipulador global de exce\u00e7\u00f5es. Trechos de c\u00f3digo como esse aqui abaixo tratando as exce\u00e7\u00f5es previstas uma a uma no web.xml se tornaram desnecess\u00e1rios.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;error-page&gt;\n  &lt;error-code&gt;404&lt;\/error-code&gt;\n  &lt;location&gt;\/404.xhtml&lt;\/location&gt;\n&lt;\/error-page&gt;\n<\/pre>\n<p>Ao inv\u00e9s da solu\u00e7\u00e3o acima, o JavaServer Faces nos permite implementar um manipulador global de exce\u00e7\u00f5es de forma relativamente simples para todas as exce\u00e7\u00f5es que podem ocorrer na aplica\u00e7\u00e3o. Para isso, voc\u00ea precisa apenas de criar duas classes que estendam as classes:<br \/>\n<strong>ExceptionHandlerWrapper<\/strong> \u2013 Que fornece uma implementa\u00e7\u00e3o simplificada da ExceptionHandler permitindo por exemplo que os desenvolvedores possam fornecer um comportamento especializado para uma inst\u00e2ncia ExceptionHandler.<br \/>\n<strong>ExceptionHandlerFactory<\/strong> \u2013 Essa classe por sua vez atua como uma Factory respons\u00e1vel por criar e retornar, quando necess\u00e1rio, uma nova inst\u00e2ncia de ExceptionHandler.<br \/>\nPor fim voc\u00ea precisa apenas algumas linhas ao arquivo &#8220;faces.config.xml&#8221; respons\u00e1veis por registrar a classe de tratamento no FacesServlet.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\n&lt;factory&gt;\n  &lt;exception-handler-factory&gt;\n     br.com.semeru.exceptions.CustomExceptionHandlerFactory\n  &lt;\/exception-handler-factory&gt;\n&lt;\/factory&gt;\n<\/pre>\n<p>No trecho de c\u00f3digo abaixo temos a classe &#8220;CustomExceptionHandlerFactory&#8221; que \u00e9 respons\u00e1vel por fabricar uma inst\u00e2ncia da classe &#8220;CustomExceptionHandler&#8221; que \u00e9 respons\u00e1vel por capturar e tratar a exce\u00e7\u00e3o.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.exceptions;\n\nimport javax.faces.context.ExceptionHandler;\nimport javax.faces.context.ExceptionHandlerFactory;\n\npublic class CustomExceptionHandlerFactory extends ExceptionHandlerFactory {\n    private ExceptionHandlerFactory parent;\n\n    public CustomExceptionHandlerFactory(ExceptionHandlerFactory parent) {\n        this.parent = parent;\n    }\n\n    @Override\n    public ExceptionHandler getExceptionHandler() {\n        ExceptionHandler handler = new CustomExceptionHandler(parent.getExceptionHandler());\n        return handler;\n    }\n\n}\n<\/pre>\n<p>J\u00e1 no trecho abaixo temos a classe &#8220;CustomExceptionHandler&#8221; que pode tratar a exce\u00e7\u00e3o da forma que voc\u00ea julgar mais apropriada. Voc\u00ea pode simplesmente imprimir a StackTrace e retornar uma p\u00e1gina de erros, ou tratar as exce\u00e7\u00f5es que mais ocorrem e retornar uma p\u00e1gina personalizada para cada uma delas. Outra coisa que pode ser interessante \u00e9 enviar a StackTrace via e-mail para a equipe de desenvolvimento.<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\npackage br.com.semeru.exceptions;\n\n\/\/import java.io.PrintWriter;\n\/\/import java.io.StringWriter;\nimport java.util.Iterator;\nimport java.util.Map;\nimport javax.faces.FacesException;\nimport javax.faces.application.FacesMessage;\nimport javax.faces.application.NavigationHandler;\nimport javax.faces.context.ExceptionHandler;\nimport javax.faces.context.ExceptionHandlerWrapper;\nimport javax.faces.context.FacesContext;\nimport javax.faces.event.ExceptionQueuedEvent;\nimport javax.faces.event.ExceptionQueuedEventContext;\n\n\/\/Inicialmente devemos implementar a classe CustomExceptionHandler que extende a classe ExceptionHandlerWrapper\npublic class CustomExceptionHandler extends ExceptionHandlerWrapper {\n\n    private ExceptionHandler wrapped;\n\n    \/\/Obt\u00e9m uma inst\u00e2ncia do FacesContext\n    final FacesContext facesContext = FacesContext.getCurrentInstance();\n\n    \/\/Obt\u00e9m um mapa do FacesContext\n    final Map requestMap = facesContext.getExternalContext().getRequestMap();\n\n    \/\/Obt\u00e9m o estado atual da navega\u00e7\u00e3o entre p\u00e1ginas do JSF\n    final NavigationHandler navigationHandler = facesContext.getApplication().getNavigationHandler();\n\n    \/\/Declara o construtor que recebe uma exceptio do tipo ExceptionHandler como par\u00e2metro\n    CustomExceptionHandler(ExceptionHandler exception) {\n        this.wrapped = exception;\n    }\n\n    \/\/Sobrescreve o m\u00e9todo ExceptionHandler que retorna a &quot;pilha&quot; de exce\u00e7\u00f5es\n    @Override\n    public ExceptionHandler getWrapped() {\n        return wrapped;\n    }\n\n    \/\/Sobrescreve o m\u00e9todo handle que \u00e9 respons\u00e1vel por manipular as exce\u00e7\u00f5es do JSF\n    @Override\n    public void handle() throws FacesException {\n\n        final Iterator iterator = getUnhandledExceptionQueuedEvents().iterator();\n        while (iterator.hasNext()) {\n            ExceptionQueuedEvent event = iterator.next();\n            ExceptionQueuedEventContext context = (ExceptionQueuedEventContext) event.getSource();\n\n            \/\/ Recupera a exce\u00e7\u00e3o do contexto\n            Throwable exception = context.getException();\n\n            \/\/ Aqui tentamos tratar a exe\u00e7\u00e3o\n            try {\n\n\/\/                \/\/ Aqui voc\u00ea poderia por exemploinstanciar as classes StringWriter e PrintWriter\n\/\/                StringWriter stringWriter = new StringWriter();\n\/\/                \/\/ PrintWriter printWriter = new PrintWriter(stringWriter);\n\/\/                \/\/ exception.printStackTrace(printWriter);\n\/\/                \/\/ Por fim voc\u00ea pode converter a pilha de exce\u00e7\u00f5es em uma String\n\/\/                String message = stringWriter.toString();\n\/\/\n\/\/                \/\/ Aqui voc\u00ea poderia enviar um email com a StackTrace\n\/\/                \/\/ em anexo para a equipe de desenvolvimento\n\/\/\n\/\/                \/\/ e depois imprimir a stacktrace no log\n\/\/                exception.printStackTrace();\n\n                \/\/ Coloca uma mensagem de exce\u00e7\u00e3o no mapa da request\n                requestMap.put(&quot;exceptionMessage&quot;, exception.getMessage());\n\n                \/\/ Avisa o usu\u00e1rio do erro\n                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage\n                    (FacesMessage.SEVERITY_ERROR, &quot;O sistema se recuperou de um erro inesperado.&quot;, &quot;&quot;));\n\n                \/\/ Tranquiliza o usu\u00e1rio para que ele continue usando o sistema\n                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage\n                    (FacesMessage.SEVERITY_INFO, &quot;Voc\u00ea pode continuar usando o sistema normalmente!&quot;, &quot;&quot;));\n\n                \/\/ Seta a navega\u00e7\u00e3o para uma p\u00e1gina padr\u00e3o.\n                navigationHandler.handleNavigation(facesContext, null, &quot;\/restrict\/home.faces&quot;);\n\n                \/\/ Renderiza a pagina de erro e exibe as mensagens\n                facesContext.renderResponse();\n            } finally {\n                \/\/ Remove a exe\u00e7\u00e3o da fila\n                iterator.remove();\n            }\n        }\n        \/\/ Manipula o erro\n        getWrapped().handle();\n    }\n}\n<\/pre>\n<p>No bloco try-finally voc\u00ea pode converter o Throwable em qualquer exce\u00e7\u00e3o espec\u00edfica e dar um tratamento especial a cada uma delas. Um simples problema de ViewExpiredException, por exemplo, pode ser redirecionado para uma p\u00e1gina informando que a &#8220;sess\u00e3o expirou&#8221; j\u00e1, no caso de uma exce\u00e7\u00e3o do tipo NullPointerException podemos usar uma p\u00e1gina padr\u00e3o apenas dizendo algo como &#8220;Ocorreu um erro inesperado, por favor, tente novamente mais tarde.&#8221;<br \/>\nUm detalhe muito importante a se lembrar \u00e9 que ao lidar com exce\u00e7\u00f5es em desenvolvimento web, voc\u00ea deve garantir que n\u00e3o est\u00e1 compartilhando informa\u00e7\u00f5es indesejadas e\/ou sens\u00edveis ao retornar o erro para a p\u00e1gina web.<\/p>\n<p>Bom \u00e9 isso e espero que gostem do post.<\/p>\n<p><strong>Editado para responder ao coment\u00e1rio do Andr\u00e9<\/strong><\/p>\n<p>Ol\u00e1 gravei uma v\u00eddeo aula explicando de forma clara como adotar o exception handler em um projeto JSF.<\/p>\n<figure class=\"wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio\">\n<div class=\"wp-block-embed__wrapper\"><iframe loading=\"lazy\" src=\"https:\/\/www.youtube.com\/embed\/fbcLOUJmS9k\" width=\"648\" height=\"365\" frameborder=\"0\" allowfullscreen=\"allowfullscreen\"><br \/>\n<\/iframe><\/div>\n<\/figure>\n<h2>Treinamentos relacionados com este post<\/h2>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_java\" target=\"_blank\" rel=\"noopener\"><\/p>\n<p><img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0  AWS com Spring Boot 3, Java e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/07-rest-spring-java.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_microservices_java\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microservices do 0 com Spring Cloud, Spring Boot e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/14-microservices-java.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_rest_spring_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"REST API's RESTFul do 0 \u00e0 AWS com Spring Boot 3, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/18-rest-spring-kotlin.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_ms_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Microsservi\u00e7os do 0 com Spring Cloud, Kotlin e Docker\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/22-ms-kotlin.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker do 0 \u00e0 Maestria: Cont\u00eaineres Desmistificados mais 3 B\u00d4NUS\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/09-docker.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_docker_para_aws\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Docker para Amazon AWS Implante Apps Java e .NET com Travis CI\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/10-docker-to-aws.png\"><br \/>\n<\/a><\/p>\n<p><a href=\"https:\/\/pub.erudio.com.br\/kr\/blog_kotlin\" target=\"_blank\" rel=\"noopener\"><br \/>\n        <img decoding=\"async\" style=\"max-width: 100%;\" title=\"Kotlin para DEVs Java: Aprenda a Linguagem Padr\u00e3o do Android\" src=\"https:\/\/raw.githubusercontent.com\/leandrocgsi\/blog-images\/main\/20-kotlin.png\"><br \/>\n<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Uma das funcionalidades mais simples e legais introduzidas pela especifica\u00e7\u00e3o 2.0 do JSF \u00e9 a possibilidade de se criar um manipulador global de exce\u00e7\u00f5es. Trechos de c\u00f3digo como esse aqui abaixo tratando as exce\u00e7\u00f5es previstas uma a uma no web.xml se tornaram desnecess\u00e1rios. Ao inv\u00e9s da solu\u00e7\u00e3o acima, o JavaServer Faces nos permite implementar um [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[44,45,49,82,119],"tags":[156,157,159,172,176,246],"_links":{"self":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/223"}],"collection":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/comments?post=223"}],"version-history":[{"count":2,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/223\/revisions"}],"predecessor-version":[{"id":1555,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/posts\/223\/revisions\/1555"}],"wp:attachment":[{"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/media?parent=223"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/categories?post=223"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.erudio.com.br\/blog\/wp-json\/wp\/v2\/tags?post=223"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}