Sequencing of the decorators calls (multiple advices calling)
vladimir-prishchep opened this issue · 3 comments
Problem
@Wove()
class Example {
foo() {
console.log('within foo');
}
bar() {
console.log('within bar');
}
}
const example = new Example();
setTimeout(() => {
example.foo();
example.bar();
}, 1e3);
class Aspect {
@beforeMethod({ classNamePattern: /^(Example)$/, methodNamePattern: /^foo/})
beforeFoo() {
console.log('before foo');
}
@afterMethod({ classNamePattern: /^(Example)$/, methodNamePattern: /^bar/})
afterBar() {
console.log('before bar');
}
}
In such code beforeFoo()
advice will be executed twice, despite foo()
is called once.
It is because of the sequencing of the decorators functions calls (@Wove, @beforeMethod, @afterMethod
). If move Example
class declaration after Aspect
class, it will be no problem (@Wove
decorator will be executed after @beforeMethod and @afterMethod
).
Possible Solution
As a fast variant it could be solved by returning from woveTarget()
func of the joint_points classes if jointpoint was already __woven__
. For method_call jointpoint:
protected woveTarget(proto: any, key:string, advice: Advice, woveMetadata: any) {
// Add this:
if (proto[key].__woven__) {
return;
}
let className = proto.constructor.name;
let bak = proto[key];
let self = this;
proto[key] = function () {
let metadata = self.getMetadata(className, key, bak, arguments, this, woveMetadata);
return advice.wove(bak, metadata);
};
proto[key].__woven__ = true;
}
Thanks for reporting the issue and for the suggestion. I'll proceed with a fix as soon as possible.
@vladimir-prishchep would you test against this branch. The issue should be resolved.
@mgechev I checked the branch, fix works. Thanks a lot for a quick response and the same fast fix. Cool tool and the same cool maintenance!