[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
[aspectj-users] field pointcut based on field annotation
|
A long while back this topic came up
(http://dev.eclipse.org/mhonarc/lists/aspectj-users/msg03752.html). I
could really use this. I'm trying to define declarative change event
publishing, which works great for simple setter/getter fields. But for
things like lists and maps it breaks down. What I want to do is:
@EventPublisher
public static class PublisherA {
private Map<String, String> nonEventMap = new HashMap<String,
String>();
@PublishEvent
private Map<String, String> eventMap = new HashMap<String,
String>();
...
}
Where changes to 'eventMap' result in an event while changes to
'nonEventMap' do not. I am able to do this but its not pretty. If
aspectj were to handle this, would be more performant that what I am
doing below?
-barry
-------
@Pointcut("call(* java.util.Map+.put(..)) "
+ "&& @within(com.foliofn.infra.event.annotation.EventPublisher)"
+ "&& this(bean) && target(map) && args(key, value)")
@SuppressWarnings("unchecked")
void mapPropertyPut(Object bean, Map map, Object key, Object value) {
}
@Around("mapPropertyPut(bean, map, key, value) &&
!withinPublisherCreation()")
@SuppressWarnings("unchecked")
public Object fireMapPutEvent(Object bean, Map map, Object key,
Object value, ProceedingJoinPoint pjp) throws Throwable {
Object result = pjp.proceed();
Field field = getMapField(bean, map);
if (field != null) {
System.err.println(String.format("*** fireMapPutEvent:
map=%s.%s%s << [%s:%s]", bean.getClass().getSimpleName(),
field.getName(), map, key, value));
}
return result;
}
private Map<Integer, Field> mapFields = new WeakHashMap<Integer,
Field>();
private final Field nullField; {{
try {
nullField = this.getClass().getDeclaredField("mapFields");
} catch (Exception e) {
throw new RuntimeException(e);
}
}};
public Field getMapField(Object bean, Map<?,?> map) {
Field cachedField = mapFields.get(map.hashCode());
if (cachedField == nullField) {
return null;
} else if (cachedField != null) {
return cachedField;
} else {
for (Field mapField : bean.getClass().getDeclaredFields()) {
try {
mapField.setAccessible(true);
if (mapField.get(bean) == map &&
mapField.isAnnotationPresent(PublishEvent.class)) {
mapFields.put(map.hashCode(), mapField);
return mapField;
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
mapFields.put(map.hashCode(), nullField);
return null;
}
}