Skip to main content

[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;
       }
   }




Back to the top