Programação Defensiva e o NullPointerException

segue tópico…

http://www.guj.com.br/posts/list/104378.java#563207

Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??
Estou fazendo um sistema Web (só jsp+servlet) que é baseado no padrão Command, de forma que qualquer ação requisitada através da View vai passar por um único servlet que, por fim, vai delegar o trabalho para um comando.
No meu caso, ao invés de encher de verificações de entradas nulas dentro dos comandos, eu poderia simplesmente fazer

try { comando.execute(request, response) } catch(NullPointerException e) { // Gerar saida amigavel sem quebrar o sistema }
Como a chamada de comando é genérica (toda ação vai sempre passar por aí), não precisaria tratar o NPE em nenhum outro lugar mais, e posso deixar todas as implementações dos comandos mais limpas, sem ter que ficar fazento if (x == null)… toda hora.

De qualquer forma eu ia ter que estar preparado para tratar entradas inválidas, já que não se pode esperar nada do usuário (em vez de usar a view o cara poderia entrar com qualquer coisa na URL do seu browser, por exemplo).

Essa não seria uma maneira muito simples e limpa de resolver o problema? O que acham?

Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.

[quote=Rubem Azenha]Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.[/quote]
Eu entendo…
Mas e se sempre que lá no código eu detecte uma variável null que não deveria ser null eu tenha o mesmo comportamento?
Como disse, num sistema web você pode esperar qualquer lenha do usuário (será que tem como e vale a pena bloquear entradas diretas na URL dos browsers?). De qualquer jeito eu ia ter que encher o sistema de verificação nula, e sempre reagir da mesma forma, enviando uma mensagem amigável de erro e redirecionando para algum lugar, a tela de login por exemplo…

Se tiver que ser assim, acho muito melhor centralizar a reação ao problema lá no catch… não?

[quote=Rubem Azenha]Você não resolve o problema dessa forma, você varre ele pra baixo do tapete.
NPE é um erro “anormal”, se seu código lança NPE é por que o seu código tem um bug. NPE = erro de programação.[/quote]

Desculpe mas ninguém varreu nada pra debaixo do tapete ele tratou o erro da forma correta, ou vc conhece outra maneira de tratar uma Excpetion sem try/cacth ???

E não venha me dizer q seu código não tem try/catch para as exceções lançadas pela API do java q vai ser dificil acreditar…

[quote=leandrocm86]
Eu entendo…
Mas e se sempre que lá no código eu detecte uma variável null que não deveria ser null eu tenha o mesmo comportamento?
Como disse, num sistema web você pode esperar qualquer lenha do usuário (será que tem como e vale a pena bloquear entradas diretas na URL dos browsers?). De qualquer jeito eu ia ter que encher o sistema de verificação nula, e sempre reagir da mesma forma, enviando uma mensagem amigável de erro e redirecionando para algum lugar, a tela de login por exemplo…

Se tiver que ser assim, acho muito melhor centralizar a reação ao problema lá no catch… não?[/quote]

[quote=Giulliano]
Desculpe mas ninguém varreu nada pra debaixo do tapete ele tratou o erro da forma correta, ou vc conhece outra maneira de tratar uma Excpetion sem try/cacth ???

E não venha me dizer q seu código não tem try/catch para as exceções lançadas pela API do java q vai ser dificil acreditar…[/quote]

Não é o caso de encher o sistema com if (obj != null). Se um objeto esta vindo nulo quando não deveria estar, tem mais é que estourar uma exception mesmo, pois é bug.

Novamente, NPE é erro de programação. Mesmo que a NPE ocorra por causa de uma entrada errada do usuário (afina, você tem que validar a entrada, certo?). Existem N erros de programação que podem ocorrer no seu sistema (ClassCastException, etc). Além disso, tem as exceptions que podem ser lançadas por algum erro do ambiente (banco fora do ar, problemas de rede, etc). Fazer um sistema tolerante a falhas não é só ficar colocando um monte de try…catch.

Excessões que representem erro de sistema e não de negócio normalmente não devem ser tratadas pela aplicação. Eu geralmente deixo elas estourarem no AS ou no servlet container. O AS o e servlet container se encarregarão de fazer o logging da excessão e redirecionar para uma página de erro se corretamente configurados.

Ok, Ok…

Minha próxima pergunta então acaba mudando um pouco o foco, talvez eu tenha que fazer lá na seção de desenvolvimento web:
Como validar entradas do usuário?
Vendo que o usuário se interage com o sistema via browser e pode fazê-lo diretamente via URL (dispensando a interface), como validar a entrada a cada requisição do usuário?

Me parece uma tarefa impossível, a menos que tenha algum jeito de eu bloquear entradas diretas na barra de endereço. Afinal, na minha interface tem como eu confiar.
Esse problema do NULL fica mais grave em sistema web porque toda requisição de ação pode estar acompanhada com uma lista distinta de parâmetros string. Cada ação, ao ser executada, teria que pegar os seus parâmetros e verificar se eles realmente vieram…

São casos excepcionais de erros mas, sendo possíveis, o sistema tem que estar preparado né…

Eu não sei como funciona com os Frameworks tipo JSF, struts etc…
Mas pelo menos num sistema JSP+Servlet como o meu, tudo é feito baseado em parâmetros String que são enviados através do objeto request.
De lá você pode esperar qualquer coisa…

Frameworks web em geral fornecem um esquema para você validar a request antes de chegar na action.

[quote=leandrocm86]Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??

[/quote]

Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )

[quote=sergiotaborda][quote=leandrocm86]Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??

[/quote]
Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )
[/quote]
-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???

[quote=Marcio Duran]
-Como eu posso obter um monitoramento de Exceções ? ; A ponto que eu possa detectar, que tal execption está refletindo um tratamento inválido em algum ponto do meu sistema ???[/quote]

Marcio, se sua aplicação estiver rodando dentro dum AS ou Servlet Container, deixe a excessão estourarno container, ele vai tratar de efetuar o logging e redirecionar para uma página de erro customizada (se você fizer a configuração de forma correta).

[quote=sergiotaborda][quote=leandrocm86]Vou questionar algo agora que, a meu ver, deixaria o programa robusto e seria de muito fácil implementação.
O que vocês acham de catar as NPEs??

[/quote]

Péssima ideia.
Isso viola várias boas práticas de tratamento de exceções. Para começar : Não pegue o que vc não consegue segurar.
Vc pega o nullpointer e dai ? vc não vai poder resolver. Isso é um erro porque o programador fez algo errado. É suposto a exceção aparecer e parar o sistema. (tal como NumberFormatException quando tenta converter “” para inteiro)

Não faça isto. Nunca faça de catch de NullPointerException. (aliás essa exceção deveria ser um Error, mas… )[/quote]
Mas nesse caso eu tenho que resolver sim, ué. Se eu pegá-la lá no servlet (que é a minha intenção), cabe ao servlet ir pra página adequada e exibir a mensagem de erro (de forma limpa).
Eu to vendo a coisa da seguinte forma:
Não tem como (sem usar os frameworks, como é meu caso), ficar validando entradas no servlet. Então eu tenho 2 opções: Ou encho cada código com um monte de verificação ou simplesmente trato lá em cima no servlet. O efeito final deve ser o mesmo: Ir para alguma página com uma mensagem de erro adequada.

Não tem jeito cara, tem que validar a entrada do usuário de alguma maneira.

Se você optar por não tratar a entrada do usuário e deixar rolar um monte de NPE (ou coisa pior) por causa disso, não precisa tratar no servlet, deixe que o container capture a excessão e ele redireciona para uma página de erro.

http://edocs.bea.com/wls/docs61/webapp/web_xml.html#1017571

Fica algo assim (no seu web.xml):

<error-page>
<exception-type>java.lang.Throwable</exception-type>
<location>paginaDeErro.jsp</location>
</error-page>

O container ainda fará o logging da exception.

Alias, acho que toda aplicação web deveria ter um tratamento assim, idependente de validar ou não a entrada do usuário.

Rubem, então acho que vou fazer isso mesmo. Deixar configurado pro tomcat.
Porque num dá pra ficar enchendo o código de verificação o tempo todo, e dá menos ainda pra implementar no braço a validação que os frameworks fazem…
Também não pode fazer aparecer uma tela toda obscura lá pro usuário quando ocorrer o erro né…

Então acho que rola isso mesmo: deixa os nullpointers (onde não deveriam ocorrer) por conta do tomcat e apresentar uma tela de erro adequada.

Leandro,

validar entradas seu programa tem que fazer, tipo onde deveria ser número você tem que verificar se a String representa um número, onde é data verificar se a String é uma data. Se não estiver válido, mostrar mensagens pro usuário corrigir, tipo: “Campo xyz deve ser número”, “Data inválida”, etc.

Mas erros inesperados de programação que não deveriam acontecer, como NullPointerException, você deixa dar Exception e configura seu servidor para mostrar uma tela mais geral do tipo: “Desculpe-nos o transtorno, ocorreu um erro inesperado. Por favor entrar em contato.”. Seu usuário não precisa ver aquelas telas feias cheias de mensagens do Java com stackTraces. Daí seria interessante ter arquivos de log com os stackTraces dos erros para que você possa ver e corrigir.

[quote=leandrocm86]Rubem, então acho que vou fazer isso mesmo. Deixar configurado pro tomcat.
Também não pode fazer aparecer uma tela toda obscura lá pro usuário quando ocorrer o erro né…
Então acho que rola isso mesmo: deixa os nullpointers (onde não deveriam ocorrer) por conta do tomcat e apresentar uma tela de erro adequada.[/quote]

Legal :slight_smile:

Algum motivo especial para não utilizar nenhum framework web? Ou integrar algum framework de validação ao seu projeto?

Renato, é exatamente o que farei.
Esse tipo de verificação que você falou (campos de um formulário, por exemplo) eu vou fazer sim.

O que eu tava com medo é que não é IMPOSSÍVEL alguns parâmetros chegarem com problemas. Se o cara ignorar a interface e acessar alguma funcionalidade via URL direta, por exemplo, Deus sabe o que poderia chegar ou não chegar para o servlet. Mas é um caso extramamente excepcional, como vários outros que podem ocorrer.

Mas só agora, com a ajuda de vocês, eu me atentei para essa coisa: Não é necessário fazer um sistema 100% à prova de qualquer falha. Os casos muito excepcionais eu posso deixar o tomcat tratar exibindo uma mensagem de erro adequada. Eu não sabia que dá pra fazer isso.

O importante, como você disse, é não jogar uma tela imunda na cara do usuário quando o erro ocorrer.

Rubem, esse é um projeto relativamente simples. É o primeiro sistema web que to fazendo, pra trabalho de faculdade. Eu poderia estar usando frameworks, mas minha maior intenção aqui era aprender mesmo como as coisas funcionam (começar do zero). Como nunca tinha feito um sistema web antes, achei que seria interessante começar fazendo algo mais puro, sem frameworks ainda, até porque eu poderia me enrolar se não fosse assim…

Como efeito disso, muitas coisas já me aconteceram durante o desenvolvimento que já me adiantaram o valor necessário que devemos dar aos frameworks :-p

[quote=leandrocm86]
Como efeito disso, muitas coisas já me aconteceram durante o desenvolvimento que já me adiantaram o valor necessário que devemos dar aos frameworks :-p[/quote]

You’ve taken your first step into a larger world. :slight_smile: