/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * NullObjectAspect is an aspect that intercepts null pointer assignments and * replaces them with a Null Object. * * Copyright (C) 2003 R. Dale Asberry * All rights reserved. This program and the accompanying materials * are made available under the terms of the Common Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/cpl-v10.html * * Contributors: * R. Dale Asberry - initial implementation * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ package test; import java.lang.reflect.Proxy; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; import org.aspectj.lang.reflect.SourceLocation; import org.aspectj.lang.reflect.FieldSignature; import org.aspectj.lang.reflect.MethodSignature; import org.aspectj.lang.Signature; public aspect NullObjectAspect { private Map cNullObjectMap = new HashMap(); pointcut callsThatReturnAnObject(Object pCalledObject): call(* *.*(..)) && target(pCalledObject) && !within(test.NullObjectAspect) && !within(test.NullProxy); pointcut nullMemberAssignments(Object pSetValue): set(* *.*) && args(pSetValue) && !within(test.NullObjectAspect) && !within(test.NullProxy); Object around(Object pCalledObject): callsThatReturnAnObject(pCalledObject) { Object lRetVal = null; MethodSignature lErrorMethod = (MethodSignature)thisJoinPoint.getSignature(); SourceLocation lErrorLocation = thisJoinPoint.getSourceLocation(); // System.out.println(thisJoinPoint + " " + lErrorLocation.getFileName() + ":" + lErrorLocation.getLine()); if(cNullObjectMap.containsKey(pCalledObject)) { System.out.println("%%%%%%%%%%%%%%%%%%\n" + cNullObjectMap.size() + "\n%%%%%%%%%%%%%%%%%%"); NullPointerException lNpe = new NullPointerException(); StackTraceElement [] lStackTrace = lNpe.getStackTrace(); ArrayList lNewStackTraceElements = new ArrayList(); for(int i = 0; i < lStackTrace.length; i++) { //Filter out confusing aspect-related stack trace elements if(!(lStackTrace[i].toString().indexOf("_aroundBody") > -1)) { lNewStackTraceElements.add(lStackTrace[i]); } } StackTraceElement [] lNewStackTrace = new StackTraceElement [lNewStackTraceElements.size()]; for(int i = 0; i < lNewStackTraceElements.size(); i++) { lNewStackTrace[i] = (StackTraceElement)lNewStackTraceElements.get(i); } lNpe.setStackTrace(lNewStackTrace); lNpe.initCause((NullPointerException)cNullObjectMap.get(pCalledObject)); cNullObjectMap.remove(pCalledObject); throw lNpe; } lRetVal = proceed(pCalledObject); if(lRetVal == null) { NullPointerException lE = new NullPointerException(); lE = buildNullException(lErrorLocation, (Signature)lErrorMethod, lE, "Null return value from "); if(lErrorMethod.getReturnType().isInterface()) { lRetVal = buildNullProxy(lErrorLocation, lErrorMethod.getReturnType(), lE); } else { try { lRetVal = lErrorMethod.getReturnType().newInstance(); } catch(Exception e) {} if(lRetVal != null) { // System.out.println(cNullObjectMap + " " + lRetVal + " " + lE); cNullObjectMap.put(lRetVal, lE); } } } return lRetVal; } Object around(Object pSetValue): nullMemberAssignments(pSetValue) { Object lRetVal = pSetValue; SourceLocation lErrorLocation = thisJoinPoint.getSourceLocation(); FieldSignature lErrorField = (FieldSignature)thisJoinPoint.getSignature(); if(pSetValue == null) { NullPointerException lE = new NullPointerException(); lE = buildNullException(lErrorLocation, (Signature)lErrorField, lE, "Null value assigned to field "); if(lErrorField.getFieldType().isInterface()) { lRetVal = buildNullProxy(lErrorLocation, lErrorField.getFieldType(), lE); } else { try { lRetVal = lErrorField.getFieldType().newInstance(); } catch(Exception e) {} } if(lRetVal != null) { cNullObjectMap.put(lRetVal, lE); } } return proceed(lRetVal); } private NullPointerException buildNullException(SourceLocation pErrorLocation, Signature pErrorSignature, RuntimeException pRe, String pMessage) { StackTraceElement [] lStackTrace = pRe.getStackTrace(); NullPointerException lNpe = new NullPointerException( pMessage + pErrorLocation.getWithinType().getName() + "." + pErrorSignature.getName() + "(" + pErrorLocation.getFileName() + ":" + pErrorLocation.getLine() + ")"); ArrayList lNewStackTraceElements = new ArrayList(); for(int i = 0; i < lStackTrace.length; i++) { //Filter out confusing aspect-related stack trace elements if(!(lStackTrace[i].toString().indexOf("_aroundBody") > -1)) { lNewStackTraceElements.add(lStackTrace[i]); } } StackTraceElement [] lNewStackTrace = new StackTraceElement [lNewStackTraceElements.size()]; for(int i = 0; i < lNewStackTraceElements.size(); i++) { lNewStackTrace[i] = (StackTraceElement)lNewStackTraceElements.get(i); } lNpe.setStackTrace(lNewStackTrace); return lNpe; } private Object buildNullProxy(SourceLocation pErrorLocation, Class pErrorType, NullPointerException pNpe) { NullProxy lNullProxy = new NullProxy(pErrorType.getName(), pNpe); return Proxy.newProxyInstance(pErrorType.getClassLoader(), new Class[] {pErrorType}, lNullProxy); } }