Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Question about interface inheritance and introduction


2009/8/14 Matthew Adams <matthew@xxxxxxxxxxxxxxx>
OK, put your thinking caps on for this one.  I'm getting introductions
on a type that doesn't match the declare parents type _expression_.

Consider the following Java artifacts, all defined in a package called
"example":

public class Foo() {}
public class Bar() {}

public interface HasFoo { Foo getFoo(); }
public interface HasBar extends HasFoo { Bar getBar(); }

public @interface Fooable {} // assume target is TYPE and retention RUNTIME
public @interface Barable {} // assume target is TYPE and retention RUNTIME

@Fooable public class MyFooable {}

@Barable public class MyBarable {}

Now, consider that I want to introduce an implementation of HasFoo to
classes annotated with @Fooable:

public aspect HasFooIntro {
       declare parents: (@Fooable *) implements HasFoo;

       private boolean HasFoo.returnNull = false;

       public Foo HasFoo.getFoo() {
               Foo foo = returnNull ? null : new Foo();
               returnNull = !returnNull;
               return foo;
       }
}

...and HasBar to classes annotated with @Barable:

public aspect HasBarIntro {
       declare parents: (@Barable *) implements HasBar;

       public Bar HasBar.getBar() {
               return getFoo() == null ? new Bar() : null;
       }
}

When the compiler completes processing, I end up with expected results
when I call "javap example.MyFooable":

Compiled from "MyFooable.java"

public class example.MyFooable
   extends java.lang.Object
   implements example.HasFoo
{
   public boolean ajc$interField$example_HasFooIntro$example_HasFoo$returnNull;
   public example.MyFooable();
   public boolean
ajc$interFieldGet$example_HasFooIntro$example_HasFoo$returnNull();
   public void
ajc$interFieldSet$example_HasFooIntro$example_HasFoo$returnNull(boolean);
   public example.Foo getFoo();
}

However, when I call "javap example.MyBarable", I get unexpected
results.  Even though the type _expression_ in HasFooIntro's "declare
parents" doesn't match MyBarable, the introduced methods and fields of
HasFooIntro are present in MyBarable:


Question:  How did the ITDs in HasFooIntro make it into MyBarable?
I'm confused because the declare parents type _expression_ of
HasFooIntro didn't match MyBarable, yet the HasFooIntro's
introductions are present in MyBarable.
 

Once

  declare parents: (@Barable *) implements HasBar;

causes MyBarable to implement HasBar, the hierarchy for MyBarable includes HasFoo - so:

  declare parents: (@Fooable *) implements HasFoo;

doesn't match because HasFoo is already there (since HasBar extends HasFoo).  Same as

aspect X {
  declare parents: C implements java.io.Serializable
}

class C implements java.io.Serializable {
}

doesn't show anything happening

ITD fields/methods on interfaces are put into the 'top most implementor' of the interface that is visible.  In the HasFoo>HasBar>MyBarable case then MyBarable is the top most implementor where they can be added.

Your output was:

fooable.getFoo():example.Foo@
de6ced class example.Foo
fooable.getFoo():null (no class)
barable.getFoo():example.Foo@1fb8ee3 class example.Foo
barable.getFoo():null (no class)
barable.getBar():null (no class)
gooable.getFoo():example.Goo@10b30a7 class example.Goo
gooable.getFoo():example.Goo@1a758cb class example.Goo
gooable.getBar():null (no class)

would be useful to know what you were expecting to see?

As far as I can see

fooable.getFoo():example.Foo@de6ced class example.Foo // as expected because the returnNull flag is false, the flag is flipped

fooable.getFoo():null (no class) // as expected because the returnNull flag is true, the flag is flipped

barable.getFoo():example.Foo@1fb8ee3 class example.Foo // as expected because the returnNull flag is false
barable.getFoo():null (no class) // as expected because the returnNull flag is true, the flag is flipped
barable.getBar():null (no class) // as expected because getFoo() called underneath will return non-null, so getBar() returns null

gooable.getFoo():example.Goo@10b30a7 class example.Goo // as expected because Gooable.getFoo() returns new Goo
gooable.getFoo():example.Goo@1a758cb class example.Goo // as expected because Gooable.getFoo() returns new Goo
gooable.getBar():null (no class) // as expected because getFoo() returns an instance, so getBar() returns null

what did you want it to do?

cheers,
Andy


 


Now, let's say that I want to allow the author of a class annotated
with @Barable to provide its own getFoo() method (required by HasFoo,
the superinterface of HasBar) with a new implementation that returns a
Goo:

public class Goo extends Foo {}

@Barable
public class MyGooable {
       public Foo getFoo() {
               return new Goo();
       }
}

Given this new class, when I call "javap example.MyGooable", I get the
following results:
 

When I run the following class, I get the results shown below.

public class Main {

       public static void main(String[] args) {
               Foo foo = null;
               Bar bar = null;

               MyFooable fooable = new MyFooable();
               foo = fooable.getFoo();
               System.out.println("fooable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));
               foo = fooable.getFoo();
               System.out.println("fooable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));

               MyBarable barable = new MyBarable();
               foo = barable.getFoo();
               System.out.println("barable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));
               foo = barable.getFoo();
               System.out.println("barable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));
               bar = barable.getBar();
               System.out.println("barable.getBar():" + bar + " "
                               + (bar == null ? "(no class)" : bar.getClass()));

               MyGooable gooable = new MyGooable();
               foo = gooable.getFoo();
               System.out.println("gooable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));
               foo = gooable.getFoo();
               System.out.println("gooable.getFoo():" + foo + " "
                               + (foo == null ? "(no class)" : foo.getClass()));
               bar = gooable.getBar();
               System.out.println("gooable.getBar():" + bar + " "
                               + (bar == null ? "(no class)" :
bar.getClass()));
       }
}

Results:

fooable.getFoo():example.Foo@de6ced class example.Foo
fooable.getFoo():null (no class)
barable.getFoo():example.Foo@1fb8ee3 class example.Foo
barable.getFoo():null (no class)
barable.getBar():null (no class)
gooable.getFoo():example.Goo@10b30a7 class example.Goo
gooable.getFoo():example.Goo@1a758cb class example.Goo
gooable.getBar():null (no class)


 

Thanks for your help, especially if you read this far! :)  I'd be
happy to zip up the example and send it if you're interested.

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


Back to the top