Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] adding interface to classes in jars that already have interface implementation

Thanks for the help Andy.  I ended up going back to the project that generates the incoming jar and applying the new interfaces with aspects there so when they get to the dependent project, no weaving is necessary as everything needed is already built into the incoming jar.

On Thu, Oct 26, 2017 at 11:07 AM, Andy Clement <andrew.clement@xxxxxxxxx> wrote:
Hey,

So sorry! I noticed I wrote this the other day but have left it in draft, finally sending now...

What you are doing looks OK but as you surmise your new code will only work if the aspect has had a chance to apply.  Let’s step through it. I’ll use real code:

=== 8< ==== A.java ======
public interface A {}

=== 8< ==== Impl.java ======
public class Impl implements A {}

Let’s build those:

ajc -1.9 A.java Impl.java -outjar original.jar



=== 8< ==== A.java ======
public interface B {}

Let’s build our new interface:
ajc -1.9 B.java -outjar b.jar


=== 8< ==== Azpect.java ======
aspect Azpect {
        declare parents: A+ implements B;
}

=== 8< ==== Test.java ======
public class Test {
  public static void main(String []argv) {
     A impl = new Impl();
     B b = impl;
  }
}


So the Test program will only compile if the aspect can make the change it needs to:

ajc -1.9 -classpath ../aspectjrt.jar:original.jar:b.jar Test.java Azpect.java
Azpect.java:2 [warning] this affected type is not exposed to the weaver: A [Xlint:typeNotExposedToWeaver]
declare parents: A+ implements B;
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        [Xlint:typeNotExposedToWeaver]
Test.java:4 [error] Type mismatch: cannot convert from A to B
B b = impl;

Notice here, it can’t. Because A.java is on the class path, it does not get woven (we need to write out a new version of A that extends B).

(Yes, in this case "A+ implements B" is being implemented as changing A to make it extend B rather than changing all implementors of A to also implement B).

There are a few options for tackling this. Perhaps the cleanest/simplest is to modify the jar with our changes before using it:

ajc -1.9 -inpath original.jar -outjar new.jar Azpect.java B.java -showWeaveInfo
Extending interface set for type 'A' (A.java) to include 'B' (Azpect.java)

Now we can use it:

ajc -1.9 -classpath ../aspectjrt.jar:new.jar Test.java

java -classpath new.jar:. Test

Works OK

We could get it to compile all in one go by combining those steps:

ajc -1.9 -inpath original.jar Azpect.java B.java Test.java -showWeaveInfo
Extending interface set for type 'A' (A.java) to include 'B' (Azpect.java)

java -classpath . Test

This works because we are making A/Impl available to the weaver as candidates for change by passing them on the inpath. But you are left with a mess of everything in the target folder.  You could use -outjar here but your test will then all be in your output jar.

I hope that helps explain what is happening.

Andy

> On Oct 21, 2017, at 12:18 PM, Jason Britton <jbritton31@xxxxxxxxx> wrote:
>
> Hi -
> I've got a bunch of generated classes across multiple jars that I cannot change the source on, nor can I change how they are generated.  These generated classes all implement interface "A"
>
> I'd like to add another interface to all these generated classes to make use of a handful of other methods they all already implement.  Essentially I'd like to simply add in another "implements B" to their definitions at compile time.  I've defined "B" interface and my aspect looks like this:
>
>       public aspect ImplementBInterfaceAspect {
>
>       declare parents : A+ implements B;
>
>       }
>
> Does that look correct?  I wrote some code that I thought would correctly prove the new "implements B" was being weaved in correctly.  That code looks like:
>
>       // C implements A by source code definition, and should have be known to "implements B" due to weaving of the aspect defined above
>       C cInstance = new C();
>
>       // B is an interface, cInstance should be known to implements B if weaving is taking place
>       B refToCInstance = cInstance;
>
> The code above doesn't compile.  Complaining that cInstance cannot be assigned to refToCInstance.  I'm now realizing that weaving must not happen until after all existing code is already compiled??  Sorry for my beginner's understanding of AspectJ.  What would be a better test to validate that my desired weaving is happening?
>
> Thank you any clarity you can provide.
>
> Jason
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> To change your delivery options, retrieve your password, or unsubscribe from this list, visit
> https://dev.eclipse.org/mailman/listinfo/aspectj-users

_______________________________________________
aspectj-users mailing list
aspectj-users@xxxxxxxxxxx
To change your delivery options, retrieve your password, or unsubscribe from this list, visit
https://dev.eclipse.org/mailman/listinfo/aspectj-users


Back to the top