Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Creating a crosscut using ClassLoader.Loadclass using AspectJ

And if you really wanted to go down the class loader route ...

========================================================
// your own class loader to load you application classes
import java.net.*;
public class ExtClassLoader extends URLClassLoader{
    public ExtClassLoader(URL[] urls) throws MalformedURLException{
		super(urls);
    }

    public Class loadClass(String name)
      throws ClassNotFoundException {
        return super.loadClass(name);
    }
};

========================================================
// a starting point to invoke your application - you need this because
.. right at the bottom
import java.net.*;
import java.io.*;
import java.lang.reflect.*;
public class Invoker
{
  public static void main(String[] args) throws MalformedURLException {
    URL[] classpathURLs = getClasspathURLs();
    ClassLoader loader = new ExtClassLoader(classpathURLs);
    try {
        Class mainClass = loader.loadClass(args[0]);
        Method main = mainClass.getMethod("main", new Class[] {
            String[].class
        });
        int modifiers = main.getModifiers();
        if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)) {
            main.invoke(null, new Object[] {
                new String[] {}
            });
        } else {
            throw new NoSuchMethodException();
        }
    } catch (Exception e) {
        System.err.println("Error running class " + args[0]);
  }
  ClassLoaderCapture.aspectOf().report();
}
	private static URL[] getClasspathURLs() throws MalformedURLException{
		String extcp = System.getProperty("extcp");
		if(extcp != null) {
			String[] cps = extcp.split(";");			
			URL[] urls = new URL[cps.length];
			for(int i = 0; i < cps.length; i++){
				urls[i] = new File(cps[i]).toURL();
			}
			return urls;
		}
		return null;
	}
}

========================================================
// an aspect that captures class loading and does the reporting in the end
import java.util.*;
import java.lang.reflect.*;
public aspect ClassLoaderCapture {
	private static final Set excludes = new HashSet();
	static{
		excludes.add("java.");
		excludes.add("javax.");
		excludes.add("org.");
	}
	private Map allMethods = new HashMap();
	private Map coveredMethods = new HashMap();
    pointcut classloading() :
       execution(Class ClassLoader+.loadClass(..)) &&
!cflowbelow(within(ClassLoaderCapture));
    after() returning(Class c) : classloading(){
	  String name = c.getName();
	  if(!excludes.contains(name.substring(0, name.indexOf('.')+1))){
		  Method[] m = c.getDeclaredMethods();
		  Set ms = new HashSet();
		  for(int i = 0; i < m.length;i++){
			  if(!m[i].getName().startsWith("ajc$"))
			  ms.add(m[i]);
		  }
          allMethods.put(c, ms);
	  }
    }

	public void register(Class c, Method m){
		String name = c.getName();
		if(!excludes.contains(name.substring(0, name.indexOf('.')+1))){
			if(!coveredMethods.containsKey(c)){
				coveredMethods.put(c, new HashSet());
			}
			((Set)coveredMethods.get(c)).add(m);
		}
	}

	void report(){
		Iterator cit = allMethods.entrySet().iterator();
		while(cit.hasNext()){
			Map.Entry entry = (Map.Entry) cit.next();
			if(coveredMethods.containsKey(entry.getKey())){
				Set cms = (Set) coveredMethods.get(entry.getKey());
				Set ams = (Set) entry.getValue();
				Set sms = new HashSet(ams);
				sms.removeAll(cms);
				System.out.println(((Class)entry.getKey()).getName() + " has "
				    +  ((double)cms.size())/ams.size() * 100
					+ "% coverage");
				System.out.println("Methods covered");
				Iterator cmit = cms.iterator();
				while(cmit.hasNext()){
					System.out.println("->"+ ((Method)cmit.next()).getName());
				}
				System.out.println("Methods skipped");
				Iterator smit = sms.iterator();
				while(smit.hasNext()){
					System.out.println("->"+ ((Method)smit.next()).getName());
				}
			}
			else{
				System.out.println(((Class)entry.getKey()).getName() + " has 0% coverage");
			}
		}
  }
}

========================================================
// an aspect that captures method invocations
import java.util.Collections;
import java.util.Arrays;
import java.util.Set;
import java.util.HashSet;
import java.lang.reflect.Method;
import java.util.Iterator;

public aspect CodeCoverAspect pertypewithin(*){
  pointcut mexec() : execution(* *(..)) && !within(CodeCoverAspect) &&
!within(ClassLoaderCapture);

  declare soft : ClassNotFoundException : within(CodeCoverAspect);
  declare soft : NoSuchMethodException : within(CodeCoverAspect);

  before() : mexec() {
      String mName = thisJoinPointStaticPart.getSignature().getName();
      Object[] args = thisJoinPoint.getArgs();
      Class[] types = new Class[args.length];
      for(int i=0;i<args.length;i++){
          types[i] = args[i].getClass();
      }
      Class clazz = thisJoinPointStaticPart.getSignature().getDeclaringType();
      Method m = clazz.getDeclaredMethod(mName, types);
      ClassLoaderCapture.aspectOf().register(clazz, m);
  }
}

========================================================
// and a dummy application
public class CodeCover{
    public static void main(String[] args) {
        CodeCover cctc = new CodeCover();
        cctc.m();
        CodeCover.p();
    }
    public void m() {
    }
    private void n(){
    }
    private static void o(){
    }
    static void p(){
    }
    static void q(){
    }
	void r(){
    }
}

..\bin\ajc -showWeaveInfo -classpath ..\lib\aspectjrt.jar *.java
Join point 'method-execution(void CodeCover.main(java.lang.String[]))'
in Type 'CodeCover' (CodeCover.java:2) advised by before advice from
'CodeCoverAspect' (CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.m())' in Type 'CodeCover'
(CodeCover.java:7) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.n())' in Type 'CodeCover'
(CodeCover.java:9) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.o())' in Type 'CodeCover'
(CodeCover.java:11) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.p())' in Type 'CodeCover'
(CodeCover.java:13) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.q())' in Type 'CodeCover'
(CodeCover.java:15) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(void CodeCover.r())' in Type 'CodeCover'
(CodeCover.java:17) advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Join point 'method-execution(java.lang.Class
ExtClassLoader.loadClass(java.lang.String))' in Type 'ExtClassLoader'
(ExtClassLoader.java:7) advised by before advice from
'CodeCoverAspect' (CodeCoverAspect.java:14)

Join point 'method-execution(java.lang.Class
ExtClassLoader.loadClass(java.lang.String))' in Type 'ExtClassLoader'
(ExtClassLoader.java:7) advised by afterReturning advice from
'ClassLoaderCapture' (ClassLoaderCapture.java:14) [with runtime
 test]

.... additional weave info left out for clarity.

and finally a way to invoke the code
java -classpath ..\lib\aspectjrt.jar;. -Dextcp=d:\app\extcp\ Invoker CodeCover

you might have to read some stuff up class loader delegation model to
understand what was done and why, to make a long story shory, the
aspects, the invoker class and ext class loader should be the only
classes that are loaded via the system class loader and you need to
load all application classes using extclassloader, i.e. they should
not be available in the class path, hence -Dextcp....

Output

CodeCover has 42.857142857142854% coverage
Methods covered
->p
->m
->main
Methods skipped
->q
->n
->o
->r

I noticed this in the weave info just as I was about to send the mail

Join point 'method-execution(void Invoker.main(java.lang.String[]))'
in Type 'Invoker' (Invoker.java:6) advised by before advice from
'CodeCoverAspect' (CodeCoverAspect.java:14)

Join point 'method-execution(java.net.URL[]
Invoker.getClasspathURLs())' in Type 'Invoker' (Invoker.java:27)
advised by before advice from 'CodeCoverAspect'
(CodeCoverAspect.java:14)

Invoker is adviced by CodeCoverAspect but there is no output, once
again think class loader.

I am guessing all that takes away from the assignment ... which was
probably something to do with AOP, you will probably be able to
improve on what I have, I'd be interested if you do

Thanks
Bhaskar



On Dec 31, 2007 2:19 PM, Bhaskar Maddala <maddalab@xxxxxxxxx> wrote:
> >> To do so, I planned to use a crosscut on the ClassLoader.LoadClass
> function, so I can check each class which is loaded in order to list
> it's methods (it's okay to check only the loaded classes).
>
> Is that really necessary? Seems to me that you are making it harder
> for yourself.
>
> Here is an aspect I wrote It seems to do what you want
>
> public aspect CodeCoverAspect pertypewithin(*){
>   private static Set types = new HashSet();
>   private Set ms = new HashSet();
>   pointcut init() : staticinitialization(*) &&
> !staticinitialization(CodeCoverAspect)
> &&!staticinitialization(ControlAspect);
>   pointcut mexec() : execution(* *(..)) && !within(CodeCoverAspect) &&
> !within(ControlAspect);
>
>   declare soft : ClassNotFoundException : within(CodeCoverAspect);
>   declare soft : NoSuchMethodException : within(CodeCoverAspect);
>
>   after() returning() : init() {
>       String typeName = getWithinTypeName();
>       Class clazz = Class.forName(typeName);
>       Method[] m = clazz.getDeclaredMethods();
>       ms.addAll(Arrays.asList(m));
>       types.add(typeName);
>   }
>
>   before() : mexec() {
>       String mName = thisJoinPointStaticPart.getSignature().getName();
>       Object[] args = thisJoinPoint.getArgs();
>       Class[] types = new Class[args.length];
>       for(int i=0;i<args.length;i++){
>           types[i] = args[i].getClass();
>       }
>       Class clazz = thisJoinPointStaticPart.getSignature().getDeclaringType();
>       Method m = clazz.getDeclaredMethod(mName, types);
>       ms.remove(m);
>   }
>
>   void report(){
>       Iterator it = ms.iterator();
>       while(it.hasNext()) {
>           Method m = (Method)it.next();
>           if(m.getName().indexOf('$') < 0)
>           System.out.println(m.getName() + " in type " +
> m.getDeclaringClass().getName() + " does not have code coverage.");
>       }
>   }
>
>   static Set types(){
>       return Collections.unmodifiableSet(types);
>   }
> }
>
> and another aspect to capture main(...) to do the reporting
>
> public aspect ControlAspect{
>     pointcut mains() : execution(public static void *.main(String[]));
>
>     after() returning() : mains() {
>         Set types = CodeCoverAspect.types();
>         Iterator it = types.iterator();
>         while(it.hasNext()){
>             try {
>               Class clazz = Class.forName((String)it.next());
>               if(CodeCoverAspect.hasAspect(clazz)) {
>                   CodeCoverAspect cca = CodeCoverAspect.aspectOf(clazz);
>                   cca.report();
>               }
>             }
>             catch(ClassNotFoundException ex){
>                 ex.printStackTrace();
>
>             }
>         }
>     }
>
> }
>
> On Dec 30, 2007 10:25 PM, Boudewijn Ector <boudewijn@xxxxxxxxxxxxxxxxx> wrote:
> > Dear peole,
> >
> > For a university assignment, I had to do a number of assignments. One of
> > these (the last one) is creating an aspect which checks for code
> > coverage, specifically function coverage.
> >
> > To do so, I planned to use a crosscut on the ClassLoader.LoadClass
> > function, so I can check each class which is loaded in order to list
> > it's methods (it's okay to check only the loaded classes).
> >
> > But whatever I'm doing, the Aspect just won't get triggered.
> > My current code :
> >
> > after() returning(Class <?> c):  target(ClassLoader) &&  call (Class<?>
> > loadClass(..))  && !within(SWE35)
> >
> > SWE35 is the current aspect. Afaik, this should work but I've also
> > tested while removing the <?> part (generics don't have to be
> > explicitely mentioned afaik). Can someone tell me what I'm doing wrong?
> > I've written succesfully about 25 aspects, but I just can't figure this
> > one out.
> >
> >
> > I'm using Sun Java 1.6 on a Linux box, and Eclipse-3.2 using it's
> > respective AspectJ plugin (the newest one) without further security
> > modifications.
> >
> >
> >
> > Cheers!
> >
> > Boudewijn Ector
> > _______________________________________________
> > aspectj-users mailing list
> > aspectj-users@xxxxxxxxxxx
> > https://dev.eclipse.org/mailman/listinfo/aspectj-users
> >
>


Back to the top