1

Is it possible to read the class property name and value in Aspectj advice while having the properties as the pointcuts. Below is the code snippet .

JAVA code:

package com.test;

public class Test {
    static List<String> list;
    static List<String> removeList;
    public static void main(String[] args) {
        list = new ArrayList<String>();
        list.add("ashish");
        removeList = new ArrayList<String>();
        removeList.add("kumar");
    }
}

AspectJ code:

package com.test;

public aspect AspectjTest {
    pointcut callAdd(): within(com.test.*) && call(* java.util.List.add(..));

    boolean around() : callAdd() {
        //code to get the property name and property value(i.e. the value going to be added to the list)
        return true;
    }
}
kriegaex
  • 63,017
  • 15
  • 111
  • 202
ashishakp
  • 111
  • 1
  • 8

1 Answers1

1

You should bind the method parameter to a variable via args() like this:

package com.test;

import java.util.List;

public aspect AspectjTest {
    pointcut callAdd(Object element) :
        within(com.test.*) &&
        call(boolean List.add(*)) &&
        args(element);

    boolean around(Object element) : callAdd(element) {
        System.out.println(thisJoinPoint + " -> " + element);
        return proceed(element);
    }
}

Console log:

call(boolean java.util.List.add(Object)) -> ashish
call(boolean java.util.List.add(Object)) -> kumar

Feel free to ask follow-up questions if you do not understand this.


Update: What I mean by refactoring is something like what Eclipse does for you (or any other decent IDE in a similar way) when you use menu option "Source", "Generate delegate methods". The result is something like this:

package com.test;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class NameDatabase {
    private final List<String> firstNames = new ArrayList<String>();
    private final List<String> lastNames = new ArrayList<String>();

    public boolean addFirstName(String e) {
        return firstNames.add(e);
    }

    public boolean removeFirstName(Object o) {
        return firstNames.remove(o);
    }

    public Stream<String> streamFirstNames() {
        return firstNames.stream();
    }

    public boolean addLastName(String e) {
        return lastNames.add(e);
    }

    public boolean removeLastName(Object o) {
        return lastNames.remove(o);
    }

    public Stream<String> streamLastNames() {
        return lastNames.stream();
    }

    public static void main(String[] args) {
        NameDatabase database = new NameDatabase();
        database.addFirstName("Galileo");
        database.addLastName("Galilei");
        database.addFirstName("Isaac");
        database.addLastName("Newton");
        database.addFirstName("Albert");
        database.addLastName("Einstein");
        database.addFirstName("Werner");
        database.addLastName("Heisenberg");
        database.addFirstName("Stephen");
        database.addLastName("Hawking");

        database.removeFirstName("Werner");
        database.removeLastName("Heisenberg");

        System.out.println(database.streamFirstNames().collect(Collectors.joining(", ")));
        System.out.println(database.streamLastNames().collect(Collectors.joining(", ")));
    }
}

Corresponding aspect:

package com.test;

public aspect NameDBContentAuditor {
    before(String name) :
        execution(public * NameDatabase.*stName(*)) &&
        args(name)
    {
        System.out.println(thisJoinPoint + " -> " + name);
    }
}

Console log:

execution(boolean com.test.NameDatabase.addFirstName(String)) -> Galileo
execution(boolean com.test.NameDatabase.addLastName(String)) -> Galilei
execution(boolean com.test.NameDatabase.addFirstName(String)) -> Isaac
execution(boolean com.test.NameDatabase.addLastName(String)) -> Newton
execution(boolean com.test.NameDatabase.addFirstName(String)) -> Albert
execution(boolean com.test.NameDatabase.addLastName(String)) -> Einstein
execution(boolean com.test.NameDatabase.addFirstName(String)) -> Werner
execution(boolean com.test.NameDatabase.addLastName(String)) -> Heisenberg
execution(boolean com.test.NameDatabase.addFirstName(String)) -> Stephen
execution(boolean com.test.NameDatabase.addLastName(String)) -> Hawking
execution(boolean com.test.NameDatabase.removeFirstName(Object)) -> Werner
execution(boolean com.test.NameDatabase.removeLastName(Object)) -> Heisenberg
Galileo, Isaac, Albert, Stephen
Galilei, Newton, Einstein, Hawking
kriegaex
  • 63,017
  • 15
  • 111
  • 202
  • Thanks for your response @kriegaex. But what I need is to get the class member name too i.e. nothing but the lists name here (ex 'list' and 'removeList'). The example you have given will able to get the values but here inside advice it is impossible to know which value is going to be added to which list. So I need the list name as well as the value to be added. – ashishakp Sep 19 '16 at 05:04
  • No, you don't. You need to encapsulate access to those members in getter/setter methods and intercept those via AspectJ by some other means. That it is hard to trace what happens in your code is not a reason to tweak the tool but to refactor. – kriegaex Sep 20 '16 at 20:26
  • I updated the answer so as to show what I mean by refactoring. – kriegaex Sep 20 '16 at 20:59
  • BTW, it would be possible to record the list objects assigned to the two members in `set()` aspects including the member names extracted from that joinpoint and then do internal object bookkeeping from in the aspect. Then, whenever an `add()` method is called upon any member in your internal list, you could correlate the method call to the member name. But that is just awful overhead. I know how to do it, but I do not think the effort is worth the trouble in comparison with the suggested refactoring. – kriegaex Sep 20 '16 at 20:59