Bug 363985

Summary: advising a private constructor generates an extra ctor that is also advised
Product: [Tools] AspectJ Reporter: Pepe <ppregs>
Component: RuntimeAssignee: aspectj inbox <aspectj-inbox>
Status: NEW --- QA Contact:
Severity: major    
Priority: P3 CC: aclement
Version: unspecified   
Target Milestone: ---   
Hardware: PC   
OS: Windows XP   
Whiteboard:

Description Pepe CLA 2011-11-16 19:10:06 EST
Build Identifier: 20110615-0604

When advising a private constructor a new constructor seems to be created.
The problem is that that new ctor is also advised if the pointcut uses new(..).

The code in "steps to reproduce" generates,

-if the ctor is not private:
before 0
Hi
after 0

-if the ctor is private:
before 0
Hi
after 0
before 1
null
after 1
null



Reproducible: Always

Steps to Reproduce:
package org.aspectj.bugs;

public aspect bug {

	static private class A {
		private A() {
			System.out.println("Hi");
		}
	}
	
	pointcut insert(A a) : this(a) && execution(A.new(..));

	before(A a) : insert(a) {
		System.out.println("before " + thisJoinPoint.getArgs().length);
		if(thisJoinPoint.getArgs().length == 1) {
			System.out.println(thisJoinPoint.getArgs()[0]);
		}
	}
	
	after(A a) : insert(a) {
		System.out.println("after " + thisJoinPoint.getArgs().length);
		if(thisJoinPoint.getArgs().length == 1) {
			System.out.println(thisJoinPoint.getArgs()[0]);
		}
	}
	
	public static void main(String[] args) {
		new A();
	}
	
}
Comment 1 Andrew Clement CLA 2011-11-17 16:29:35 EST
The generation of the secondary constructor is not AspectJ, it is how the eclipse compiler chooses to implement private inner class constructors (if the outer class needs to be able to see into the type, the compiler creates a second ctor of package visibility and tries to kind of 'hide it' by making it synthetic and giving it an unusual argument).  javac does things differently - it does generate the extra ctor but the parameter is of a different type.  This code compiled with javac or plain eclipse will show bytecode containing two ctors (for class B):

public class A {
  static private class B {
    private B() {
    }
  }

  public void m() {
    new B();
  }
}

Anyway, the AspectJ weaver sees the bytecode and all it sees are two different constructors, it doesn't know/recognize what the compiler did to create them, so it is kind of working-as-designed that both are advised.

In your advice you can exclude synthetic constructors:

execution(!synthetic A.new(..));