使用JavaTemplate实现链式方法调用触发异常,求排查与解答
问题描述
尝试使用org.openrewrite.java.JavaTemplate将permitAll方法调用替换为链式方法调用,在JavaIsoVisitor中实现的visitMethodInvocation方法如下:
@Override public J.MethodInvocation visitMethodInvocation(final J.MethodInvocation method, final ExecutionContext ctx) { if (method.getSimpleName().equals("permitAll") && isExpressionUrlAuthorizationConfigurer(method.getSelect())) { final JavaTemplate template = JavaTemplate.builder( "permitAll().and().anonymous(Customizer.withDefaults()).httpBasic(AbstractHttpConfigurer::disable)") .imports( "org.springframework.security.config.Customizer", "org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer") .build(); return template.apply(getCursor(), method.getCoordinates().replaceMethod()); } return super.visitMethodInvocation(method, ctx); }
调用template.apply()时触发异常:
java.lang.IllegalStateException: Expected to find enclosing SourceFile at org.openrewrite.Cursor.firstEnclosingOrThrow (Cursor.java:178) at org.openrewrite.Tree.printer (Tree.java:73) at org.openrewrite.Tree.print(Tree.java:81) at org.openrewrite.Tree.print(Tree.java:77) at org.openrewrite.java.internal.template.JavaTemplateParser.parseMethod (JavaTemplateParser.java:187)
直接调用method.getSelect().print(getCursor())也可复现该异常,提出两个问题:
- 在设置或应用
JavaTemplate时存在哪些错误? - 这是否是
org.openrewrite.java.JavaTemplate的bug,或是J.MethodInvocation的构建问题?(单元测试与实际场景均复现,说明method无SourceFile)
解决方案与分析
针对问题1:设置/应用JavaTemplate的错误
- 坐标选择错误:你使用的
method.getCoordinates().replaceMethod()仅替换方法本身,但模板是一整段链式调用。原permitAll()的调用上下文(即method.getSelect())未正确关联到SourceFile,导致模板解析时无法获取必要的文件上下文信息。 - 节点上下文缺失:
method.getSelect()可能是脱离完整语法树的孤立节点,没有挂载到包含SourceFile的父节点上,这会触发打印或模板解析时的上下文查找失败。
针对问题2:是否是框架bug或节点构建问题
这大概率不是框架bug,而是节点上下文缺失导致的问题:
- Rewrite的语法树节点必须关联到
SourceFile才能正常执行打印、模板解析等操作。如果method或其getSelect()节点未正确挂载到包含SourceFile的语法树上,就会触发该异常。 - 单元测试和实际场景均复现,说明要么是测试用例构建的语法树不完整(未将
method关联到SourceFile),要么是isExpressionUrlAuthorizationConfigurer方法选中了上下文缺失的节点。
修复建议
- 调整替换坐标:改用
method.getCoordinates().replace()替换整个方法调用节点,而非仅替换方法部分:
return template.apply(getCursor(), method.getCoordinates().replace());
- 添加上下文校验:处理前检查节点是否具备完整上下文:
if (method.getSimpleName().equals("permitAll") && isExpressionUrlAuthorizationConfigurer(method.getSelect()) && method.getSourceFile() != null) { // 模板逻辑 }
- 确保测试用例语法树完整:单元测试中通过
JavaParser解析完整代码片段生成包含SourceFile的语法树,避免手动构建孤立的J.MethodInvocation节点。
内容的提问来源于stack exchange,提问作者JanDasWiesel
相关产品推荐
相关产品推荐

