关于使用 AspectJ 执行策略

发布于 2024-11-04 05:51:40 字数 1165 浏览 4 评论 0原文

我正在使用 Aspectj 来执行项目范围内的策略。

我现在尝试实现的一件事是,除了使用 Guava 的 Preconditions.check* 方法进行简单验证之外,任何 setter 方法中都不应该有任何逻辑。

public pointcut withinSetter() :
    withincode(public void set*(*));
public pointcut inputValidation() :
    call(public void Preconditions.check*(*));
public pointcut setFieldValue() : set(* *);
public pointcut entity() : within(com.mycompany.BaseEntity+);

declare warning :
entity() && withinSetter() && !setFieldValue() && !inputValidation():
"Please don't use Logic in Setters";

这按预期工作,为任何非 setter 代码生成警告。但是,对于这样的构造它会失败:

public void setFoo(final String newFoo) {
    Preconditions.checkNotNull(newFoo); // this is OK
    Preconditions.checkArgument(
                 newFoo.matches("\\p{Alpha}{3}"), // this generates a warning
                                                  // because String.matches()
                                                  // is called
                "Foo must have exactly 3 characters!");
    this.foo = newFoo;
}

所以我正在寻找的是一个允许任何代码的构造,只要它发生在 Preconditions.check* 调用的参数内即可。有这样的切入点吗?

I am using Aspectj for project-wide policy enforcement.

One thing I am trying to implement now is that there should be no logic in any setter methods except simple validation with Guava's Preconditions.check* methods.

public pointcut withinSetter() :
    withincode(public void set*(*));
public pointcut inputValidation() :
    call(public void Preconditions.check*(*));
public pointcut setFieldValue() : set(* *);
public pointcut entity() : within(com.mycompany.BaseEntity+);

declare warning :
entity() && withinSetter() && !setFieldValue() && !inputValidation():
"Please don't use Logic in Setters";

This works as expected, generating warnings for any non-setter code. However, it fails for constructs like this:

public void setFoo(final String newFoo) {
    Preconditions.checkNotNull(newFoo); // this is OK
    Preconditions.checkArgument(
                 newFoo.matches("\\p{Alpha}{3}"), // this generates a warning
                                                  // because String.matches()
                                                  // is called
                "Foo must have exactly 3 characters!");
    this.foo = newFoo;
}

So what I am looking for is a construct that would allow any code, as long as it happens inside the parameters to a Preconditions.check* call. Is there such a pointcut?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

空城旧梦 2024-11-11 05:51:40

我知道这是一个老问题,但我只是在搜索其他内容时偶然发现了它。

答案是否定的,因为在 JVM 字节码中不存在“检查中的逻辑”之类的东西* 调用”。例如,将结果传递给 Preconditions.checkArgument(..)< 之前评估 newFoo.matches(..) /code>,非常像这样:

boolean match = newFoo.matches("\\p{Alpha}{3}");
Preconditions.checkArgument(match, "Foo must have exactly 3 characters!");

如果代码是这样编写的,那么您无论如何都会发出警告,那么为什么不将相同的 Java 代码(可能导致相似或相同的字节代码)编写为嵌套调用呢? ;-)


更新: 我创建了一个小例子:

public class Application {
    public static void main(String[] args) {
        String newFoo = "Scrum";
        boolean match = newFoo.matches("\\p{Alpha}{3}");
        checkArgument(
            match,
            "Foo must have exactly 3 characters!"
        );
        checkArgument(
            newFoo.matches("\\p{Alpha}{3}"),
            "Foo must have exactly 3 characters!"
        );
    }

    private static void checkArgument(boolean status, String errorMessage) {
        if (!status)
            System.out.println(errorMessage);
    }
}

如果您使用 javap -c Application 转储字节代码,您会看到

Compiled from "Application.java"
public class Application extends java.lang.Object{
public Application();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc #16; //String Scrum
   2:   astore_1
   3:   aload_1
   4:   ldc #18; //String \p{Alpha}{3}
   6:   invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   9:   istore_2
   10:  iload_2
   11:  ldc #26; //String Foo must have exactly 3 characters!
   13:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   16:  aload_1
   17:  ldc #18; //String \p{Alpha}{3}
   19:  invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   22:  ldc #26; //String Foo must have exactly 3 characters!
   24:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   27:  return

}

:可以看到,转储中第 3-13 行和第 16-24 行的字节码是相同的,除了布尔值的存储和重新加载之外。也许这说明了我之前所说的。

I know it is an old question, but I just stumbled across it while searching for something else.

The answer is no, because in JVM bytecode there is no such thing as "logic inside a check* call". For example, newFoo.matches(..) is evaluated before the result is passed to Preconditions.checkArgument(..), very much like this:

boolean match = newFoo.matches("\\p{Alpha}{3}");
Preconditions.checkArgument(match, "Foo must have exactly 3 characters!");

If the code was written like this, you would issue a warning anway, so why not if the same Java code, possibly resulting in similar or identical byte code, is written as a nested call? ;-)


Update: I have created a little example:

public class Application {
    public static void main(String[] args) {
        String newFoo = "Scrum";
        boolean match = newFoo.matches("\\p{Alpha}{3}");
        checkArgument(
            match,
            "Foo must have exactly 3 characters!"
        );
        checkArgument(
            newFoo.matches("\\p{Alpha}{3}"),
            "Foo must have exactly 3 characters!"
        );
    }

    private static void checkArgument(boolean status, String errorMessage) {
        if (!status)
            System.out.println(errorMessage);
    }
}

If you dump the byte code using javap -c Application you see this:

Compiled from "Application.java"
public class Application extends java.lang.Object{
public Application();
  Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   ldc #16; //String Scrum
   2:   astore_1
   3:   aload_1
   4:   ldc #18; //String \p{Alpha}{3}
   6:   invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   9:   istore_2
   10:  iload_2
   11:  ldc #26; //String Foo must have exactly 3 characters!
   13:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   16:  aload_1
   17:  ldc #18; //String \p{Alpha}{3}
   19:  invokevirtual   #20; //Method java/lang/String.matches:(Ljava/lang/String;)Z
   22:  ldc #26; //String Foo must have exactly 3 characters!
   24:  invokestatic    #28; //Method checkArgument:(ZLjava/lang/String;)V
   27:  return

}

As you can see, the byte code of lines 3-13 versus 16-24 in the dump is identical except for the storing and re-loading of the boolean value. Maybe this illustrates what I have said before.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文