Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.

Bug 347395

Summary: java.lang.VerifyError after custom aspect weaving
Product: [Tools] AspectJ Reporter: akankaluga <forolap>
Component: LTWeavingAssignee: aspectj inbox <aspectj-inbox>
Status: NEW --- QA Contact:
Severity: normal    
Priority: P3 CC: aclement
Version: 1.6.11   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:
Attachments:
Description Flags
Initial aspect class
none
Decompiled woven TaskHistoryAspect
none
updated decompiled aspect none

Description akankaluga CLA 2011-05-27 02:00:44 EDT
Build Identifier: 

I was updated to new version of aspectj (1.6.11) from ver 1.6.0. My aspect is looking like:
@Aspect
public class TaskHistoryAspect {

    @Pointcut("execution(@xxx.TaskModification * *.*(..))")
    void modification(ProceedingJoinPoint joinPoint) {}

    @Around("modification(joinPoint)")
    public Object aroundModification(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        Task task = ...// obtaining from args
        List<Task> list = ... // obtaining from args;
        try {
            Object result = joinPoint.proceed(joinPoint.getArgs());
            if (task != null) {
                logModification(joinPoint, task);
            } else if (list != null) {
                logModification(joinPoint, list);
            }
            return result;
        } finally {
           // do somthing
        }
    }

    private void logModification(JoinPoint joinPoint, Task task) {
        // log for task
    }

    private void logModification(JoinPoint joinPoint, List<Task> tasks) {
       // log for each task in list
    }
}

Part of code was skipped for simplifying.
After weaving that aspect (I use LTW) was an error:

Caused by: java.lang.VerifyError: (class: xxx/TaskHistoryAspect, method: aroundModification signature: (Lorg/aspectj/lang/ProceedingJoinPoint;)Ljava/lang/Object;) Incompatible argument to function

I have saved weaved code for class, it seems like (also simplified):
@Around(value="modification(joinPoint)")
    public Object aroundModification(ProceedingJoinPoint joinPoint)
        throws Throwable
    {
        Task task;
        List list;
...
        Object obj;
        Object result = joinPoint.proceed(joinPoint.getArgs());
        if(task != null)
            ajc$inlineAccessMethod$xxx_TaskHistoryAspect$xxx_TaskHistoryAspect$logModification(this, joinPoint, task);
        else
        if(list != null)
            ajc$inlineAccessMethod$xxx_TaskHistoryAspect$xxx_TaskHistoryAspect$logModification(this, joinPoint, list);
        obj = result;
 ...
    }

and only 1 method with name ajc$inlineAccessMethod$xxx_TaskHistoryAspect$xxx_TaskHistoryAspect$logModification with Task argument (for List was not presented):

public static void ajc$inlineAccessMethod$xxx_TaskHistoryAspect$xxx_TaskHistoryAspect$logModification(TaskHistoryAspect taskhistoryaspect, JoinPoint joinpoint, Task task)
    {
        taskhistoryaspect.logModification(joinpoint, task);
    }

I think, the problem cause is incorrect class transformation when there are overloaded methods. It is only hypothesis..


Reproducible: Always
Comment 1 Andrew Clement CLA 2011-05-27 12:25:31 EDT
is there anyway you can complete the sample with something that gets advised and shows the failure when executing?  I tried creating something simple but it just worked for me.
Comment 2 akankaluga CLA 2011-05-28 03:03:56 EDT
Created attachment 196820 [details]
Initial aspect class

TaskHistoryAspect, initial aspect class
Comment 3 akankaluga CLA 2011-05-28 03:06:21 EDT
Created attachment 196821 [details]
Decompiled woven TaskHistoryAspect

I had saved transformed TaskHistoryAspect class (in debug during class loading by TomcatInstrumentalClassloader) and decompiled it later. Decompiled class is in attachement
Comment 4 akankaluga CLA 2011-05-28 03:12:27 EDT
I have attached initial and woven aspects (in files was changed only package, to xxx). Also I have noticed that there is join point from another aspect (ExceptionsTranslationAspect) in method public TaskAuditService getTaskAuditService(). It is strange... I can provide code for ExceptionsTranslationAspect too if needed.
Comment 5 akankaluga CLA 2011-05-28 03:19:57 EDT
Created attachment 196822 [details]
updated decompiled aspect

updated
Comment 6 akankaluga CLA 2011-05-28 03:24:42 EDT
After changing aspect code to new (see below) all things become well.

@Around("modification(joinPoint)")
    public Object aroundModification(ProceedingJoinPoint joinPoint) throws Throwable {
        Object target = joinPoint.getTarget();
        List<Task> list = new LinkedList<Task>();
        if (target instanceof TaskAware) {
            list.add(((TaskAware) target).getTask());
        } else {
            for (Object arg : joinPoint.getArgs()) {
                if (arg instanceof Task) {
                    list.add((Task) arg);
                    break;
                } else if(arg instanceof List) {
                    List tmpLst = new LinkedList((List) arg);
                    if (tmpLst.size() > 0 && tmpLst.get(0) instanceof Task) {
                        list.addAll(tmpLst);
                        break;
                    }
                }
            }
        }
        pushInfoForTaskList(list);
        try {
            Object result = joinPoint.proceed(joinPoint.getArgs());
            logModification(joinPoint, list);
            return result;
        } finally {
            popInfoForTaskList(list);
        }
    }
Comment 7 Andrew Clement CLA 2011-06-20 13:22:57 EDT
ok - the problem here is the two similar methods:

    private void logModification(JoinPoint joinPoint, Task task) {
        // log for task
    }

    private void logModification(JoinPoint joinPoint, List<Task> tasks) {
       // log for each task in list
    }

These only differ in terms of parameters.  AspectJ attempts to generate an accessor method for calling these from elsewhere (it needs to because they are private).  Because the parameters aren't used in the logic that computes the accessors, it generates one accessor for both methods (!).  Clearly this accessor can't cope with the two kinds of second parameter (task/list) and so a verify error comes out.  Simplest workaround is renaming one of them (call it logModificationWithList for example).  I have a prototype of the fix but generating two accessors in this situation is breaking some other tests and I still have to get to the bottom of why that is.