Project: AspectJ
Bug 122370 [@AspectJ] @DeclareParents/declare parents not equivalent
Reported: 2005-12-30 00:54:07 | Status: resolved fixed

Adding a setter to the Moody example makes it clear that the annotation style (@DeclareParents) results in different behavior than the classic (declare parents) style. Calling the setter in a "declare parents"-advised object behaves as one would expect. However, calling the setter with a "@DeclareParents"-advised object has no effect -- that is, you can call the setter (and see that it's been called) and immediately call the getter, only to find that the value didn't change. The following examples (all in "package moody;") illustrate: public enum Mood { HAPPY, JOLLY } Classic style: ------------- public aspect ClassicMoodIndicator { public interface Moody { Mood getMood(); void setMood(Mood mood); } private Mood Moody.mood = Mood.HAPPY; public Mood Moody.getMood() { return mood; } public void Moody.setMood(Mood mood) { this.mood = mood; } declare parents : moody.ClassicMoodImplementor implements Moody; } public class ClassicMoodImplementor { } Annotation style: ---------------- import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.DeclareParents; @Aspect public class AnnotationMoodIndicator { public interface Moody { Mood getMood(); void setMood(Mood mood); } public static class MoodyImpl implements Moody { private Mood mood = Mood.HAPPY; public Mood getMood() { return mood; } public void setMood(Mood mood) { this.mood = mood; } } @DeclareParents(value="moody.AnnotationMoodImplementor",defaultImpl=MoodyImpl.class) private Moody implementedInterface; } public class AnnotationMoodImplementor { } JUnit TestCase: -------------- import junit.framework.TestCase; public class MoodTester extends TestCase { public MoodTester(String name) { super(name); } public void testClassic() { ClassicMoodImplementor cmi0 = new ClassicMoodImplementor(); ClassicMoodImplementor cmi1 = new ClassicMoodImplementor(); assertEquals("cmi0 should be HAPPY", Mood.HAPPY, cmi0.getMood()); cmi1.setMood(Mood.JOLLY); assertEquals("cmi1 should be JOLLY", Mood.JOLLY, cmi1.getMood()); assertEquals("cmi0 should be *still* be HAPPY", Mood.HAPPY, cmi0.getMood()); } public void testAnnotation() { AnnotationMoodImplementor ami0 = new AnnotationMoodImplementor(); AnnotationMoodImplementor ami1 = new AnnotationMoodImplementor(); assertEquals("ami0 should be HAPPY", Mood.HAPPY, ((AnnotationMoodIndicator.Moody) ami0).getMood()); ((AnnotationMoodIndicator.Moody) ami1).setMood(Mood.JOLLY); assertEquals("ami1 should be JOLLY", Mood.JOLLY, ((AnnotationMoodIndicator.Moody) ami1).getMood()); assertEquals("ami0 should be *still* be HAPPY", Mood.HAPPY, ((AnnotationMoodIndicator.Moody) ami0).getMood()); } } Result: ------ The test run is as follows: ..F Time: 0.021 There was 1 failure: 1) testAnnotation(moody.MoodTester)junit.framework.AssertionFailedError: ami1 should be JOLLY expected:<JOLLY> but was:<HAPPY> at moody.MoodTester.testAnnotation(MoodTester.java:27) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at moody.MoodTester.main(MoodTester.java:7) FAILURES!!! Tests run: 2, Failures: 1, Errors: 0 For classic, you can see that cmi1.setMood was successful and cmi0/cmi1 are decoupled (that is, calling setMood on cmi1 has no impact on cmi0). The annotation style, however, fails because ami1.setMood appears to have done nothing. The result should have been that ami1 is JOLLY and ami0 HAPPY (I include the second assert because both ami0 & ami1 ended up JOLLY in RC1). The current behavior makes @DeclareParents unusable for retaining field state (near as I can tell, it retains state throughout the method invocation, but not beyond it, like it is creating and discarding a backing object with each method invocation).

Files changed in fix:
tests/bugs151/pr122370/moody/AnnotationMoodImplementor.java tests/bugs151/pr122370/moody/AnnotationMoodIndicator.java tests/bugs151/pr122370/moody/MainClass.java tests/bugs151/pr122370/moody/Mood.java tests/src/org/aspectj/systemtest/ajc151/Ajc151Tests.java weaver/src/org/aspectj/weaver/bcel/BcelTypeMunger.java