Static Linkage Checker is a tool that finds static linkage errors on a class path and reports the errors to the console. It scans the class files in the class path for references to other classes and reports any reference that cannot be satisfied in the class path. It can report all such unsatisfied references or only those that are reachable from a given set of entry point classes.
There are two use cases for Static Linkage Checker:
-
For library/application developers the tool finds static linkage errors in their projects, and will help to avoid incompatible versions of libraries in their dependencies.
-
For organizations that provide multiple libraries developed by different teams, the tool helps to ensure that users depending on the libraries will not see any static linkage errors at runtime.
-
The tool takes a class path as required input. This class path is called the input class path and is separate from the runtime class path of the tool itself. The tool operates on the input class path to find linkage errors.
-
The tool extracts all symbolic references from the all class files in the class path.
-
The tool records static linkage errors for symbolic references which cannot be satisfied in the class path.
-
Optionally, the user can specify a subset of elements in the class path as entry points. In that case, the tool will list only those references that are reachable from the classes in the entry points.
-
At the end, the tool outputs a report on the linkage errors.
The input of the tool is either the Maven coordinates of a BOM, a list of Maven coordinates, or a list of class and jar files in the filesystem. All of these inputs are converted to a class path for the static linkage check, which is the input class path.
When the input is a Maven BOM, the elements in the BOM are converted to a list of Maven coordinates. If the BOM imports another BOM, the elements of the second BOM are recursively added to the list of Maven coordinates. This list of Maven coordinates is handled in the same way as a directly-provided list of coordinates (see below).
When the input is a list of Maven coordinates, they are resolved to a list of jar files that consists of the artifacts and their dependencies, through a Maven dependency graph. This list of jar files is handled in the same way as a directly-provided list of jar files (see below).
When the input is a list of class and jar files, they are used directly as the input class path.
The tool reports static linkage errors for the input class path. Each of the static linkage errors contains information on the source class and the destination class of the reference, and has one of the three types: missing class, missing method, or missing field.
In order to provide a diagnosis in the output report, the tool builds a class reference graph, and annotates linkage errors with reachability from entry point classes. Optionally the tool outputs a report including only reachable static linkage errors. The tool allows users to choose the scope of entry point classes:
-
Classes in the target project: when the scope of the entry point is only the classes in the target project, it ensures that the current functionality used in the dependencies will not cause static linkage errors. The output may fail to report potential static linkage errors, which would be introduced by starting to use a previously unreachable class in one of the dependencies.
-
With direct dependencies of the target project: when the scope of the entry point is the classes in the target project and the all classes in the direct dependencies of the project, it ensures that functionality of the dependencies will not cause static linkage errors. The output may contain linkage errors for unreachable classes from user's perspective.
-
All classes in the input class path: when reachability check is off, then all static linkage errors from all classes in the classpath, regardless of the reachability, are reported.
A Maven dependency graph is a graph data structure where
-
Node: a node is a Maven artifact identified by Maven coordinates such as
com.example.foo:bar:1.5.4. A node may be marked unavailable when the artifact is not available in Maven repositories. -
Edge: a directed edge is a dependency from one Maven artifact (source of the edge) to another Maven artifact (target of the edge).
A dependency has a boolean attribute
optionaland an enum attributescope, among other properties listed in POM Reference: Dependencies.Self-loops are not possible. A parallel edge is allowed but is dropped in the model.
Compared to a Maven dependency tree retrieved by a pom.xml through
RepositorySystem.resolveDependencies, a Maven dependency graph has the following differences:
- A Maven dependency tree cannot have multiple versions of a Maven artifact, whereas a Maven dependency graph can have them.
- A Maven dependency tree does not have transitive
scope: provideddependencies under ascope: provideddependency, whereas a Maven dependency graph can have them. - A Maven dependency tree does not contain a cycle, whereas a Maven dependency graph can contain cycles.
Given an ordered list of Maven artifacts, DependencyGraphBuilder constructs a Maven dependency
graph in the following steps:
- Start with a graph with nodes of the Maven artifacts in the list. The nodes are called initial nodes.
- Pick up an unvisited node which is not marked unavailable in a graph in breadth-first manner.
- By reading dependencies of the node,
- add new nodes corresponding to the target Maven artifacts, identified by Maven coordinates, if not present.
- add edges from the source node to the target nodes of the Maven artifacts.
- Repeat Step 2-3, until all nodes are visited in the breadth-first traversal.
A graph construction may fail when there is a problem.
A Maven artifact may be unavailable through Maven repositories. Such nodes are marked unavailable at Step 3 of a graph construction.
Given a set of initial nodes, a node is called optional when the path from the initial nodes to
the artifact contains an optional node. A node is called provided if the path contains
a scope: provided dependency.
When there is an unavailable Maven artifact and it is not optional or provided for the initial nodes, the graph construction fails.
A dependency element in pom.xml may have a version range specification. Each of the specifications creates a version constraint.
When there is a version constraint that cannot be satisfied, the graph construction fails.
A class path (list of jar files of Maven artifacts) can be generated from a Maven dependency graph. A class path is built by picking up Maven artifacts by a breadth-first traversal. The traversal starts from the initial nodes of a Maven dependency graph.
During the pick-up,
- duplicate artifacts identified by Maven coordinates are discarded.
- nodes marked as unavailable are skipped.
When there are multiple versions of a Maven artifact identified by Maven coordinates without the version part, a version is picked up using one of the following strategies:
- Maven dependency mediation strategy: the first version encountered during the breadth-first traversal is selected.
- Gradle dependency mediation strategy: the highest version among a Maven dependency graph is selected.