Bug 162135 - [plan] [ataspectj] BCException when @Around is uncommented - if() related
Summary: [plan] [ataspectj] BCException when @Around is uncommented - if() related
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.2   Edit
Hardware: PC Windows XP
: P3 normal (vote)
Target Milestone: 1.6.3   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2006-10-24 15:23 EDT by Barry Kaplan CLA
Modified: 2008-12-04 18:42 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Barry Kaplan CLA 2006-10-24 15:23:31 EDT
I'm getting the below exception whenever the @Around is uncommented:

package com.foliofn.infra.logging;

import java.lang.reflect.Field;

import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.NDC;
import org.apache.log4j.spi.LoggingEvent;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;

@Aspect
public class ExceptionMessageNdcAdderC {

    static final String SEPERATOR = " - ";

    private Logger log = Logger.getLogger(getClass());

    @Pointcut("call(Throwable+.new(String, ..)) && this(caller) && args(exceptionMessage) && if()")
    public static boolean exceptionInitializer(Object caller, String exceptionMessage) {
        return isNdcEmpty();
    }
    
    // Comment out just the next line and the error does not occur.
    @Around("exceptionInitializer(caller, exceptionMessage)")
    public Object annotateException(ProceedingJoinPoint jp, Object caller, String exceptionMessage) {
//        return jp.proceed(new Object[]{caller, ndcAnnotateMessage(exceptionMessage)});
        return null;
    }
    
    private static boolean isNdcEmpty() {
        return NDC.getDepth() == 0;
    }
    
    private String ndcAnnotateMessage(String message) {
        return  formatNdcAnnotatedMessage(getNcdValue(), message);
    }
    
    private String getNcdValue() {
        LoggingEvent logEvent = new LoggingEvent("anything", log, Level.INFO, "anything", null);
        return logEvent.getNDC();
    }
    
    static String formatNdcAnnotatedMessage(String ndcValue, String message) {
        return ndcValue + SEPERATOR + message;
    }
    
}


------
org.aspectj.weaver.BCException
at org.aspectj.weaver.bcel.BcelRenderer.visit(BcelRenderer.java:237)
at org.aspectj.weaver.ast.Literal.accept(Literal.java:29)
at org.aspectj.weaver.bcel.BcelRenderer.recur(BcelRenderer.java:153)
at org.aspectj.weaver.bcel.BcelRenderer.renderTest(BcelRenderer.java:119)
at org.aspectj.weaver.bcel.BcelAdvice.getTestInstructions(BcelAdvice.java:587)
at org.aspectj.weaver.bcel.BcelShadow.weaveAroundClosure(BcelShadow.java:3050)
at org.aspectj.weaver.bcel.BcelAdvice.implementOn(BcelAdvice.java:270)
at org.aspectj.weaver.Shadow.implementMungers(Shadow.java:684)
at org.aspectj.weaver.Shadow.implement(Shadow.java:471)
at org.aspectj.weaver.bcel.BcelClassWeaver.implement(BcelClassWeaver.java:2825)
at org.aspectj.weaver.bcel.BcelClassWeaver.weave(BcelClassWeaver.java:502)
at org.aspectj.weaver.bcel.BcelClassWeaver.weave(BcelClassWeaver.java:115)
at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1574)
at org.aspectj.weaver.bcel.BcelWeaver.weaveWithoutDump(BcelWeaver.java:1525)
at org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify(BcelWeaver.java:1305)
at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1127)
at org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.weave(AjCompilerAdapter.java:321)
at org.aspectj.ajdt.internal.compiler.AjCompilerAdapter.afterCompiling(AjCompilerAdapter.java:192)
at org.aspectj.ajdt.internal.compiler.CompilerAdapter.ajc$afterReturning$org_aspectj_ajdt_internal_compiler_CompilerAdapter$2$f9cc9ca0(CompilerAdapter.aj:70)
at org.aspectj.org.eclipse.jdt.internal.compiler.Compiler.compile(Compiler.java:367)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.performCompilation(AjBuildManager.java:887)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.doBuild(AjBuildManager.java:244)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.doBuild(AjBuildManager.java:199)
at org.aspectj.ajdt.internal.core.builder.AjBuildManager.incrementalBuild(AjBuildManager.java:170)
at org.aspectj.ajde.internal.CompilerAdapter.compile(CompilerAdapter.java:117)
at org.aspectj.ajde.internal.AspectJBuildManager$CompilerThread.run(AspectJBuildManager.java:191)

trouble in: 
public class com.foliofn.infra.logging.ExceptionThrowingClassForTest extends java.lang.Object:
  public org.apache.log4j.Logger log
  private static final org.aspectj.lang.JoinPoint$StaticPart ajc$tjp_0 [Synthetic]
  public void <init>():
                    ALOAD_0     // Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest; this   (line 5)
                    INVOKESPECIAL java.lang.Object.<init> ()V
    constructor-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.<init>())
    |               ALOAD_0     // Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest; this   (line 7)
    |               ALOAD_0     // Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest; this
    |               INVOKEVIRTUAL java.lang.Object.getClass ()Ljava/lang/Class;
    |               INVOKESTATIC org.apache.log4j.Logger.getLogger (Ljava/lang/Class;)Lorg/apache/log4j/Logger;
    |               PUTFIELD com.foliofn.infra.logging.ExceptionThrowingClassForTest.log Lorg/apache/log4j/Logger;
    |               RETURN   (line 5)
    constructor-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.<init>())
  end public void <init>()

  public void throwRuntimeException(String)    org.aspectj.weaver.MethodDeclarationLineNumber: 9:194
:
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwRuntimeException(java.lang.String))
    |               ALOAD_1     // Ljava/lang/String; message   (line 10)
    |               ASTORE_2
    |               GETSTATIC com.foliofn.infra.logging.ExceptionThrowingClassForTest.ajc$tjp_0 Lorg/aspectj/lang/JoinPoint$StaticPart;
    |               ALOAD_0
    |               ACONST_NULL
    |               ALOAD_2
    |               INVOKESTATIC org.aspectj.runtime.reflect.Factory.makeJP (Lorg/aspectj/lang/JoinPoint$StaticPart;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Lorg/aspectj/lang/JoinPoint;
    |               ASTORE_3
    |               ATHROW
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwRuntimeException(java.lang.String))
  end public void throwRuntimeException(String)

  public void throwRuntimeException(String, Throwable)    org.aspectj.weaver.MethodDeclarationLineNumber: 13:306
:
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwRuntimeException(java.lang.String, java.lang.Throwable))
    |               NEW java.lang.RuntimeException   (line 14)
    |               DUP
    |               ALOAD_1     // Ljava/lang/String; message
    |               ALOAD_2     // Ljava/lang/Throwable; nested
    | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String, java.lang.Throwable))
    | |             INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;Ljava/lang/Throwable;)V
    | constructor-call(void java.lang.RuntimeException.<init>(java.lang.String, java.lang.Throwable))
    |               ATHROW
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwRuntimeException(java.lang.String, java.lang.Throwable))
  end public void throwRuntimeException(String, Throwable)

  public void throwException(String) throws java.lang.Exception    org.aspectj.weaver.MethodDeclarationLineNumber: 17:444
:
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwException(java.lang.String))
    |               NEW java.lang.Exception   (line 18)
    |               DUP
    |               ALOAD_1     // Ljava/lang/String; message
    | constructor-call(void java.lang.Exception.<init>(java.lang.String))
    | |             INVOKESPECIAL java.lang.Exception.<init> (Ljava/lang/String;)V
    | constructor-call(void java.lang.Exception.<init>(java.lang.String))
    |               ATHROW
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwException(java.lang.String))
  end public void throwException(String) throws java.lang.Exception

  public void throwExceptionExtension(Object) throws java.lang.RuntimeException    org.aspectj.weaver.MethodDeclarationLineNumber: 21:559
:
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwExceptionExtension(java.lang.Object))
    |               NEW com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension   (line 22)
    |               DUP
    |               ALOAD_0     // Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest; this
    |               ALOAD_1     // Ljava/lang/Object; someObject
    | constructor-call(void com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init>(com.foliofn.infra.logging.ExceptionThrowingClassForTest, java.lang.Object))
    | |             INVOKESPECIAL com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init> (Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest;Ljava/lang/Object;)V
    | constructor-call(void com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init>(com.foliofn.infra.logging.ExceptionThrowingClassForTest, java.lang.Object))
    |               ATHROW
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwExceptionExtension(java.lang.Object))
  end public void throwExceptionExtension(Object) throws java.lang.RuntimeException

  public void throwExceptionExtension(Object, Throwable) throws java.lang.RuntimeException    org.aspectj.weaver.MethodDeclarationLineNumber: 25:705
:
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwExceptionExtension(java.lang.Object, java.lang.Throwable))
    |               NEW com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension   (line 26)
    |               DUP
    |               ALOAD_0     // Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest; this
    |               ALOAD_1     // Ljava/lang/Object; someObject
    |               ALOAD_2     // Ljava/lang/Throwable; t
    | constructor-call(void com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init>(com.foliofn.infra.logging.ExceptionThrowingClassForTest, java.lang.Object, java.lang.Throwable))
    | |             INVOKESPECIAL com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init> (Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest;Ljava/lang/Object;Ljava/lang/Throwable;)V
    | constructor-call(void com.foliofn.infra.logging.ExceptionThrowingClassForTest$ExceptionExtension.<init>(com.foliofn.infra.logging.ExceptionThrowingClassForTest, java.lang.Object, java.lang.Throwable))
    |               ATHROW
    method-execution(void com.foliofn.infra.logging.ExceptionThrowingClassForTest.throwExceptionExtension(java.lang.Object, java.lang.Throwable))
  end public void throwExceptionExtension(Object, Throwable) throws java.lang.RuntimeException

  static final RuntimeException init$_aroundBody0(com.foliofn.infra.logging.ExceptionThrowingClassForTest, String, org.aspectj.lang.JoinPoint):
                    NEW java.lang.RuntimeException
                    DUP
                    ALOAD_1
                    INVOKESPECIAL java.lang.RuntimeException.<init> (Ljava/lang/String;)V   (line 10)
                    ARETURN
  end static final RuntimeException init$_aroundBody0(com.foliofn.infra.logging.ExceptionThrowingClassForTest, String, org.aspectj.lang.JoinPoint)
end public class com.foliofn.infra.logging.ExceptionThrowingClassForTest

public class com.foliofn.infra.logging.ExceptionThrowingClassForTest$AjcClosure1 extends org.aspectj.runtime.internal.AroundClosure:
  public void <init>(Object[]):
                    ALOAD_0
                    ALOAD_1
                    INVOKESPECIAL org.aspectj.runtime.internal.AroundClosure.<init> ([Ljava/lang/Object;)V
                    RETURN
  end public void <init>(Object[])

  public Object run(Object[]):
                    ALOAD_0
                    GETFIELD org.aspectj.runtime.internal.AroundClosure.state [Ljava/lang/Object;
                    ASTORE_2
                    ALOAD_2
                    BIPUSH 0
                    AALOAD
                    CHECKCAST com.foliofn.infra.logging.ExceptionThrowingClassForTest
                    ALOAD_2
                    BIPUSH 1
                    AALOAD
                    CHECKCAST java.lang.String
                    ALOAD_2
                    BIPUSH 2
                    AALOAD
                    CHECKCAST org.aspectj.lang.JoinPoint
                    INVOKESTATIC com.foliofn.infra.logging.ExceptionThrowingClassForTest.init$_aroundBody0 (Lcom/foliofn/infra/logging/ExceptionThrowingClassForTest;Ljava/lang/String;Lorg/aspectj/lang/JoinPoint;)Ljava/lang/RuntimeException;
                    ARETURN
  end public Object run(Object[])
end public class com.foliofn.infra.logging.ExceptionThrowingClassForTest$AjcClosure1

when implementing on shadow constructor-call(void java.lang.RuntimeException.<init>(java.lang.String))
when weaving type com.foliofn.infra.logging.ExceptionThrowingClassForTest
when weaving classes 
when weaving 
when batch building BuildConfig[Q:\eclipse.workspaces\folio2\.metadata\.plugins\org.eclipse.ajdt.core\fn_infra.aj.generated.lst] #Files=18
Comment 1 Barry Kaplan CLA 2006-10-24 15:26:24 EDT
Actually, the error appears to be releated to the if() in the exceptionInitializer pointcut. If I remove the "&& if()" and change the signature the error is eliminated (with the full @Around adviced uncommented)
Comment 2 Andrew Clement CLA 2006-10-25 05:23:49 EDT
thanks for the small testcase -  I have recreated this.  I'd probably use code style aspects if I were you, the if() support in annotation style is a bit buggy.
Comment 3 Barry Kaplan CLA 2006-10-25 07:18:39 EDT
Thanks for recreating! Too bad about @Aspect if()'s. We are using only @Aspect syntax. Is there a category/search criteria for @Aspect specific bugs so I can be on the lookout for gotchas?
Comment 4 Andrew Clement CLA 2006-10-30 05:23:54 EST
tests for this have been committed (they are currently commented out in Ajc153tests)
Comment 5 Andrew Clement CLA 2008-12-04 18:42:19 EST
ok, the problem here is the parameter binding is hopeless for annotation style.

Here is the pointcut (highlights):

 @Pointcut("call(...) && this(caller) && args(exceptionMessage) && if()")
    public static boolean foo(Object caller, String exceptionMessage) {

and here is the advice method (highlights):

@Around("foo(caller, exceptionMessage)")
public Object goo(ProceedingJoinPoint jp, Object caller, String exceptionMessage) {

Code style does a lot of analysis to bind things correctly.  Here the binding of caller and exceptionmessage for passing to them to foo() gets completely thrown by the addition of ProceedingJoinPoint in the advice method.  In the end it kind of attempts to pass ProceedingJoinPoint and caller as the two parameters to foo.  And blows up as shown.

So I've made this situation work now.  It is is still fragile but the rules are relatively straightforward - the parameter ordering for the if() must match the order in goo() but you are allowed special parameters ahead of the normal parameters (like ProceedingJoinPoint above).  I've added 6 testcase variants for this and they are all OK.  It will be easy to break it by violating this rule but at least a well written pointcut/advice pair will work as expected now.