Inspired by a post Chris (aka Kolszew) entitled JavaBeans - bad idea pl.comp.lang.java decided to prepare an example demonstrating the use of Aspect Oriented Programming (specifically AspectJ) to solve the problem presented by Chris. I'm interested in getting
setter selected classes of behavior is identical with the following words:
void setText (String txt) {String oldValue =
this.text;
this.text = txt;
propertyChangeSupport.firePropertyChange ("text", oldValue, txt );}
without adding in any setterze first and third of these lines of code.
The first step is to create the project. Plugin AJDT (AspectJ Development Tools ) to the Eclipse AspectJ project allows the creation of (New-> Project AspectJ) containing immediately hooked bilbioteki AJ.
I create a base class for classes of model that provides a method firePropertyChange which simply delegates the call to a private field of type PropertyChangeSupport.
import java.beans.PropertyChangeSupport;
BaseModelObject {public class
private PropertyChangeSupport propertyChangeSupport = new PropertyChangeSupport (
this);
public void firePropertyChange (final String propertyName, Object oldValue
final, final Object newValue) {
propertyChangeSupport.firePropertyChange (propertyName, oldValue, newValue
);
}}
Let's test a class that inherits from BaseModelObject:
pl.kadamczyk.ajpropertychange.model package;
public class extends SomeModelObject BaseModelObject {private String
someStringProperty;
private int someIntProperty;
getSomeStringProperty public String () {return
someStringProperty;
}
public void setSomeStringProperty (final String someStringProperty) {
this.someStringProperty = someStringProperty;
} public int
getSomeIntProperty () {return
someIntProperty;
} public void
setSomeIntProperty (final int someIntProperty) {
this.someIntProperty = someIntProperty;
}}
It is the coolest moment: create aspect of who is responsible for invoking the method firePropertyChange class BaseModelObject:
pl.kadamczyk.ajpropertychange.aspects package;
pl.kadamczyk.ajpropertychange.model import. BaseModelObject;
public aspect PropertyChangeAspect {
/ **
* We define "place" where applied shall Tip
* /
pointcut callSetter (Object target, Object param): target (target) & & args (arg) & &
execution ( void set pl.kadamczyk.ajpropertychange.model .*. *(..));
/ ** * Tip type
around - to execute code before and after appropriate
* method is called.
* * /
Object around (Object target, Object newval): callSetter (target, newval) {String
jointPoint = ThisJoinPoint.getSignature (). GetName ();
/ / Specify the name of the field induced by the name of the setter
String fieldName = jointPoint.replaceFirst ("set", "");
fieldName = Character.toLowerCase (fieldName.charAt (0 )) +
fieldName.substring (1);
try {Class clazz =
target.getClass ();
/ / grab the box before the scheduled class called
java.lang.reflect.Field field = clazz.getDeclaredField (fieldName );
field.setAccessible (true);
/ / grab the old value Object oldValue
field field.get = (target);
/ / allow to call setter
Object result = proceed (target, newval);
triggerPropertyChange (target, newval, oldValue, fieldName);
return result;
} catch (NoSuchFieldException e) {throw new RuntimeException
(e);
} catch (IllegalArgumentException e) {throw new RuntimeException
(e);
} catch (IllegalAccessException e) {throw new RuntimeException
(e);}
} / ** * Checks
whether the method was performed on object class that inherits from the BaseModelObject
*, and if so, calls on him firePropertyChange
* / private void
triggerPropertyChange (final Object target, Object newval
final, final Object oldValue, final String fieldName) {
System.out.println ("Changing the value of field" + fieldName);
if (target instanceof BaseModelObject)
{/ / call the method from the base class
((BaseModelObject) target). firePropertyChange (fieldName, oldValue,
newval);
}}}
Defined call pointcut specifies all methods in all classes in package pl.kadamczyk.ajpropertychange.model name that begins with "set" and the return type "void". Defining
Tips (advice) of the type around allows you to perform operations both before and after the proper method to liberate calling proceed () .
also deserves a special variable used thisJoinPoint - this is an analogy to the standard Javowego this - this variable may be used only in the context of counseling (advice). It contains many przydatnich information about the current Join Point, which is in our case caused by a particular setter. In particular, calling:
thisJoinPoint.getSignature (). GetName () returns the name of the currentlymethod invoked by the set *.
To see the result of the above aspect run a simple class with a method main () :
pl.kadamczyk.ajpropertychange.launcher package;
import pl.kadamczyk.ajpropertychange.model.SomeModelObject;
public class Launcher {public static
void main (final String [] args) {
SomeModelObject SomeModelObject mo = new ();
mo.setSomeIntProperty (23);
mo.setSomeStringProperty ('ala has a cat ");}
}
to get the console output:
Change the value of field someIntProperty
Change the value of field someStringProperty
We note at the end - This code will not work with the appropriate manager fired security, because it will not allow the method call setAccesible (true) on the fields.
Taking this into account in a different way to get the value of the field - here I used a 'hack' with the method setAccesible because it was the fastest;)
0 comments:
Post a Comment