Validation overlays using AOP
July 31st, 2007 | 7 Comments »As i mentioned in the previous entry, one of the disadvantages of overriding the paint() method for validation overlays is that you need to do it for each one of the components that can have validation errors. So, you no longer use a “pure” JTextField, for example. You either override the paint() method when you create your text field, or use a custom class that extends JTextField and overrides the paint() method. Needless to say that the impact on your UI creation code is rather large and unpleasant. Wouldn’t it be nice if you could just inject the required functionality to all Swing components?
Although i might not be the biggest fan of aspect-oriented programming (AOP), it certainly sounds like a promising approach. In fact, AOP has been shown to address other Swing-related problems by Ben Galbraith (for adding property change support on Java beans) and by Alexander Potochkin (for tracing EDT violations). Disregarding all the hype around AOP (that seems to have thankfully died over the past year), the eventual result is that you inject the functionality you need at the specific methods in your classes. In fact, i used a very similar approach in one of my look-and-feel related projects. Isn’t this exactly what we’re looking for?
Well, it almost is. The main caveat with the bytecode injection (which is the eventual result of applying aspects to the classes) is that it is done on the bytecode class that you can control. The examples mentioned above apply this technique on the application classes. Where do we want to apply this? Mostly (unless you override the paint() method) on the core JVM classes. And this is where our problem lies.
AspectJ is one of the leading implementations of AOP in Java (especially since it has joined forces with AspectWerkz some time ago). Its load-time weaving (LTW) explicitly excludes the core classes (that would be JComponent among the rest). In addition, your application most probably doesn’t call the paint() method itself (that is left to the Swing painting pipeline, and as we have seen in the discussion on the repaint managers, there is no extension point that paints a specific dirty component). And so, if you want to use AspectJ, the only other possible option is to weave the core classes at compilation time.
You can download and build Swing using the latest JDK 7.0 weekly builds. Then, you can weave your aspect into the created swing.jar and put it in front of the bootstrap classpath. While certainly doable, this approach is far from optimal. First, you bundle an extra 4.1MB jar. Second, you’re confining yourself to the specific JDK build, including all its bugs. Third, you might run into classloader problems in specialized runtime environments, such as WebStart, applets and others.
A way around the limitation of weaving core classes would be to extend all the core Swing components, override the paint() method to call the super implementation and the weave the validation overlay logic. While it will work, it is hardly an improvement over overriding the paint() directly (without the overhead hassle of using aspects); you’ll still end up not using the core components directly in your code.
While the list of Java AOP frameworks contains other options (besides AspectJ), i am not aware of another AOP-based approach that will allow weaving core classes at runtime without any limitations. If you know of any, i will be more than happy to hear about them in the comments.
Related posts:
- Validation overlays using paint() In the previous entries on painting validation overlays using repaint manager and borders i discussed...
- Validation overlays extending a specific look and feel With the last few entries essentially using the same part of the Swing painting pipeline...
- Validation overlays using borders Every core Swing component inherits the setBorder() method from the JComponent. In this entry i’m...
- Validation overlays using JXLayer To continue addressing the disadvantages of overriding paint() for showing validation overlays, this time i...
This issue comes around to bite our AOP attempts on a regular basis. Not just with Swing components, but with other core Java classes as well. To make matters worse, if you happen to use WebStart, there is no way to use custom instrumented core Java classes (asside from forking another JVM, which introduces platform specific code into your WebStart app). This makes things like Terracotta on the WebStart client side almost impossible (at least, very difficult).
You can use Cglib as (part of) an AoP framework, which you can deploy using WebStart and using the standard JVM
Oh, I can get AOP to work with WebStart on classes that I control. The issue is instrumenting core Java classes (such as those in java.* or in javax.swing.*).
BTW, I would be great if the JVM provided a standard (WebStart compatible!) way to instrument system classes.
Isn’t there a licensing issue around instrumenting the core classes, placing them in the bootclasspath? If my reading of Sun’s license servers (no pun) correctly, I don’t think you can do that prior to Java6.0 and even then, it was solely available to Intranet distribution, not for solutions distributed to anybody and everybody. Please correct me if I am wrong here, but if ability to do this type of thing is only available to certain releases, it seems important to note. We can’t all have fun with the latest and greatest releases! ;-)
Ooop. Screwed up my html bolding there… should have been a close after the ‘ra’ in Intranet! Sorry about that runnaway bold; can’t have that!
Greg, i’ve fixed the incorrect closing tag. This is indeed, a valid concern when one decides to instrument core classes, especially in pre-GPL era.