Solução -> Encapsulamento + NullPointerException

11 respostas
Giulliano

Resolvi dar um jeito no famoso NullPointerException, não em todo contexto de uma aplicação, mas especificamente em nossos beans (Classes com métodos GET e SET, padrão de nomenclatura javabean).
Através de AOP todo método getXXX que retornar um objeto com referência nula receberá uma nova instância do seu tipo de retorno.

PRÓS: Evita NullPointerExceptions e gera uma saída no console para que o programador esteja ciente que foi evitado uma exceção desse tipo ao invés de parar a aplicação e jogar uma pilha de erros pro JVM.

CONTRA: Pode gerar confusão na cabeça do programador, quando valores de saída forem diferentes daquilo que ele esperava.

Agora espero as críticas…rss…

[]'s

Fontes aspectJ

pointcut gettingValues(): execution(public * *.get*());
	
	before():gettingValues(){
		
		assinatura = thisJoinPoint.getSignature();
		metodoGet = assinatura.getName();
		tipoRetorno = assinatura.toLongString().split(" ")[1];
		metodoSet = assinatura.getName().replace("get", "set");
		
		nomeClasse = assinatura.toLongString().split(" ")[2];
		Integer divisor = nomeClasse.lastIndexOf('.');
		nomeClasse = nomeClasse.substring(0, divisor);
				
		isNull = MorroniReflection.isNull(nomeClasse, metodoGet);
		if(isNull){
			System.out.println("####################### AspectJ (Inicio) #####################");
			System.out.println("Evitando NullPointerException ");
			System.out.print(" Classe: "+this.nomeClasse);
			System.out.print(" Atributo: "+this.metodoGet.replace("get", "").toLowerCase() +"\n");
			System.out.println("####################### AspectJ (Fim) ########################");
			MorroniReflection.defaultValue(thisJoinPoint.getTarget(), metodoSet,tipoRetorno);
		}

	}

Fontes Reflection

public class MorroniReflection {

	@SuppressWarnings("unchecked")
	private static Class<?> classe = null;
	private static Method metodo = null; 
	private static Object clazz = null;
	
	/**
	 * Valida se um atributo possui referência nula
	 * dado o nome da classe (incluindo o pacote) e o 
	 * nome do método get (padrão javaBeans) do atributo que será 
	 * validado. 
	 * <br />  
	 * Exemplo sobre os parâmetros: 
	 * <br />
	 * String className  = "com.morroni.javabean.JavaBean";
	 * <br />
	 * String methodName = "getDescription";
	 * 
	 * @param String className
	 * @param String methodName
	 * @return Boolean
	 */
	public static Boolean isNull(String className, String methodName) {
		if(classe == null || clazz == null || metodo ==null){
			try {
				clazz = Class.forName(className).newInstance();
				classe = Class.forName(className);
				metodo = classe.getMethod(methodName);
				if(metodo.invoke(clazz) == null){
					limpaAtributos();
					return true;	
				}else{
					limpaAtributos();
					return false;
				}
			} catch (Exception e) {
				e.printStackTrace();
				limpaAtributos();
				return false;
			}
		}else{
			limpaAtributos();
			return false;
		}
	}
	
	/**
	 * Define uma nova referência para o atributo recebido, dado
	 * o objeto em questão, o nome do método get (Padrão JavaBeans) do atributo e 
	 * o tipo de retorno desse atributo.
	 * 
	 * @param obj
	 * @param methodName
	 * @param tipoRetorno
	 */
	public static void defaultValue(Object obj, String methodName,String tipoRetorno) {
		Method method = null;
		Class&lt;?&gt; classeTipoRetorno = null;
		try {
			classeTipoRetorno = Class.forName(tipoRetorno);
			method = obj.getClass().getDeclaredMethod(methodName, classeTipoRetorno);
			
			if(tipoRetorno.contains("Long")){
				method.invoke(obj,new Long(0));
			}else if(tipoRetorno.contains("Double")){
				method.invoke(obj,new Double(0));
			}else if(tipoRetorno.contains("Integer")){
				method.invoke(obj,new Integer(0));
			}else if(tipoRetorno.contains("Character")){
				method.invoke(obj,new Character('0'));
			}else{
				method.invoke(obj,classeTipoRetorno.newInstance());	
			}
	
		} catch (Exception e) {
			e.printStackTrace();
		}
		
	}

	/**
	 * Limpa os atributos do objeto do objeto em questão. 
	 * Os atributos são do tipo static e por isso precisam
	 * que seu valor seja reiniciado manualmente. 
	 */
	private static void limpaAtributos(){
		classe = null; 
		clazz  = null;
		metodo = null;
	}
	
}

11 Respostas

wariows

A Pergunta principal é: Será que devemos lutar conta o null?

Eu acho que ao invés de se preocupar com os nulls, você deve se preocupar em garantir uma pós-condição especificada por você quando a pré-condição é garantida. Ao invés de lutar contra o null, lutar contra valores fora do que você considera válido. Estes parâmetros válidos são contratos.

Design By Contract by Wikipedia

[]´s

Giulliano

Concordo com vc q a luta contra o null ao mesmo tempo desobedece o trato de pós-condição, porém precisamos ver o que é mais importante dentro do escopo do sistema. Eu prefiro q meus clientes vejam valores errados e me alertem sobre isso do que ver uma bela exceção de NullPointerException (considerando que muitas sistemas não tratam as exceções e nem criam página de erros)

wariows

Valores errados podem passar desapercebido, exceções não. Isso é fato.

Se o sistema não trata das exceções com páginas de erros e mensagens úteis para o usuário, é bom implementar isso ao invés de mascarar os erros. Pelo menos é o que eu acho.

[]'s

Giulliano

Respeito sua opnião cara…mas como vc disse no final da sua frase…é o que vc acha…

Eu acho melhor que a plicação continue rodando sem desvios. E valores não podem passar desapercebidos se a pessoa esiver atenta ao que esta fazendo… Mas aí tb já entra em opniões pessoais…

wariows

Giulliano:
Respeito sua opnião cara…mas como vc disse no final da sua frase…é o que vc acha…

Eu acho melhor que a plicação continue rodando sem desvios. E valores não podem passar desapercebidos se a pessoa esiver atenta ao que esta fazendo… Mas aí tb já entra em opniões pessoais…

Tipo… Se eu tenho um valor no meu banco de dados que é not null. Daí numa transação qualquer, esse null é evitado (com essa sua solução) e é colocado um branco no lugar… Imagine que esse campo é de extrema importância para a minha aplicação, e sem ele provavelmente nada funcionará.

Se veio null, algum problema aconteceu, e a transação deve ser cancelada e deve acontecer um rollback. Se vier branco, a transação vai continuar normalmente e vai ser dado o commit. Você não acha que tem alguma coisa estranha aí?

Giulliano

Então mas aí você iria perceber isso né ??? afinal é uma informação de extrema importância.

Nesse caso eu acho q poderia ser gerada uma mensagem para o usuário (supondo q vc use JSF) alertando- que foi inserido um valor me branco ou um avloar igual a zero pois o campo tal não foi preenchido. A idéia warriors não é ficar preenchendo campo nulo, mas sim evitar que a aplicação desvie do seu fluxo.

Realmente tem muitos prós e muitos contras. Eu ouvi dizer que no Java 7 eles vão dar um jeito no NullPointerException, mas não li nada sério ainda foram apenas especulações por enquanto.

S

Eu realmente não entendo qual o grande problema do NullPointerException.

Como o wariows falou, você deve esconder uma null pointer do usuário, mas não do desenvolvedor. Vendo o erro sabemos o que tá errado.

Muitas vezes os erros mais difíceis de encontrar são os erros idiotas, tipo um campo com um valor que não foi atribuído.
Uma vez dei manutenção no código em ASP/VB que era uma loucura, milhares de linhas, código espaguete, e lá no meio, bem escondidinho num arquivo asp tínhamos uma bela linha: “On Error Resume Next”. beleza, escondeu o erro do usuário, mas de nós também.

Giulliano

Ssalgado:
Eu realmente não entendo qual o grande problema do NullPointerException.

Como o wariows falou, você deve esconder uma null pointer do usuário, mas não do desenvolvedor. Vendo o erro sabemos o que tá errado.

Muitas vezes os erros mais difíceis de encontrar são os erros idiotas, tipo um campo com um valor que não foi atribuído.
Uma vez dei manutenção no código em ASP/VB que era uma loucura, milhares de linhas, código espaguete, e lá no meio, bem escondidinho num arquivo asp tínhamos uma bela linha: “On Error Resume Next”. beleza, escondeu o erro do usuário, mas de nós também.

Verdade hein…esconder o erro é coisa de noob…por isso eu disse q gero uma saída no console e se prefirir até na interface da aplicação :slight_smile:

wariows

Giulliano:
Ssalgado:
Eu realmente não entendo qual o grande problema do NullPointerException.

Como o wariows falou, você deve esconder uma null pointer do usuário, mas não do desenvolvedor. Vendo o erro sabemos o que tá errado.

Muitas vezes os erros mais difíceis de encontrar são os erros idiotas, tipo um campo com um valor que não foi atribuído.
Uma vez dei manutenção no código em ASP/VB que era uma loucura, milhares de linhas, código espaguete, e lá no meio, bem escondidinho num arquivo asp tínhamos uma bela linha: “On Error Resume Next”. beleza, escondeu o erro do usuário, mas de nós também.

Verdade hein…esconder o erro é coisa de noob…por isso eu disse q gero uma saída no console e se prefirir até na interface da aplicação :)

Fazer o mesmo sem mascarar a NullPointerException seria o ideal.

peerless

Qual a diferença disso para uma NPE ? Continua sendo um erro do programador, certo? :slight_smile:

Giulliano

Continua sendo erro do progrmador…mas a questão discutida não é essa. E sim uma maneira de se trabalhar isso.

Criado 25 de setembro de 2008
Ultima resposta 26 de set. de 2008
Respostas 11
Participantes 4