Bug 215115 - [ataspectj] [decp] Can't advice introduced method with annotation-style
Summary: [ataspectj] [decp] Can't advice introduced method with annotation-style
Status: NEW
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.5.4RC1   Edit
Hardware: PC Linux
: P3 major (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-01-12 11:28 EST by Carlos Pita CLA
Modified: 2013-06-24 11:07 EDT (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Carlos Pita CLA 2008-01-12 11:28:44 EST
Instead what is adviced is the introduced object (maybe a delegate?). Take for example the following aspect, which is intended to after advice deserialization of objects annotated with @Injected. For this, the aspect introduces the method DeserializationSupport.readResolve() and makes the adviced class implements Serializable. readResolve() is part of the deserialization protocol, and will be invoked by the java rt during deserialization if it's there. 

@Aspect
public class InjectorAspect {

    @After("execution(* framework.injection.InjectorAspect.DeserializationSupport.readResolve()) && this(injected)")
    public void afterDeserialization(Object injected, JoinPoint jp) {
       // I get a DeserializationSupportImpl instance here :(
    }
    
    @DeclareParents(value="@framework.injection.Injected java.io.Serializable+", defaultImpl=DeserializationSupportImpl.class)
    private DeserializationSupport deserializationSupport;
    
    public interface DeserializationSupport extends Serializable {
        public Object readResolve() throws ObjectStreamException;
    }
    
    @SuppressWarnings("serial")
    public static class DeserializationSupportImpl implements DeserializationSupport {
        public Object readResolve() throws ObjectStreamException {
            return this;
        }
    }
}

What are really being intercepted are instances looking like framework.injection.InjectorAspect$DeserializationSupportImpl@b16f5f. These are not instances of the expected @Injected at all! Even if I relaxed to advice pointcut to: "execution(* *.readResolve()) && this(injected)", the only intercepted instances would still be DeserializationSupportImpl ones, never @Injected objects.

But then, rewriting the aspect in aj-style, makes it work as pretended

public aspect InjectorAspect {

    after(Object injected) :
        execution(Object DeserializationSupport+.readResolve() throws ObjectStreamException) && @this(Injected) && this(injected) {
       // I get an @Intected instance here :) !
    }
    
    declare parents: @Injected Serializable+ implements DeserializationSupport;

    interface DeserializationSupport extends Serializable {
    }

    public Object DeserializationSupport.readResolve() throws ObjectStreamException {
        return this;
    }
}

AFAICS the only difference in the second version is the extra pointcut clause "@this(Injected)". But of course if I add this clause to the annotation-style version, no joinpoint will be matched, because even the much more permisive "execution(* *.readResolve())" never makes true "@this(Injected)".

I think this is a bug because it implies there are different semantics for things that -at least from my interpretation of the docs- should be equivalent. Also, a valid use case (advicing introduced method) seems to be outside the scope of annotation-style aspects.
Comment 1 Andrew Clement CLA 2008-02-21 20:07:13 EST
I'm afraid that right now it is the documentation that is incorrect in this case.  Weaving of AspectJ constructs that modify the type system is hard in a pure Java (annotation) style.  A simple code style ITD that the aspectj compiler can easily implement has to be mapped to a mixin style interface/class implementation as you have done - because it has to keep javac happy.

I can imagine I can address this to a degree by advising the delegate method introduced into the target type - but that needs a lot of thought to ensure it is correct in all circumstances.
Comment 2 Andrew Clement CLA 2013-06-24 11:07:13 EDT
unsetting the target field which is currently set for something already released