Bug 170635 - support for protected inter-type declarations
Summary: support for protected inter-type declarations
Status: RESOLVED INVALID
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: 1.5.3RC1   Edit
Hardware: PC Windows XP
: P3 enhancement (vote)
Target Milestone: ---   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2007-01-16 10:42 EST by Sergey Olefir CLA
Modified: 2007-01-31 03:59 EST (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Sergey Olefir CLA 2007-01-16 10:42:41 EST
Currently AspectJ doesn't support protected inter-type declarations.

E.g. specifying within aspect file:
protected java.lang.String Customer.getSpecialCode(){return null;}

results in:
"protected inter-type declarations are not allowed"
(this is verified under Eclipse [3.2.1 M20060921-0945] using AJDT [1.4.1.200611230655] with AspectJ [1.5.3.200611221118])

I think there are numerous valid reasons to introduce protected inter-type declaration -- e.g. I'm trying to use it for generating & injecting getters and setters into classes.

This enhancement request is actually duplicate of Bug#39457 https://bugs.eclipse.org/bugs/show_bug.cgi?id=39457 (don't know how to properly link it), but 39457 is marked as "Resolved Later" so I'm not sure anyone looks at it now [ http://wiki.eclipse.org/index.php/Bug_Reporting_FAQ#Why_is_using_RESOLVED.2FLATER_bad.3F ]
Comment 1 Matthew Webster CLA 2007-01-16 11:03:29 EST
I am not sure are asking for the same thing. The modifier on a ITD specifies visibility with respect to the declaring aspect _not_ the target type i.e. a private ITD can only be used by the declaring aspect and avoids name clashes with ITDs from other aspects. All ITDs whether public, private or even protected result in a new constructor/field/method on the target type that is public (otherwise it couldn't be referenced by the declaring aspect). Bug 39457 "support protected inter-type declarations" follows this model.
Comment 2 Sergey Olefir CLA 2007-01-16 11:52:34 EST
Well, I just tested it, and either I misunderstood you or you are not correct in saying that "All ITDs ... result in a new constructor/field/method on the target type that is public".

Code sample (three classes all in the same package):

public class BaseClass2
{
	/* empty */
}

public aspect BaseClassAspect2
{
	void BaseClass2.test() {System.out.println("Ding!");}
}

public class ExtendedBaseClass2 extends BaseClass2
{
	@Override void test() {super.test();}
}


This code compiles fine. It also executes fine (from the same package):
new ExtendedBaseClass2().test();

Now if you change visibility in Aspect to "public":
public void BaseClass2.test() {System.out.println("Ding!");}

then code won't compile anymore. Error on test() method in ExtendedBaseClass2:
Cannot reduce the visibility of the inherited method from BaseClass2

So it seems that AspectJ is capable of generating methods on target type that have less than public visibility.


However some additional testing shows that methods declared as private in Aspect file are not visible in the target type. Thanks for enlightening me about the fact that those modifiers act in respect to the declaring aspect and not the target class!

----------------

Now getting back to what I actually want :)

I'd like to be able to use ITD to inject methods (fields, constructors) into target classes with full selection of visibility with respect to the target type. I.e. I would like to be able to use aspects to e.g. declare protected (or private) getter on the target class -- thus removing getter/setter clutter from the actual class.

Seeing your comment though leads me to believe that it might be something that is not an intended use of AspectJ and thus is not likely to happen... Though I'd still like to know whether I can at least rely on methods being package-visible -- or is it some sort of bug and they are supposed to be public as per your comment.
Comment 3 Matthew Webster CLA 2007-01-17 07:21:01 EST
(In reply to comment #2)
> Well, I just tested it, and either I misunderstood you or you are not correct
> in saying that "All ITDs ... result in a new constructor/field/method on the
> target type that is public".

You are mistaken. There is no public method BaseClass2.test() only a pubic forwarding method to the aspect (which can be confirmed using javap). You will notice that to avoid "red squiggles" and the error "The method test() is undefined for the type BaseClass2" you must open ExtendedBaseClass2 with the AspectJ editor which understands the special methods added by the compiler.

As I said the modifier for an ITD determines its visibility WRT the declaring aspect. If you move the aspect into a different package you will get an error "The method test() from the type BaseClass2 is not visible" unless the ITD is declared public. You code works because the ITD test() method is visible to types in the same package as the BaseClassAspect2 aspect.

You are right when you say AspectJ is not designed to "inject methods (fields, constructors) into target classes" but separate concerns. There are many use-cases for ITDs some of which are described in the various books that are available. Typically an ITD is public and part of an interface that can be discovered and invoked by normal Java or private to the aspect and part of a larger feature such as implementing the Observer design pattern on behalf of the target class(es).

At this time _all_ ITD members are public so that they can be accesses by the declaring aspect which can be in a different package to the target type(s). The very old Bug 50195 "overriding introduced methods with default access fails" suggested changing this. However I still don't think that would help you.
Comment 4 Sergey Olefir CLA 2007-01-17 08:45:50 EST
Thanks for the in-depth info!

After reading your comments and playing around with decompiler (should've done that earlier!), I think I now more or less understand what is going on.


Well, maybe let me describe what I'm trying to do, so then you can decide whether it "fits" the AspectJ scope and whether something could be considered for future enhancements.

The actual goal I'm trying to hit is to remove getters/setters clutter from Java bean source code while still retaining the full functionality of the bean -- i.e. client classes should be able to use getters/setters but the source code should not be cluttered with them.

At the same time I need to retain an option to define your own getters/setters in case they need to be "smart". This also means that in the place where custom getters/setters are defined (preferably the same place where fields are declared) getters/setters for other bean properties should be available.

And I want to be IDE-friendly (Eclipse in my case) -- meaning that code completion, javadoc documentation, etc. should all work when writing client classes.

My first idea after learning a bit about AspectJ and after seeing the availability of e.g. https://handyaspects.dev.java.net/ was to use AspectJ to simply generate/introduce required methods into my bean classes. I quickly learned though that it is impossible to dynamically generate methods based on field signatures using AspectJ.

Then I decided to combine APT code generation and AspectJ. APT would generate AspectJ files that would use ITD to inject getters/setters into my bean classes. I discovered that current AspectJ support in AJDT is lacking though -- code completion doesn't work for introduced methods -- so I actually went for generating two classes -- AspectJ aspect to inject abstract getters/setters into my bean class (also abstract) and subclass that contains actual implementation of the said getters/setters (the subclass would actually be used by the client code).

This is when I discovered all the peculiarities when attempting to use non-public ITDs :)

------------------------

I think I can still achieve what I want with APT & AspectJ. I would use AspectJ "declare parents" to make my java beans to extend abstract generated class containing getters/setters declarations (instead of trying to inject methods directly in the java bean). And I would also auto-generate class extending my (abstract) java bean and providing actual implementations of the getters/setters -- this way getters/setters will be available within java bean code if needed while being separated into different classes.

-----------------------

This is sort of turning into off-topic discussion now. Feel free to close this enhancement request if you feel there's nothing rational that can be considered for implementation in AspectJ.
Comment 5 Matthew Webster CLA 2007-01-17 09:39:45 EST
I think you have discovered that AspectJ _can_ deliver what you want but your problems and this enhancement stems from the (current) shortcomings in AJDT. Bug 74419 "Improve code completion support" currently documents the situation. I think we should close this bug but I strongly recommend posting your last comment to the aspectj-users list where it may stimulate discussion and perhaps a solution!
Comment 6 Sergey Olefir CLA 2007-01-31 03:59:03 EST
Much of this "bug" report is based on my misunderstanding of the AspectJ.

Maybe this can be re-made as "feature request" but this is certainly not a bug.