我已经从java字节码生成了一个调用图,并且需要找到生成方法的类的最接近的父类。我有一个解决方案,我只想验证它不会变得更简单。
该图表具有以下关系和标签:
+---------[ :Class ] -[hasMethod]-> [ :Method ] --+
| ^ ^ |
+-[inherits]-+ +-[invokes]-+
现在考虑将以下代码作为输入:
class Parent {
protected void hello() {
}
}
class Foo extends Parent {
@Override
protected void hello() {
}
}
class Bar extends Foo {
public void test() {
hello();
}
}
通过解析字节码,我得到了以下节点和关系(这里只显示了相关的字节码:
(Parent:Class)-[:hasMethod]-(:Method{name:"Parent#hello()V",
simpleName:"hello", signature:"()V"})
(Foo:Class)-[:inherits]->Parent
Foo-[:hasMethod]->(:Method{name: "Foo#hello()V",
simpleName:"hello", signature:"()V"})
(Bar:Class)-[:inherits]->Foo
Bar->[:hasMethod]->(test:Method{simpleName: "test"})
test->[:invokes]->(:Method{name: "Bar#hello()V",
simpleName:"hello", signature: "()V"
我想找到在这种情况下将调用的最近父级的声明方法。我的解决方案如下:
match (m:Method) where not m<-[:hasMethod]-()
// method.name is Class#name(signature)
with m, split(m.name,'#')[0] as className
// find a method with same name and signature
match (superMethod:Method{methodName:m.methodName, signature:m.signature}),
// which is declared in a superclass
p=(c:Class{name:className})-[:inherits*]->(super)-[:hasMethod]->superMethod
// and group them in a collection
with m, collect(p) as allPossibleSuperMethods
// and now keep the closest method (with the shortest path to it)
with m, reduce(path = null, p in allPossibleSuperMethods |
case
// the candidate is either better than nothing or shorter than previous
when path is null or length(p) < length(path) then p
// or we've got our winner already
else path
end) as superMethodPath
// and the last on the path is the closest declared method
with m,last(superMethodPath) as superMethod
// so we mark the replacement
create m-[:implementedBy]->superMethod
如您所见,任务是在非声明方法(没有hasMethod关系的方法)和父类的一个声明方法之间创建链接。问题是:它可以变得更简单吗?据我所知,shortestPath函数不能对目标节点有约束,如果省略事实,我们需要遍历两种不同的关系类型。
该示例也可在http://console.neo4j.org/?id=9cmwaf
的交互式版本中使用查询的任务是返回单行--Foo#hello()