Summary: | Explicit formals binding to constants wanted in pointcuts | ||
---|---|---|---|
Product: | [Tools] AspectJ | Reporter: | Dusan Chromy <bobik72> |
Component: | Compiler | Assignee: | Adrian Colyer <adrian.colyer> |
Status: | REOPENED --- | QA Contact: | |
Severity: | enhancement | ||
Priority: | P5 | CC: | Alexander, ramnivas |
Version: | 1.2.1 | ||
Target Milestone: | --- | ||
Hardware: | PC | ||
OS: | Windows XP | ||
Whiteboard: |
Description
Dusan Chromy
2005-04-27 05:26:50 EDT
why not just use thisJoinPoint in the body of the advice? Since T and F match different join points, this would always enable you to distinguish. If T and F *could* both match at some join point, your proposal would break - what should the value of the flag be? Advice executes at join points, not at pointcuts, so the current thisJoinPoint abstraction is appropriate imho. not sure why this was assigned to me - sending it back to Adrian... Hello Adrian, thanks for your response. I even reassigned the bug to Julie in the false belief that the bug report went unnoticed, sorry for that extra bother. A friend of mine met you on the JAX in Frankfurt, so I see you must be busy these days. I understand it is possible to examine thisJoinPoint in the advice body to distinguish the cases in my example. However, it means the advice must know about join point signatures, which is IMHO something that should be captured in pointcuts only. I agree the binding would be impossible if T and F both matched the same join point, but that's not really anything new or bad - there already is an "Ambigous binding" error in AspectJ. I admit my example was perhaps too abstract and not very convincing. Let me give you a real code example that I wrote just today. We are using AspectJ to do performance monitoring using Apache's StopWatch class. In some classes, I introduce the StopWatch object to the class using inter-type declaration (more precisely, I declare the class to extend a base class which has the StopWatch as a member). In other classes, I just create a new StopWatch object for every method invocation. This leads to a code with two very similar advices: Object around() : measuredMethod() { StopWatch w = new StopWatch(); try { w.start(); return proceed(); } finally { w.stop(); // output w here } } Object around(StopWatchOwner owner) : measuredMethodWithOwnWatch(owner){ try { owner.getWatch().start(); return proceed(owner); } finally { owner.getWatch().stop(); // output owner.getWatch() here } } As you see, the two advices are almost identical. A clear violation of the DRY principle, isn't it? Yet the two cannot be merged, for the sole reason that one pointcut has no arguments and the other one has one. What I would love to do is this: //redefine the pointcut that had originally no arguments pointcut measuredMethod(StopWatchOwner owner) : // whatever joinpoint definition here && bind(null); //and merge the two advices as: Object around(StopWatchOwner owner) : measuredMethod(owner) || measuredMethodWithOwnWatch(owner) { StopWatch w = (owner == null) ? new StopWatch() : owner.getWatch(); try { w.start(); return proceed(); } finally { w.stop(); // output w here } } What do you think? This example makes a lot more sense, thanks. I don't think we'll have time to think through all of the potential issues in here in order to make the 1.5.0 release - and it's also something that no other user has asked for afaik. I'm going to leave this open as an enhancement request but with no target milestone assigned for the time being, that way we can come back and take another look once we've dealt with the 1.5.0 release. We're not going to get to this in AJ 1.5.0. Marking as "LATER" for consideration in 1.5.1 and future release planning. LATER/REMIND bugs are being automatically reopened as P5 because the LATER and REMIND resolutions are deprecated. I second this (old) request. My situation is as follows: I have a logging aspect with several pointcuts and advice: aspect LoggingAspect { pointcut logMe1() : execution(...); pointcut logMe2() : execution(...); pointcut logMe3() : execution(...); Object around() : logMe1() { String logMessage = "log message #1"; logger.log("before " + logMessage); logger.indent(); Object result = proceed(); logger.dedent(); logger.log("after " + logMessage); } Object around() : logMe2() { String logMessage = "log message #2"; logger.log("before " + logMessage); logger.indent(); Object result = proceed(); logger.dedent(); logger.log("after " + logMessage); } Object around() : logMe3() { String logMessage = "log message #1"; logger.log("before " + logMessage); logger.indent(); Object result = proceed(); logger.dedent(); logger.log("after " + logMessage); } } Obviously there is code duplication just because the log message is different. (Actually it is more complicated because sometimes the message is not constant, but needs to be constructed from a "this" object's properties, but let's forget about that for now.) What I would like to have is this: aspect LoggingAspect { pointcut logMe1(String msg) : execution(...) && bind(msg="log message #1"); pointcut logMe2(String msg) : execution(...) && bind(msg="log message #2"); pointcut logMe3(String msg) : execution(...) && bind(msg="log message #3"); Object around(String msg) : logMe1(msg) || logMe2(msg) || logMe2(msg) { logger.log("before " + msg); logger.indent(); Object result = proceed(msg); // maybe even just proceed() // for bound pointcut parameters logger.dedent(); logger.log("after " + msg); } } |