gpt4 book ai didi

java - 如何为无法更新任何实例变量的方法编写方面或注释?

转载 作者:行者123 更新时间:2023-12-02 10:24:42 25 4
gpt4 key购买 nike

如何为无法更新任何实例变量的方法编写方面或注释?

例如,我有以下 java 类

public class Foo {

String name;
int id;

public getName() {
return name;
}
}

现在假设我想编写一个方面,或者一般来说,一些注释将其称为@readOnly,它可以强制getName()方法不修改任何一个 nameid 所以如果这样做

public class Foo {

String name;
int id;

@readOnly
public getName() {
name = "hello world";
id = 7564;
return name;
}
}

任何像上面这样的 getName() 调用都会导致错误,因为它会修改 nameid

像下面这样的类应该没问题,因为它只是读取实例变量。

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 {}

示例类/驱动程序应用程序:

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 中你会看到类似这样的东西:

AspectJ declared compile errors

如果您还想检测 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)

如果您执行后者(修复代码),您当然只会看到第二个异常。

关于java - 如何为无法更新任何实例变量的方法编写方面或注释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54061431/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com