禁止基于另一个注释的注释
Disallow an annotation based on another annotation
我有一个适用于类型的注释(即class级别)和另一个适用于字段变量的注释。如果已经应用了类型注释,是否有办法禁止字段注释?
我正在开发一个 AspectJ 应用程序,它具有基于注释的切入点。目前,我有两个注解——@Trace 和@TraceAll。 @Trace 允许用于字段变量,@TraceAll 允许用于类型。
如果应用了@Trace,我将使用 set() 来跟踪对其应用的字段变量的写入。如果应用@TraceAll,我使用 within() 来跟踪所有字段变量和方法。
如果用户在单个 class 上应用两个注释,我不想重复跟踪。
我在这里做你的工作,提供 MCVE。这是您的免费拍摄,因为您是 SO 的新手,下次请自己动手:
标记注释:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(TYPE)
public @interface TraceAll {}
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Trace {}
这里首先想到的是:为什么需要两个注解?为什么不只有一个注解 @Trace
可以同时应用于类型和方法?保持简单,拥有两个注释没有额外的价值。如果 @Trace
将应用于一个类型,是否隐含地明确您想跟踪该 class 中的所有方法?
注解classes+驱动程序申请:
package de.scrum_master.app;
@TraceAll
public class SomeClass {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
}
package de.scrum_master.app;
public class Application {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
public static void main(String[] args) {
new Application().doSomething();
new SomeClass().doSomething();
}
}
我在这里复制了你的情况:Application
只使用 method-level 注释,SomeClass
混合了两种注释类型。
原版纵横:
由于您没有显示任何代码,我不得不猜测您在您的方面做了什么。我假设它是这样的:
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : @target(TraceAll) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
before() : @annotation(Trace) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
这将导致您在问题中描述的问题:
原始方面的控制台日志:
execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot())
execution(void de.scrum_master.app.SomeClass.doSomething())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.bar())
execution(void de.scrum_master.app.SomeClass.zot())
execution(void de.scrum_master.app.SomeClass.zot())
我们可以看到两个建议都触发了,SomeClass.foo()
和 SomeClass.zot()
被记录了两次。这就是你想要避免的,对吧?
如果用户这样做,这里有一个触发编译错误的方法:
改进方面:
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : @target(TraceAll) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
before() : @annotation(Trace) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
declare error : execution(@Trace * (@TraceAll *).*(..))
: "Don't combine @TraceAll and @Trace annotations";
}
现在 class SomeClass
不再编译,直到方法注释被删除,只留下类型注释。在 Eclipse 中它看起来像这样:
但实际上有一种更简单的方法可以避免重复记录:
改进方面,迭代 2:
只需通过 ||
运算符将两个建议合二为一。
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : (@target(TraceAll) || @annotation(Trace)) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
改进方面的控制台日志,迭代 2:
execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot())
execution(void de.scrum_master.app.SomeClass.doSomething())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.bar())
execution(void de.scrum_master.app.SomeClass.zot())
看到了吗?在不强制用户按照您强加给他们的规则进行游戏的情况下,不再重复登录。为什么不同时使用这两种注解呢?也许开发人员总是想跟踪某些方法。为了调试,她临时添加了一个 type-level 注释,不想被迫删除所有 method-level 注释,因为她稍后可能会忘记再次添加它们。
迭代3:只有一个注释
现在只使用一个这样的注释怎么样:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface Trace {}
package de.scrum_master.app;
@Trace
public class SomeClass {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
public aspect TraceAspect {
before() : (@target(Trace) || @annotation(Trace)) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
结果是一样的。
我有一个适用于类型的注释(即class级别)和另一个适用于字段变量的注释。如果已经应用了类型注释,是否有办法禁止字段注释?
我正在开发一个 AspectJ 应用程序,它具有基于注释的切入点。目前,我有两个注解——@Trace 和@TraceAll。 @Trace 允许用于字段变量,@TraceAll 允许用于类型。
如果应用了@Trace,我将使用 set() 来跟踪对其应用的字段变量的写入。如果应用@TraceAll,我使用 within() 来跟踪所有字段变量和方法。
如果用户在单个 class 上应用两个注释,我不想重复跟踪。
我在这里做你的工作,提供 MCVE。这是您的免费拍摄,因为您是 SO 的新手,下次请自己动手:
标记注释:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(TYPE)
public @interface TraceAll {}
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target(METHOD)
public @interface Trace {}
这里首先想到的是:为什么需要两个注解?为什么不只有一个注解 @Trace
可以同时应用于类型和方法?保持简单,拥有两个注释没有额外的价值。如果 @Trace
将应用于一个类型,是否隐含地明确您想跟踪该 class 中的所有方法?
注解classes+驱动程序申请:
package de.scrum_master.app;
@TraceAll
public class SomeClass {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
}
package de.scrum_master.app;
public class Application {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
public static void main(String[] args) {
new Application().doSomething();
new SomeClass().doSomething();
}
}
我在这里复制了你的情况:Application
只使用 method-level 注释,SomeClass
混合了两种注释类型。
原版纵横:
由于您没有显示任何代码,我不得不猜测您在您的方面做了什么。我假设它是这样的:
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : @target(TraceAll) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
before() : @annotation(Trace) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
这将导致您在问题中描述的问题:
原始方面的控制台日志:
execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot())
execution(void de.scrum_master.app.SomeClass.doSomething())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.bar())
execution(void de.scrum_master.app.SomeClass.zot())
execution(void de.scrum_master.app.SomeClass.zot())
我们可以看到两个建议都触发了,SomeClass.foo()
和 SomeClass.zot()
被记录了两次。这就是你想要避免的,对吧?
如果用户这样做,这里有一个触发编译错误的方法:
改进方面:
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : @target(TraceAll) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
before() : @annotation(Trace) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
declare error : execution(@Trace * (@TraceAll *).*(..))
: "Don't combine @TraceAll and @Trace annotations";
}
现在 class SomeClass
不再编译,直到方法注释被删除,只留下类型注释。在 Eclipse 中它看起来像这样:
但实际上有一种更简单的方法可以避免重复记录:
改进方面,迭代 2:
只需通过 ||
运算符将两个建议合二为一。
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
import de.scrum_master.app.TraceAll;
public aspect TraceAspect {
before() : (@target(TraceAll) || @annotation(Trace)) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
改进方面的控制台日志,迭代 2:
execution(void de.scrum_master.app.Application.foo())
execution(void de.scrum_master.app.Application.zot())
execution(void de.scrum_master.app.SomeClass.doSomething())
execution(void de.scrum_master.app.SomeClass.foo())
execution(void de.scrum_master.app.SomeClass.bar())
execution(void de.scrum_master.app.SomeClass.zot())
看到了吗?在不强制用户按照您强加给他们的规则进行游戏的情况下,不再重复登录。为什么不同时使用这两种注解呢?也许开发人员总是想跟踪某些方法。为了调试,她临时添加了一个 type-level 注释,不想被迫删除所有 method-level 注释,因为她稍后可能会忘记再次添加它们。
迭代3:只有一个注释
现在只使用一个这样的注释怎么样:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Retention(RUNTIME)
@Target({ TYPE, METHOD })
public @interface Trace {}
package de.scrum_master.app;
@Trace
public class SomeClass {
public void doSomething() {
foo();
bar();
zot();
}
@Trace
public void foo() {}
public void bar() {}
@Trace
public void zot() {}
}
package de.scrum_master.aspect;
import de.scrum_master.app.Trace;
public aspect TraceAspect {
before() : (@target(Trace) || @annotation(Trace)) && execution(* *(..)) {
System.out.println(thisJoinPoint);
}
}
结果是一样的。