如何写不能更新任何实例变量的方法的方面或注解?
例如说,我有以下的Java类
public class Foo {
String name;
int id;
public getName() {
return name;
}
}
现在说我想写一个方面或者在一般情况下,一些注释调用它说@readOnly
可强制执行getName()
方法不能修改任何name
或id
,所以如果做
public class Foo {
String name;
int id;
@readOnly
public getName() {
name = "hello world";
id = 7564;
return name;
}
}
的任何调用getName()
像上面应该导致错误,因为它同时修改name
和id
因为它只是在做阅读的实例变量像下面的类应该就好了。
public class Foo {
String name;
int id;
@readOnly
public getName() {
return name + "," + id;
}
}
如何直接抛出一个编译错误,当有任何任何成员的写访问get*()
方法?
标记注释:
package de.scrum_master.app;
import static java.lang.annotation.ElementType.FIELD;
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, FIELD, METHOD })
public @interface ReadOnly {}
Sample类/驱动器应用:
package de.scrum_master.app;
public class Application {
private int id = 1;
private String name = "default";
@ReadOnly
public int getId() {
return id;
}
@ReadOnly
public String getName() {
name = "hello world";
id = 7564;
return name;
}
public String getNameWithoutReadOnly() {
name = "hello world";
id = 7564;
return name;
}
@ReadOnly
public String getNameIndirectly() {
modifyMembers();
return name;
}
private void modifyMembers() {
name = "hello world";
id = 7564;
}
public static void main(String[] args) {
Application application = new Application();
application.getId();
try { application.getName(); }
catch (Exception e) { e.printStackTrace(System.out); }
application.getNameWithoutReadOnly();
try { application.getNameIndirectly(); }
catch (Exception e) { e.printStackTrace(System.out); }
}
}
看点声明编译错误:
以下方面仅检测@ReadOnly
上的方法的注释,而不是类或成员。 你可以扩展它,如果你还需要这一点。
该declare error
声明与编译AspectJ编译应用程序时直接抛出编译错误。 在Eclipse中,你会看到这样的内容:
如果你也想检测由一个getter称为辅助方法间接写访问,你还需要有动态切入点cflow()
但一个只能在运行时,而不是在编译的时候,因为它检查调用堆栈。 如果你不需要它,只是将其删除。
package de.scrum_master.aspect;
import de.scrum_master.app.ReadOnly;
public aspect ReadOnlyGetterAspect {
declare error :
set(* *) && withincode(public * get*()) && @withincode(ReadOnly) :
"Setting members from within a getter is forbidden";
before() : set(* *) && cflow(execution(@ReadOnly public * get*())) {
throw new IllegalAccessError("Setting members from within a getter is forbidden");
}
}
顺便说一句,如果你想在行动中看到运行切入点/建议,你需要做的代码编译第一。 所以,你要么需要削弱declare error
为declare warning
或注释掉两个语句导致编译错误getName()
。
如果你是前者,你的日志输出将是:
java.lang.IllegalAccessError: Setting members from within a getter is forbidden
at de.scrum_master.aspect.ReadOnlyGetterAspect.ajc$before$de_scrum_master_aspect_ReadOnlyGetterAspect$1$3e55e852(ReadOnlyGetterAspect.aj:11)
at de.scrum_master.app.Application.getName(Application.java:14)
at de.scrum_master.app.Application.main(Application.java:39)
java.lang.IllegalAccessError: Setting members from within a getter is forbidden
at de.scrum_master.aspect.ReadOnlyGetterAspect.ajc$before$de_scrum_master_aspect_ReadOnlyGetterAspect$1$3e55e852(ReadOnlyGetterAspect.aj:11)
at de.scrum_master.app.Application.modifyMembers(Application.java:32)
at de.scrum_master.app.Application.getNameIndirectly(Application.java:27)
at de.scrum_master.app.Application.main(Application.java:42)
如果你选择后者(修复代码),当然你只能看到第二个例外。
文章来源: How to write an aspect or annotation for a method that cannot update any instance variables?