Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[aspectj-users] How to introduce a really final member via ITD

Hello,

I'm trying to find a way to introduce a member in another type via ITD but making sure it is safe published. According to the Java Memory Model, all final fields are guaranteed to be safe published after the constructor execution ends and everything not final is not guaranteed to ever be seen by another threads, so if I don't want to make use of synchronization I better make sure my things are final.. For the use case I have in hand, I'm trying to make a Runnable keep some information from the thread in which it was created and make it available to the thread in which it will be later run, a stub of what I did is this:

Aspect:
privileged public aspect ContextAware {
    private final TraceContext MyRunnable.context = TraceContext.current();
}

Runnable (scala code, also tried java and the effects are the same):
class MyRunnable extends Runnable {
  def run() {}
}

so far so good, but de-compiling the weaved MyRunnable class showed me something pretty different to what I was expecting:

public class MyRunnable
    implements Runnable
{
    public void run()
    {
    }

    public MyRunnable()
    {
        ContextAware.ajc$interFieldInit$kamon_instrumentation_ContextAware$kamon_instrumentation_MyRunnable$context(this);
    }

    public static TraceContext ajc$get$context(MyRunnable myrunnable)
    {
        return myrunnable.context;
    }

    public static void ajc$set$context(MyRunnable myrunnable, TraceContext tracecontext)
    {
        myrunnable.context = tracecontext;
    }

    private TraceContext context;
}

The "context" member in the weaved class is not final and the delegation on ajc$... for initializing the field seems unnecessary.. If it is a ITD member and the weaver is already putting some code inside the constructor to initialize a field that is supposed to be final, why the weaver is not just leaving the field as final and putting "context = TraceContext.current()" instead of "ContextAware.ajc$...." in the constructor?.. Maybe I'm doing something wrong, or I have wrong assumptions on how aspectj works.

I also tried using a perthis aspect with the context member in it and even while in that case the aspect constructor looks exactly how I expected it to be, I couldn't get to understand if the binding between the aspect instance and the runnable instance happens in a way that make sure it will be available to other threads.

The only way in which I managed this to work as I needed was to declare a parent class for MyRunnable which for this case works fine, but as soon as the target class extends another class then this is no longer viable... even the common pattern of declaring a empty interface, introducing members to it and the declare it as parent produces non-final members.. I hope that someone can help me with this!

best regards,

Ivan


Back to the top