我想在方法的开头添加以下if
-语句:
@Grant( [ Permission.admin ] )
def someMethod( someArg ){
if( GrantUtil.checkAuthorization( someArg, Permission.admin ){ // 2nd param comes from annotation
// nothing
}else{
return null
}
// the rest
}
为此,我使用了自定义的AST转换:
class GrantASTTransformation implements ASTTransformation {
@Override
void visit( ASTNode[] nodes, SourceUnit source ) {
if( !nodes ) return
MethodNode methodNode = (MethodNode) nodes.find{ it in MethodNode }
if( methodNode ) augmentMethod methodNode
}
void augmentMethod( MethodNode methodNode ) {
List<AnnotationNode> annos = methodNode.getAnnotations new ClassNode( Grant )
Expression rolesValue = annos.first().getMember 'value'
Expression param = new VariableExpression( methodNode.parameters[ 0 ] )
Expression args = new ArgumentListExpression( [ param, rolesValue ] )
StaticMethodCallExpression callExp = new StaticMethodCallExpression( new ClassNode( GrantUtil ), 'checkAuthorization', args )
BooleanExpression checkExpression = new BooleanExpression( callExp )
IfStatement ifStmt = new IfStatement( checkExpression, new EmptyStatement(), new ReturnStatement( ConstantExpression.NULL ) )
((BlockStatement)methodNode.code).statements.add 0, ifStmt
}
}
而且效果很好
现在我想用一个更透明的AstBuilder重写这个方法,到目前为止我得到了:
void augmentMethod( MethodNode methodNode ) {
List<AnnotationNode> annos = methodNode.getAnnotations new ClassNode( Grant )
Expression rolesValue = annos.first().getMember 'value'
IfStatement ifStmt = (IfStatement)new AstBuilder().buildFromSpec{
ifStatement{
booleanExpression{
staticMethodCall( GrantUtil, 'checkAuthorization' ){
argumentList{
// this doesn't work
param
rolesValue
}
}
}
//if block
empty()
//else block
returnStatement{ constant null }
}
}.first()
((BlockStatement)methodNode.code).statements.add 0, ifStmt
}
但它无法填充argumentList
,
groovy.lang.MissingMethodException: No signature of method: static GrantUtil.checkAuthorization() is applicable for argument types: () values: []
Possible solutions: checkAuthorization(io.vertx.ext.web.RoutingContext, java.util.List)
我浏览了test,但找不到将“外部”参数引入argumentList
的方法。
做这件事的正确方法是什么?AstBuilder支持吗?
更新:
我尝试了@cfrick的建议,它工作到50%:
staticMethodCall(GrantUtil, 'checkAuthorization') {
argumentList {
variable methodNode.parameters[0].name // works like charm!
constant( [ Permission.user ] as Permission[] )
}
}
在执行时,我得到了一个异常:
org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
General error during instruction selection: Cannot generate bytecode for constant: [Lio.lootwalk.domain.Permission;@1e7f19b4 of type: [Lio.lootwalk.domain.Permission;
因此,在argumentList
中将枚举对象数组作为constant
传递失败。
2条答案
按热度按时间6mw9ycah1#
您可以使用Groovy的
GeneralUtils
类中的静态方法来改进您的原始解决方案:至于
AstBuilder
,它现在不如它的替代品宏那么受欢迎。使用宏编写augmentMethod
的一种方法是:你只需要小心在代码中引用类,这就是为什么
GrantUtil
没有显式出现的原因。要坚持使用
AstBuilder
,您可以用途:可能有一个简化的可能,但上述工作。
vktxenjb2#
错误的原因是传递给
argumentList
的闭包基本上是一个no-op。你可以在那里写任何你想要的(非DSL)代码,但它不会对生成的代码产生任何直接影响;因此,在运行时最后一次调用时会出现缺少参数的错误。你必须使用DSL的动词来实际创建参数。在你的例子中,它们是
variable
和constant
。这是生成正确的代码:
编辑
对于记录版本,使其与枚举数组一起工作:
这只是确保,总是有一个列表字面周围,然后只是采取任何在那里;那我们就把它当成是表达了
这适用于: