英文:
When does Sonar's TryStatementTree#resourceList return a Tree that isn't a VariableTree?
问题
我在查看一些 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) // 这个条件有可能为false吗?
.map(VariableTree.class::cast)
.map(resource -> resource.simpleName().name())
.forEach(SomeClass::handleThisCase);
// ...
}
查阅Java语言规范,我想不出在 try
语句中会有什么东西代替资源声明,而不是标识符列表。
我认为这可能与需要表示不存在的资源定义或类似的情况有关,所以我对它进行了一些单元测试。
try { // 这里没有资源声明
// ...
} catch (SomeException ex) {
// ...
}
但在这种情况下,方法根本不会被调用,我猜这是由 BaseTreeVisitor
处理的。
我一直在尝试想出使转换不可能的示例,但我想到的一切要么无法编译,要么从不遵循这个执行路径。
我是否忽略了一种使用更通用的 Tree
更好的情况?还是这个选择源于库中接口的结构方式?这似乎并不受任何超级接口(TryStatementTree
-> StatementTree
-> Tree
)的强制。resourceList
是由 TryStatementTree
本身定义的。
英文:
I came across the org.sonar.plugins.java.api.tree.TryStatementTree
interface while going over some code for a SonarQube plugin. One of the rules implemented goes over the variables defined in a try-with-resources block.
Looking at the TryStatementTree#resourceList
, I can see that it returns a ListTree<Tree>
. This can be iterated over in a number of ways. In one case, the plugin inspects the name of the variable declared. When this happens, the Tree
is cast to VariableTree
because Tree
is a more generic interface that doesn't provide access to variable names via IdentifierTree
.
This is where the cast is in the code I'm looking at, a class that extends BaseTreeVisitor
and implements 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);
// ...
}
Looking at the Java Language Standard, I can't think of a situation when a try
statement would have something in place of the resource declaration that isn't a list of identifiers.
I thought this had to do with the need to represent a non-present resource definitions or something similar so I threw a few unit test cases at it.
try { // No resource declaration here
// ...
} catch (SomeException ex) {
// ...
}
but in this case the method isn't called at all, which I guess is handled by BaseTreeVisitor
.
I've been trying to come up with examples that would make the cast impossible but everything I've come up with either doesn't compile or never follows this execution path.
Am I missing a way to write a try
statement that makes the more generic Tree
the better choice? Or does this choice stem from the way the interfaces in the library have been structured? It doesn't seem to be enforced by any of the super-interfaces (TryStatementTree
-> StatementTree
-> Tree
). resourceList
is defined by TryStatementTree
itself.
答案1
得分: 0
Ironically, I stumbled upon the answer in the SonarQube documentation minutes after posting the question.
It turns out there's a method that works exactly as I expected it to, TryStatementTree#resource
, which was deprecated and then removed in favour of TryStatementTree#resourceList
, which is exactly what my code uses.
Deprecated method
org.sonar.plugins.java.api.tree.TryStatementTree.resources()
has been removed, in favor oforg.sonar.plugins.java.api.tree.TryStatementTree.resourceList()
, as Java 9 allows other trees thanVariableTree
to be placed as resources intry-with-resources
statements.
Here's an example:
SomeAutoCloseableClass myResource = obtainOneSomehow(); try (myResurce) { // No resource declaration here, just an identifier // ... } catch (SomeException ex) { // ... }
My project is compiled with the source level set to Java 8 compatibility, which should be amended and a new unit test case should be added to make sure the newly possible way to write a try-with-resources
block is handled.
英文:
Ironically, I stumbled upon the answer in the SonarQube documentation minutes after posting the question.
It turns out there's a method that works exactly as I expected it to, TryStatementTree#resource
, which was deprecated and then removed in favour of TryStatementTree#resourceList
, which is exactly what my code uses.
> Deprecated method org.sonar.plugins.java.api.tree.TryStatementTree.resources()
has been removed, in favor of org.sonar.plugins.java.api.tree.TryStatementTree.resourceList()
, as Java 9 allows other trees than VariableTree
to be placed as resources in try-with-resources
statements.
Here's an example:
SomeAutoCloseableClass myResource = obtainOneSomehow();
try (myResurce) { // No resource declaration here, just an identifier
// ...
} catch (SomeException ex) {
// ...
}
My project is compiled with the source level set to Java 8 compatibility, which should be amended and a new unit test case should be added to make sure the newly possible way to write a try-with-resources
block is handled.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论