如果一个方法有参数,为什么 Groovy 应用两次 AST 转换?
Why would Groovy apply an AST transformation twice if a method has parameters?
我是 运行 使用 Groovy/Grails v5 将 AST 转换应用于控制器方法的小测试。
该方法采用单个参数来表示典型的命令对象。
我在 AST 转换中添加了一些日志记录 class 所以在 visit() 方法中,我可以看到它正在被应用。
如果控制器方法没有参数,那么我看到正在应用转换,没问题。
但是,如果我将参数、命令对象添加到方法中,那么我会看到我的日志输出两次。
第一次应用它时,我可以看到预期的输出,告诉我它正在应用于方法,并且检测到参数。
然后第二次调用它并告诉我它正在应用,但这次它没有看到任何参数。
这是 visit() 方法:
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class AjaxResponseASTTransformation extends AbstractAstTransformation {
private static final Logger LOG = LoggerFactory.getLogger(AjaxResponseASTTransformation.class);
@Override
public void visit(ASTNode[] nodes, SourceUnit source) {
final MethodNode methodNode = (MethodNode) nodes[1];
log("detected AjaxResponse annotation for method " + methodNode.getName());
final Parameter[] parameters = methodNode.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
log("Found Parameter : " + parameter.getName());
}
if (parameters.length == 0) {
log("No parameters present - what gives??");
}
}
}
这是控制器方法:
@AjaxResponse
def index(MyCommand myCommand) { render "" }
构建此项目会产生以下输出:
20:01:00.537 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - detected AjaxResponse annotation for method index
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - Found Parameter : myCommand
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - detected AjaxResponse annotation for method index
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - No parameters present - what gives??
任何人都可以解释为什么它会被应用两次吗?
当你编写这样的控制器操作时:
def index(MyCommand myCommand) {
render ""
}
在编译时,我们生成该方法的 no-arg 版本,如下所示:
def index() {
MyCommand c = new MyCommand()
bindData c, request
// subject c to dependency injection here, code ommitted
// this call to validate is only generated if `MyCommand` is validateable...
c.validate()
// this will call your method
index(c)
}
因此,class 中有 2 个名为 index
的方法,即使您只写了一个。
在 grails-plugin-controllers/src/main/groovy/org/grails/compiler/web/ControllerActionTransformer.java#L395 处是控制器动作转换器的一部分,它将您的注释复制到 no-arg 方法。
顺便说一下,这就是控制器操作方法不支持方法重载的原因。我们必须生成具有相同名称的 no-arg,因此您不能有 2 个具有相同名称但接受不同参数的操作方法。我们生成一个编译器错误,指示遇到该场景时。
我是 运行 使用 Groovy/Grails v5 将 AST 转换应用于控制器方法的小测试。 该方法采用单个参数来表示典型的命令对象。 我在 AST 转换中添加了一些日志记录 class 所以在 visit() 方法中,我可以看到它正在被应用。
如果控制器方法没有参数,那么我看到正在应用转换,没问题。 但是,如果我将参数、命令对象添加到方法中,那么我会看到我的日志输出两次。
第一次应用它时,我可以看到预期的输出,告诉我它正在应用于方法,并且检测到参数。
然后第二次调用它并告诉我它正在应用,但这次它没有看到任何参数。
这是 visit() 方法:
@GroovyASTTransformation(phase = CompilePhase.CANONICALIZATION)
public class AjaxResponseASTTransformation extends AbstractAstTransformation {
private static final Logger LOG = LoggerFactory.getLogger(AjaxResponseASTTransformation.class);
@Override
public void visit(ASTNode[] nodes, SourceUnit source) {
final MethodNode methodNode = (MethodNode) nodes[1];
log("detected AjaxResponse annotation for method " + methodNode.getName());
final Parameter[] parameters = methodNode.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
log("Found Parameter : " + parameter.getName());
}
if (parameters.length == 0) {
log("No parameters present - what gives??");
}
}
}
这是控制器方法:
@AjaxResponse
def index(MyCommand myCommand) { render "" }
构建此项目会产生以下输出:
20:01:00.537 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - detected AjaxResponse annotation for method index
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - Found Parameter : myCommand
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - detected AjaxResponse annotation for method index
20:01:00.538 [/127.0.0.1:51713 to /127.0.0.1:51712 workers] INFO mypackage.AjaxResponseASTTransformation - No parameters present - what gives??
任何人都可以解释为什么它会被应用两次吗?
当你编写这样的控制器操作时:
def index(MyCommand myCommand) {
render ""
}
在编译时,我们生成该方法的 no-arg 版本,如下所示:
def index() {
MyCommand c = new MyCommand()
bindData c, request
// subject c to dependency injection here, code ommitted
// this call to validate is only generated if `MyCommand` is validateable...
c.validate()
// this will call your method
index(c)
}
因此,class 中有 2 个名为 index
的方法,即使您只写了一个。
在 grails-plugin-controllers/src/main/groovy/org/grails/compiler/web/ControllerActionTransformer.java#L395 处是控制器动作转换器的一部分,它将您的注释复制到 no-arg 方法。
顺便说一下,这就是控制器操作方法不支持方法重载的原因。我们必须生成具有相同名称的 no-arg,因此您不能有 2 个具有相同名称但接受不同参数的操作方法。我们生成一个编译器错误,指示遇到该场景时。