In her German book “Langlebige Software-Architekturen” Carola Lilienthal tells the story of an architect who wants to know which public methods are currently not called from outside the package (p. 117).
Sure, with a powerful tool like Sotograph she is using this is no problem - if you have the money. But can you achieve this also with Open Source tools? Having read some of my previous posts (especially the ones about jQAssistant) you already know the answer: yes, of course! I’ll show you how easy that is.
For this post, I created a little demo project with a Service and a Client calling this Service:
The Service has two methods
1
2
3
4
5
6
public class Service {
public void calledFromDifferentPackage(){
onlyCalledInPackage();
}
public void onlyCalledInPackage(){}
}
and the Client calls one of them from a different package
1
2
3
4
5
public class Client {
public void call() {
new Service().calledFromDifferentPackage();
}
}
I scanned the project into a jQAssistant database and started the server for exploration. Now I can query for the public methods not accessed from a different package in three easy steps.
First step: put a label ‘Public’ on the public methods
1
2
3
4
5
6
MATCH
(c:Type:Class)-[:DECLARES]->(m:Method)
WHERE
m.visibility='public'
SET
m:Public
Second step: put a label ‘UsedFromDifferentPackage’ on methods which are called from a different package
1
2
3
4
5
6
7
8
9
MATCH
(t1:Type)-[:DECLARES]->(m:Method),
(t2:Type)-[:DECLARES]->(p:Method:Public),
(package1:Package)-[:CONTAINS]->(t1),
(package2:Package)-[:CONTAINS]->(t2),
(m)-[:INVOKES]->(p)
WHERE
package1.fqn <> package2.fqn
SET p:UsedFromDifferentPackage
Third step: query for the methods which have no label ‘UsedFromDifferentPackage’
1
2
3
4
5
6
MATCH
(c:Type)-[:DECLARES]->(u:Method:Public)
WHERE NOT
u:UsedFromDifferentPackage
RETURN
c.fqn, u.name
Of course I could have done this in one more complex step. But I decided to separate the concerns in this way because most likely I would add some WHERE clauses in the third step to exclude public APIs, unscanned entry points, uninteresting packages, or examine only some submodules. As a nice side effect, the first two steps can be easily transformed into jQAssistant concepts and the third one into a jQAssistant constraint.
I published the source code on GitHub.