题
我正在使用fackj进行整个项目的政策执法。
我现在要实现的一件事是,除了使用guava的简单验证外,任何设置器方法中都不应有逻辑 Preconditions.check*
方法。
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";
这是按预期工作的,为任何非设定代码生成警告。但是,这样的结构失败了:
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*
称呼。有这样的尖端吗?
解决方案
我知道这是一个古老的问题,但是我只是在寻找其他东西时偶然发现了它。
答案是否定的,因为在JVM字节码中,没有“逻辑” check*
呼叫”。例如, newFoo.matches(..)
被评估 前 结果传递给 Preconditions.checkArgument(..)
, ,非常像这样:
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是相同的,除了存储和重新加载布尔值。也许这说明了我之前所说的话。
不隶属于 StackOverflow