在浏览SonarQube插件的一些代码时,我遇到了org.sonar.plugins.java.api.tree.TryStatementTree
界面。实施的规则之一遍历了try-with-resources块中定义的变量。
查看TryStatementTree#resourceList
,我可以看到它返回了ListTree<Tree>
。这可以通过多种方式进行迭代。在一种情况下,插件会检查声明的变量的名称。发生这种情况时,将Tree
强制转换为VariableTree
,因为Tree
是更通用的接口,无法通过IdentifierTree
访问变量名。
这就是我正在查看的代码中的强制转换的地方,它是扩展BaseTreeVisitor
并实现JavaFileScanner
的类。
@Override
public void visitTryStatement(TryStatementTree tree) {
// ...
tree.resourceList().stream()
.filter(resource -> resource instanceof VariableTree) // Is it possible for this condition to evaluate to false?
.map(VariableTree.class::cast)
.map(resource -> resource.simpleName().name())
.forEach(SomeClass::handleThisCase);
// ...
}
看着Java Language Standard,我想不出
try
语句代替资源声明而不是标识符列表的情况。我认为这与表示不存在的资源定义或类似内容的需求有关,因此我在上面提出了一些单元测试用例。
try { // No resource declaration here
// ...
} catch (SomeException ex) {
// ...
}
但是在这种情况下,根本不会调用该方法,我猜这是由
BaseTreeVisitor
处理的。我一直在尝试提出一些示例,这些示例将使强制转换变得不可能,但是我提出的所有内容要么无法编译,要么永远不会遵循该执行路径。
我是否缺少编写
try
语句的方法,该语句使更通用的Tree
更好的选择?还是这种选择源于库中接口的结构方式?似乎没有任何超级接口(TryStatementTree
-> StatementTree
-> Tree
)强制执行。 resourceList
由TryStatementTree
本身定义。 最佳答案
具有讽刺意味的是,我在发布问题后的SonarQube documentation分钟内偶然发现了答案。
事实证明,有一个方法完全符合我的预期,TryStatementTree#resource
,已被弃用,然后取而代之的是TryStatementTree#resourceList
,这正是我的代码所使用的方法。
不赞成使用的方法org.sonar.plugins.java.api.tree.TryStatementTree.resources()
已被删除,而支持org.sonar.plugins.java.api.tree.TryStatementTree.resourceList()
,因为Java 9允许将VariableTree
以外的其他树作为资源放置在try-with-resources
语句中。
这是一个例子:
SomeAutoCloseableClass myResource = obtainOneSomehow();
try (myResurce) { // No resource declaration here, just an identifier
// ...
} catch (SomeException ex) {
// ...
}
我的项目是在源级别设置为Java 8兼容性的情况下编译的,应该对此进行修改,并应添加新的单元测试用例,以确保处理了写入
try-with-resources
块的新方法。