0

I am trying to write an aspect to catch all methods execution and retrieve the line number where the methods have been invoked. For example, if I have:

public class MyMainClass {
    public static void main(String[] args){
        MyArray m = new MyArray(5);
        m.setValue //...
        //...
    }
}

I would like to write a pointcut and an advice able to get the line where the method setValue has been called (i.e. line number 4) and not the source code line, where the method has been implemented (accessible with thisJoinPoint.getSourceLocation().getLine()).

Is there any way to do this? Thanks!

UPDATE: I just found out that this code:

StackTraceElement[] trace = Thread.currentThread().getStackTrace();
System.out.println("[AspectJ]LineNumber: " + trace[trace.length-1].getLineNumber());

prints the last method invocation line number, the problem is that it is not useful when there is method invocation inside a method implementation (because, in that case I should decrease trace elements position, but I don't know how to understand when to do that).

kriegaex
  • 63,017
  • 15
  • 111
  • 202
delca85
  • 1,176
  • 2
  • 10
  • 17
  • I have reformatted your code. Please learn how to use the syntax for code formatting and syntax highlighting. Thanks and welcome to StackOverflow. – kriegaex Feb 15 '17 at 18:44
  • Don't worry, you will learn about Java and AspectJ if you take your time. P.S.: My fencing is worse than your programming. ;-) – kriegaex Feb 15 '17 at 18:51
  • @kriegaex: Sorry, I am going to understand how to format code and to use syntax highlighting. And...here is really more important to be good at programming than at fencing! ;D – delca85 Feb 15 '17 at 19:29

2 Answers2

4

Next time, please share your aspect code if you have an AspectJ question, I had to guess what was going wrong in your case. But okay, this one was easy: If you get the source location from the executing method instead of the calling method, you have used an execution() pointcut, whereas you would have needed a call() pointcut, see also the first paragraph here.

BTW, In AspectJ you do not need to inspect stack traces manually, you just use thisJoinPoint.getSourceLocation(). That part of your initial idea was correct. You just had the wrong pointcut type.

Driver application + helper class:

package de.scrum_master.app;

public class MyMainClass {
  public static void main(String[] args) {
    MyArray m = new MyArray(5);
    m.setValue(2, 11);
  }
}
package de.scrum_master.app;

public class MyArray {
  public MyArray(int i) {
    // dummy
  }

  public void setValue(int i, int j) {
    // dummy
  }
}

Aspect in native AspectJ syntax:

package de.scrum_master.aspect;

import de.scrum_master.app.MyArray;

public aspect MyAspect {
  before() : call(* MyArray.setValue(..)) {
    System.out.println(thisJoinPoint + " -> " + thisJoinPoint.getSourceLocation());
  }
}

Console log:

call(void de.scrum_master.app.MyArray.setValue(int, int)) -> MyMainClass.java:6

I much prefer the native syntax, but if you prefer the weird, annotation-based @AspectJ syntax where you need the fully qualified class name inside the pointcut, this is the equivalent aspect:

package de.scrum_master.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class MyAspect {
  @Before("call(* de.scrum_master.app.MyArray.setValue(..))")
  public void logSourceLocation(JoinPoint thisJoinPoint) {
    System.out.println(thisJoinPoint + " -> " + thisJoinPoint.getSourceLocation());
  }
}

If you have any follow-up questions, feel free to ask, but please express yourself more clearly. It is quite hard to understand what exactly you are asking.

Community
  • 1
  • 1
kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Thank you very much kriegaex! I am sorry I haven't expressed myself clearly in the first post. You have completely answered to my question. Even if I have already read the link you posted me, I wasn't able to understand that for what I want, I should use _call_ instead of _execution_, I was really dumb. Thanks again! – delca85 Feb 15 '17 at 19:34
  • Just imagine you are calling your mother on the phone, telling her to switch on her TV because her favourite film is playing. You are the caller, she is the callee executing your "command". Where you are, `call()` is effective, where your mother is, `execution()` is effective. – kriegaex Feb 15 '17 at 20:37
  • Thank you, reading the post you linked to me again, and with this example I have understood. Sorry for the silly question. – delca85 Feb 15 '17 at 20:41
  • I am glad it was helpful. Thanks in advance for accepting and upvoting my answer. – kriegaex Feb 15 '17 at 21:23
  • I have just entered the stackoverflow community and because of my reputation, I cannot vote your answer. But I accepted it. Thanks again! – delca85 Feb 15 '17 at 21:46
0

Have you tried something like to get the line number ...

Thread.currentThread().getStackTrace()[2].getLineNumber();

You may need to verify the array index (e.g 2 in this case) position depending on your JVM version.

fabfas
  • 2,200
  • 1
  • 21
  • 21
  • I am getting the line number, maybe you haven't read my update. The problem is I don't know how to decide what position in trace array select. – delca85 Feb 15 '17 at 18:11