Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] Re: [aspectj-dev] AspectJ Runtime: Signatures for interface initialization and type staticinitialization

(late reply - spam cop)
 
I agree that we should document it in the API if we return null.  (More generally, we should document
handling of interfaces generally - matching those types, declaring members on them, matching
initializers, order of initialization, etc.  But it's not clear to me yet where that should go.)
 
The Signature interfaces aren't so elegant.  It would be nice if there was one for each kind of join point
and they used the same names as JoinPoint.getKind().  However, removing getConstructor() from
InitializerSignature would be a binary-incompatible change, so we won't make that change.
It would be runtime-incompatible to stop returning InitializerSignature from an interface-initialization
join point.  That could be ok if justified, but I don't think we should create InterfaceInitializerSignature since
it's not a kind of join point nor is it a different signature (syntactically) from class initializer.
 
Also if we do add StaticInitializerSignature it probably should not be a CodeSignature since they
have no parameters or exceptions.  But that again is a runtime-incompatible change since we've been
returning InitializerSignature for static initialization.  So we could create StaticInitializerSignature as a
subinterface of InitializerSignature, and then document that it returns empty arrays or null from *all*
of the methods (inherited from CodeSignature and InitializerSignature).  Oh joy!  We could call it
EmptyInitializerSignature or NonConstructorInitializerSignature and use it for both static initializers
and interface initializers, but yuck!
 
So avoiding making binary-incompatible changes I think forces us to return null/empty values and
document them.  Since the user can get the kind of the join point from JoinPoint.StaticPart.getKind(),
s/he can distinguish static-initialization join points from initialization join points, so there's no real
reason to create StaticInitializerSignature if/since it offers no additional methods (and indeed, can't
implement the methods it inherits).   The user can also check if the declaring type is an interface
(JoinPoint.StaticPart.getSignature().getDeclaringType().isInterface()). 
 
It might be a helpful static optimization to add boolean JoinPoint.StaticPart.isDeclaringTypeInterface().
Some uses are:
- detecting initialization and staticinitialization of interfaces
- detecting whether a top-level implementation of a interface method was defined in an aspect
 
But I'm not sure these underlie compelling use-cases.  Does anyone have more use-cases for this?
Also, it exposes what might be implementation-specific behaviors, and thus to encourage
people to write programs that might not work in other implementations of AspectJ.
 
Wes
 
------------Original Message------------
From: Matthew Webster <matthew_webster@xxxxxxxxxx>
To: wes@xxxxxxxxxxxxxx, "AspectJ developer discussions" <aspectj-dev@xxxxxxxxxxx>
Date: Thu, Sep-21-2006 6:54 AM
Subject: Re: [aspectj-dev] AspectJ Runtime: Signatures for interface    initialization and type staticinitialization

Wes,

Ok, I accept that the declaring type for an interface initialization join point should be the interface type. What I find hard to accept is that "getConstructor()" can return null, not because the terse API documentation says so but because we silently catch an exception. We have an elegant hierarchy of Signature types so we should return one for interface intializers which has no such method. The only methods that are documented to return null (and for which it makes complete sense) are JoinPoint.getThis/Target().

The other issue not covered concerns staticinitialization join points. Having InitializerSignature.getInitializer() return a java.lang.reflect.Constructor makes no sense especially when for a class this turns out to be the default constructor. You get null here for interface types too:

public aspect Aspect {


        before () : staticinitialization(Interface+) && !within(Aspect) {
                Signature signature = thisJoinPoint.getSignature();
                System.err.println("Aspect.before() this=" + thisJoinPoint.getThis() + ", signature=" + signature.getClass() + ", declaringType=" + thisJoinPoint.getSignature().getDeclaringTypeName() + ", " + ((InitializerSignature)signature).getInitializer());
        }
       
}

Aspect.before() this=null, signature=class org.aspectj.runtime.reflect.InitializerSignatureImpl, declaringType=Test, public Test()
Aspect.before() this=null, signature=class org.aspectj.runtime.reflect.InitializerSignatureImpl, declaringType=Interface, null

My main concern is that our API sometimes returns an undocumented null which can cause a user application to fail as in  https://bugs.eclipse.org/bugs/show_bug.cgi?id=157054.

Matthew Webster
AOSD Project
Java Technology Centre, MP146
IBM Hursley Park, Winchester,  SO21 2JN, England
Telephone: +44 196 2816139 (external) 246139 (internal)
Email: Matthew Webster/UK/IBM @ IBMGB, matthew_webster@xxxxxxxxxx
http://w3.hursley.ibm.com/~websterm/



"Wes" <wes@xxxxxxxxxxxxxx>
Sent by: aspectj-dev-bounces@xxxxxxxxxxx

20/09/2006 19:27

Please respond to
wes@xxxxxxxxxxxxxx; Please respond to
AspectJ developer discussions <aspectj-dev@xxxxxxxxxxx>

To
"AspectJ developer discussions" <aspectj-dev@xxxxxxxxxxx>
cc
Subject
Re: [aspectj-dev] AspectJ Runtime: Signatures for interface        initialization and type staticinitialization





Thanks for bringing this up for discussion, Matthew.  Some comments and code
below; I do think the current behavior is correct, i.e., it's what the user should
expect based on how the programming guide describes initialization and handling
interface initializers.
 
First,
> One thing I am sure of: we should not return null [from getConstructor()]
 
That seems like the correct behavior to me if there is no constructor for an interface
(this assumes we have an interface-specific initializer, which I think we do).  
 
Second, wrt interface initialization, even though Java does not permit interfaces to have
constructors, AspectJ permits interfaces to have fields that have initialization statements,
so I think users should be able to expect those to be sequestered in an interface initializer,
i.e., "initialization(Interface.new(..)) && ! initialization(Instance.new(..))"  Indeed, in the
example of an instance with superclass and superinterface, there should be three
initialization join points: the instance, the superclass, and the superinterface.  This is
what the code below shows.  With care, each join point can be picked out.
 
Third, wrt declaring type,  the programming guide says
 
 "At object initialization and pre-initialization join points, the signature is the constructor
 signature for the constructor that started this initialization: the first constructor entered
 during this type's initialization of this object."
 
On one hand, I think we'd want AspectJ's reflective access to follow this model, so the
declaring type of the (reflective) signature indeed should reflect the specific instance type,
"Test" in your program and "Initializer" in mine below.  On the other hand, if the pointcut
really is only picking out the interface or superclass initialization join point, it seems
weird to say that it picks up the declaring type of the initiating constructor.  That would mean
the declaring type of the interface-initializer join point enclosed by the subtype-initializer
join point would be the subtype, and it would thus get as many declaring types as
there are implementing types, and it becomes not static data associated with the
join point but dynamic data associated with the enclosing join point.  So perhaps
we should qualify the programming guide to say the declaring type for purposes
of matching or some such language.  In any case, the code below shows what I think
is the correct declaring type, Interface for the interface-initialization and Initializer for
the subtype.
 
Fourth, one might think that initialization of an instance starts the instance-initialization join
point and then starts the instance-initialization join point of any parent, since this is what
Java leads us to believe is the order of execution for constructors.  However, AspectJ defines
constructor-execution for the subtype to start when the code for the constructor starts,
which is after any explicit or implicit call to this(..) or super(..) in the constructor.  That
means the supertype constructor-execution join point is not enclosed by the subtype
constructor execution.  Initialization follows this even though initialization is intended to
pick out the initiating constructor.  So even though the initialization join point matches based
on the subtype-type, the first initialization join point run is not the subtype-being-initialized but
the supertype.  That's reflected in the code below and should probably be explained to users.
(There is a faq entry on point, as well as a definition of the order of initialization for interfaces.)
 
hth - Wes
 
-------  Initializer.java
import org.aspectj.lang.Signature;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.ConstructorSignature;

 
interface Interface { void m();}
 
public class Initializer extends Parent implements Interface {
 
        public static void main(String[] args) {
               new Initializer();
       }

 
}
 

class Parent { public void m(){}}

 
aspect Aspect {
       static int counting() {
               System.err.println("COUNTING"); return ++COUNT; }
       static int COUNT;

 
        public int Interface.count = counting();
 

       before () : initialization(Initializer.new()) {
               print(thisJoinPoint, " Interface");
       }
       before () : initialization(Interface.new()) {
               print(thisJoinPoint, " Interface");
       }
       before () : initialization(Interface.new())
                   && !initialization(Parent.new()) {
               print(thisJoinPoint, "=Interface");
       }
       before() : initialization(Parent.new()) {
               print(thisJoinPoint, "    Parent");
       }
       before() : initialization(Parent.new())
                   && !initialization(Initializer.new()) {
               print(thisJoinPoint, "   =Parent");
       }
       before() : initialization(Parent+.new()) {
               print(thisJoinPoint, "   Parent+");
       }
       void print(JoinPoint jp, String label) {
               Signature signature = jp.getSignature();
               int line = jp.getStaticPart().getSourceLocation().getLine();
               System.err.println(label
               + " ["  + line
               + "] tjp=" + jp.hashCode()
               + "] this=" + jp.getThis()
               + ", declaringType=" + signature.getDeclaringTypeName()
               + ", " + ((ConstructorSignature)signature).getConstructor());
       }

 
}
 
------------Original Message------------
From: Matthew Webster <matthew_webster@xxxxxxxxxx>
To: aspectj-dev@xxxxxxxxxxx
Date: Tue, Sep-19-2006 6:14 AM
Subject: [aspectj-dev] AspectJ Runtime: Signatures for interface initialization and type staticinitialization

This discussion relates to https://bugs.eclipse.org/bugs/show_bug.cgi?id=157054. I have also found https://bugs.eclipse.org/bugs/show_bug.cgi?id=49295 and https://bugs.eclipse.org/bugs/show_bug.cgi?id=60936 which concern the removal from the language of the interface constructor execution pcd. Unfortunately the documentation for this part of the API is terse and the tests almost non-existent so it is very difficult to determine the intended behaviour. One thing I am sure of: we should not return null.


There seems to be a discrepancy between classes and interfaces when it comes to the initialization join point. In the example below we advise the initialization of a single class both as an extender of Parent and an implementer of Interface:


public
class Test extends Parent implements Interface {

       
public static void main(String[] args) {
               
new Test();
       }


}


public
interface Interface {
}


public
class Parent {
}


public
aspect Aspect {

       
before () : (initialization(Interface.new()) || initialization(Parent+.new())) && !within(Parent) {
               Signature signature =
thisJoinPoint.getSignature();
               System.err.println(
"Aspect.before() this=" + thisJoinPoint.getThis()
               +
", signature=" + signature.getClass()
               +
", declaringType=" + thisJoinPoint.getSignature().getDeclaringTypeName()
               +
", " + ((ConstructorSignature)signature).getConstructor());
       }


}


However the output in each case is different:


Aspect.before() this=Test@1833955, signature=class org.aspectj.runtime.reflect.ConstructorSignatureImpl, declaringType=Test, public Test()

Aspect.before() this=Test@1833955, signature=class org.aspectj.runtime.reflect.ConstructorSignatureImpl, declaringType=Interface, null


Firstly while the declaring type for a class initializer is the target class in the case of the interface it is not. Secondly an interface cannot have a constructor. There are two possible solutions:

1. Make the implementing type the declaring type and remove the discrepancy between class and interface.

2. Return an InitializerSignature instead of a ConstructorSignature. Unfortunately this interface has getInitializer() which also returns a java.lang.reflect.Constructor. What is slightly bizarre is that this interface is also used for staticinitializer join points and in this case the interface returns the signature for the default constructor of the target class!


Matthew Webster
AOSD Project
Java Technology Centre, MP146
IBM Hursley Park, Winchester,  SO21 2JN, England
Telephone: +44 196 2816139 (external) 246139 (internal)
Email: Matthew Webster/UK/IBM @ IBMGB, matthew_webster@xxxxxxxxxx
http://w3.hursley.ibm.com/~websterm/

_______________________________________________
aspectj-dev mailing list
aspectj-dev@xxxxxxxxxxx

https://dev.eclipse.org/mailman/listinfo/aspectj-dev _______________________________________________
aspectj-dev mailing list
aspectj-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-dev


Back to the top