Note: this page is very dated at the moment. If you are interested in an AspectJ version of this aspect, please visit the Handy-Aspects project on
Java.netGitHub.In the near future, a more refined JBoss AOP version will be released in that project as well. The JBoss AOP version will no longer be maintained and any future work will be based on AspectJ. You can follow that work on GitHub here.
Like some, I was wondering if there is there a practical use for AOP outside of the typical logging and transaction examples? I recently came accross a situation where I realized I had a cross-cutting concern and I figured I’d see if I could create an aspect to address it. I had 29 classes I created for an application that uses Hibernate. These classes were nothing more that value objects with simple setter and getter methods. I was going to use these classes in a Swing application. Additionally, I was looking into the JGoodies Binding framework to ease binding data to GUI components. JGoodies Binding requires that your beans support bound properties and my classes did not. I didn’t want to have to update every class in my application as it would have required a lot of extra testing. So I starting looking deeper into AOP frameworks to see what could be done.
Solutions
Before getting itno the aspect, lets cover what needs to be done get the classes to support bound properties. There’s not much to it really, you can simply add a field to your class that holds an instance of
PropertyChangeSupport, as well as the two methods to add and remove listeners, preferably:
addPropertyChangeListenerremovePropertyChangeListener
JGoodies looks for the presence of these two methods in order to verify that the bean support s bound properties. Additionally, in all your setter methods, you should compare the new value to the current value and fire a property change event if the values are different. While this isn’t a terribly difficult task, the amount of effort in adding this new behavior to your POJOs grows with the number of classes you have to change times the number of properties in each each class. If you have existing classes that don’t support bound properties but now need to, updating each one individually could take a while. Additionally if you don’t have access to the sources, you’d have to develop a proxy, or sub-class, that can handle bound properties.
The Aspect
I really didn’t love the idea of adding a whole bunch of new code my existing classes that already worked just fine. I started to tinker with the JBoss AOP framework and realized that I could create an aspect that could make my classes support bound properties without having to change the code. By using an introduction, you can force a Java class to implement an interface. Additioanlly, you can also define a mixin class that will provide an implementation to support your introduction. I ended up with what I call the JavaBeanAspect, since it will make a regular value object a propert JavaBean. The JavaBeanAspect is based on the the GOFObservable aspect found on the JBoss wiki. The concepts in this aspect were what I wanted, but it did nothing to support the JavaBean specification. So with the GOFObservable aspect in mind, I started designing an aspect that would do the following:
- Introduce JavaBean style behavior to POJOs
- Support Java 5 annotations, beans marked
@Observablewould automatically inherit this behavior - By default, all fields of the advised class are bound.
- Fields marked
@NotBoundwill not fire property changes. - Fields marked
@Constrainedwill fire vetoable property changes. Below is a class diagram depicting the architecture of the aspect:
*Note: AOP UML notation taken from Renaud Pawlak’s research report: A Notation for Aspect-Oriented Distributed Software Design * The JavaBeanAspect defines the introduction, which declares that the advised class will implement the JavaBean interface. It also defines a mixin class, JavaBeanMixin, which provides the default implementation of the JavaBeaninterface. The JavaBeanMixinclass would be the equivent of adding PropertyChangeSupportplus the addPropertyChangeListener, and removePropertyChangeListenermethods to your existing class. The PropertyChangeAspectis responsible for firing change events for all classes that are advised by the JavaBeanAspect. Whenever a field value changes,this aspect will determine weather or not to fire an event. And finally, we have the @ValueBeanannotation that is used to mark classes that you want to apply the aspect to. You can download the source code (Java 5 required) here:
How to Use it
Currently, this aspect works only with Java 5. Using it in your code is quite simple, you can simply annotate your class with the
@Observable annotation, compile it with AopC, and your classwill now support bound properties. Here’s an example:
@Observable
public class ValueObject {
private String name;
private String description;
private int value;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getValue() {
return value;
}
public void setValue(int value) {
this.value = value;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}
If you can’t or don’t want to annotate the classes because you either don’t like annotaions or you don’t have access to the sources, you can also apply the advice using an XML descriptor:
< ?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<aop>
<aspect class="com.damnhandy.aspects.bean.PropertyChangeAspect"
scope="PER_VM"/>
<bind pointcut="set(* ValueObject->*)">
<advice name="fieldChangeAdvice"
aspect="com.damnhandy.aspects.bean.PropertyChangeAspect"/>
</bind>
<introduction class="ValueObject">
<mixin>
<interfaces>com.damnhandy.aspects.bean.JavaBean</interfaces>
<class>com.damnhandy.aspects.bean.JavaBean</class>
<construction>new com.damnhandy.aspects.bean.JavaBeanMixin(this)</construction>
</mixin>
</introduction>
</aop>
By contrast, this is how the same class might might look if coded in a more traditional fashion:
public class ValueObject {
private String name;
private String description;
private int value;
private PropertyChangeSupport pcs = new PropertyChangeSupport(this);
public String getName() {
return name;
}
public void setName(String name) {
String oldName = getName();
this.name = name;
firePropertyChange("name",oldName,name);
}
public int getValue() {
return value;
}
public void setValue(int value) {
int oldValue = getValue();
this.value = value;
firePropertyChange("value",oldValue,value);
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
String oldDescription = this.getDescription();
this.description = description;
firePropertyChange("description",oldDescription,description);
}
private void firePropertyChange(String propertyName,
Object oldValue, Object newValue)
{
if (oldValue == null && newValue != null ||
!oldValue.equals(newValue)) {
this.pcs.firePropertyChange(propertyName, oldValue, newValue);
}
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
public void addPropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
public void removePropertyChangeListener(String propertyName,
PropertyChangeListener listener) {
pcs.removePropertyChangeListener(propertyName, listener);
}
}
The two versions of this class will behave the exactly same way. The big difference here is the amount of code that needs to be added to the class in order to support bound properties. The advised class contains half as many lines of code than the non-advised class. Admittely, the non-advised class could benefit by extending a base class, such as the JGoodies
Modelclass, that would provide the base implementation for bound properties. However, no base class can aleviate the donkywork involed in firing the property change events within every setter method. This is where I think the aspect approach really excells.
The Aspect in Action
Since my motivation around this aspect started with my need to make classes work with the JGoodies Binding framework, I have prepared an example using some tutorial code from the JGoodies Binding tutorial. I chose the
CommitStylesExample as it was the simplest example in the bunch. Both examples use Java Web Start and require Java 5 and they both use a self-sign certificate. Here’s the original example:
CommitStylesExample Orginal
And here’s the advised version:
CommitStylesExample with JavaBean Aspect
As you can see, there’s no difference in behavior between the two examples, nor should there be. The only difference is in the code, which you can download here:
JavaBeanAspect Eclipse Project
Considerations
While JBoss AOP can save you a lot of time and effort, there are some things you should take into consideration:
- The JBoss AOP runtime will add about 2.4MB to your application. This is quite a lot for a WebStart application or applet.
- Using JBoss AOP in a Web Start application is challenging. I have not been able to get loadtime weaving working, nor have I been successful using annotated aspects to work in a Web Start app. No matter what I try, Web Start can’t seem to properly read the
jboss.aop.class.pathproperty. These Web Start demos use the XML configuration that gets placed in the META-INF folder - It was a pain in the ass to set up
But once it’s working, it’s several time easier than updating every setter in every class. -
You can use this aspect with existing class files, you do not need the sources. You’ll need to assess you own situation to see if an AOP framework can be of value to you. Personally, I’ve found JBoss AOP to be incredibly useful asset in my work. The more you understand how to identify cross-cutting concerns, the more useful AOP can become. As for the JavaBeanAspect, there’s still some work to do. For example:
-
The name of the Aspect will probably change. “JavaBean” doesn’t fully convey what the aspect does. Any suggestions?
- Adder methods(i.e.
Order.addItem(Item item)), and other methods that might alter an internal collection or other value, currently won’t trigger change events. - Tweak the pointcut so that change events are not fired when set in a constructor. This usually isn’t preferred behavior.
- The
@NotBoundannotation should be handled through a pointcut expression rather than in code. - Similarly,
@Constrainedfields should have it’s own advice and bound to a pointcut expression - Not sure if vetoable change support is totally appropriate in an aspect
- Implement the same aspect using AspectJ 5 to compare against JBoss AOP Hopefully, this can illustrate how aspects can be used to assist you in solving a real-world problem.






Pingback: DamnHandy : Archive » ValueBean Aspect and AspectJ 5
Pingback: My Weblog