> Of course, this is hard to detect by a compiler such as Ajc, but if there was > an option to force inlining the around advice for the constructor, this > scheme would work. So my questions are: > > Is there such an option? I did not find any obvious compiler switch. > If not, do you see any chance to implement it, given technical feasibility? The only force option you have is -XnoInline which forces the opposite of what you want ;)
Not 100% sure but the check about who can initially set some of those fields seems more policed lately than in older versions of Java. (There have been a few bugs reported about the ajc specific static initializer block setting final static fields that never triggered an access error before. I hadn’t seen it with instance fields though until you showed this). What version of Java are you trying it on? Did you try it on Java 8 to compare? (Just out of interest, I’m not saying that is the fix). I suspect we do need to do more inlining to fix this across the board. Cheers, Andy > On May 21, 2020, at 2:52 AM, Alexander Kriegisch <alexan...@kriegisch.name> > wrote: > > Hi Andy. > > Today I got a tricky one. I thought about opening a Bugzilla ticket, but this > is actually more of a question, maybe a future feature request if what I want > is technically possible at all. So it depends on your answer if I shall open > a ticket or not. > > The requirement is simple (to explain, not to implement): I want to > around-advise constructors in order suppress any side effects from happening > there. The purpose would be to (ab)use AspectJ in order to create some kind > of mock object which does not do anything expensive while being constructed. > BTW, actually I am thinking about doing this with a library like ASM, but > first I wanted to play with AspectJ in order to see what is possible there > and create a proof of concept. But let me not get ahead of myself and set the > stage first: > > > package de.scrum_master.app; > > public class Base { > protected final int id; > > public Base(int id) { > System.out.println("Constructing Base -> " + this); > this.id <http://this.id/> = id; > } > } > package de.scrum_master.app; > > public class Sub extends Base{ > private final String name; > > public Sub(int id, String name) { > super(id); > System.out.println("Constructing Sub -> " + this); > this.name = name; > } > > @Override > public String toString() { > return "Sub@" + this.hashCode() + " [name=" + name + ", id=" + id + "]"; > } > } > package de.scrum_master.app; > > public class AnotherSub extends Base{ > private final String name; > > public AnotherSub(int id, String name) { > super(id); > System.out.println("Constructing AnotherSub -> " + this); > this.name = name; > } > > @Override > public String toString() { > return "AnotherSub@" + this.hashCode() + " [name=" + name + ", id=" + id > + "]"; > } > } > package de.scrum_master.aspect; > > import de.scrum_master.app.Base; > import de.scrum_master.app.Sub; > > public aspect ConstructorAspect { > void around() : execution(Base+.new(..)) && target(Sub) { > return; > } > } > package de.scrum_master.app; > > public class Application { > public static void main(String[] args) { > System.out.println(new Sub(11, "Xander")); > System.out.println("----------"); > System.out.println(new AnotherSub(22, "Someone")); > } > } > > As you can see, I did the following: > > Create a base class Base with two subclasses Sub and AnotherSub. > The aspect tries to > suppress constructor execution for one Sub (with the intent to "mock" it, > just imagine its methods get advised by additional behaviour), > but not for AnotherSub (not a mock target) of the subclasses. > The aspect does this by > making sure that super class constructors are also suppressed via > execution(Base+.new(..)), > excluding anything that is not the target type via target(Sub) and finally > simply not proceeding to the constructor by just returning from the around > advice. > Now this works beautifully whenever creating a Sub instance, but fails > whenever creating an AnotherSub instance: > > > Sub@1211076369 [name=null, id=0] > ---------- > Constructing Base -> AnotherSub@1551870003 [name=null, id=0] > Exception in thread "main" java.lang.IllegalAccessError: Update to non-static > final field de.scrum_master.app.Base.id <http://de.scrum_master.app.base.id/> > attempted from a different method (init$_aroundBody0) than the initializer > method <init> > at de.scrum_master.app.Base.init$_aroundBody0(Base.java:8) > at de.scrum_master.app.Base.<init>(Base.java:6) > at de.scrum_master.app.AnotherSub.<init>(AnotherSub.java:7) > at de.scrum_master.app.Application.main(Application.java:7) > > The explanation is pretty straightforward if we look at the console log and > the class definitions: > > The Base class has a final instance field. > AspectJ factors the Base constructor code out into a private helper method > Base.init$_aroundBody0 and dispatches to it from the instrumented constructor > Base.<init> instead of initialising the field directly from there. > While this does no harm for the "mock target" class Sub because there the > helper method is never called (the no-op around advice kicks), > it fails miserably when creating an AnotherSub instance because then the > helper method does get called but a helper method must not violate the JVM > rule that final fields can only be initialised directly from a constructor > (or during declaration). > Of course, this is hard to detect by a compiler such as Ajc, but if there was > an option to force inlining the around advice for the constructor, this > scheme would work. So my questions are: > > Is there such an option? I did not find any obvious compiler switch. > If not, do you see any chance to implement it, given technical feasibility? > > Best regards > > -- > Alexander Kriegisch > https://scrum-master.de <https://scrum-master.de/> > > _______________________________________________ > aspectj-users mailing list > aspectj-users@eclipse.org <mailto:aspectj-users@eclipse.org> > To unsubscribe from this list, visit > https://www.eclipse.org/mailman/listinfo/aspectj-users > <https://www.eclipse.org/mailman/listinfo/aspectj-users>
_______________________________________________ aspectj-users mailing list aspectj-users@eclipse.org To unsubscribe from this list, visit https://www.eclipse.org/mailman/listinfo/aspectj-users