Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Find all direct dependencies of an artifact on Maven Central

Tags:

java

maven

For an artifact on Maven central (or any other given Nexus repository), I want to make a list of all direct dependencies.

At first, I thought about just reading the pom.xml and gather all entries from the dependency section. But I noticed that these entries might have no version (supplied by dependency management) or that entries might come from parent poms.

My second idea was to build some kind of artificial Maven project and gather the dependencies with mvn dependency:tree. This might become complicated.

What would be the most direct (but also reliable) way?

like image 948
J Fabian Meier Avatar asked Sep 22 '16 11:09

J Fabian Meier


People also ask

Where can I find Maven dependencies?

In your project's POM, press Ctrl and hover the mouse over the dependency. Click the dependency to open the dependency's POM. In the dependency POM, view the active dependency, its transitive dependencies and their versions. You can check the origin from which the dependency was pulled in.

How do you find transitive dependency?

If A, B, and C are attributes of relation R, such that A → B, and B → C, then C is transitively dependent on A, unless either B or C is a candidate key or part of a candidate key. Equivalently, a transitive dependency exists when a nonprime attribute determines another nonprime attribute.


2 Answers

Outside of a Maven plugin, you can do this programmatically using Aether. There is a method readArtifactDescriptor that does exactly this:

Gets information about an artifact like its direct dependencies and potential relocations.

First, add the Aether dependencies to your POM:

<dependencies>
    <dependency>
        <groupId>org.eclipse.aether</groupId>
        <artifactId>aether-impl</artifactId>
        <version>${aetherVersion}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.aether</groupId>
        <artifactId>aether-connector-basic</artifactId>
        <version>${aetherVersion}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.aether</groupId>
        <artifactId>aether-transport-file</artifactId>
        <version>${aetherVersion}</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.aether</groupId>
        <artifactId>aether-transport-http</artifactId>
        <version>${aetherVersion}</version>
    </dependency>
    <dependency>
        <groupId>org.apache.maven</groupId>
        <artifactId>maven-aether-provider</artifactId>
        <version>${mavenVersion}</version>
    </dependency>
</dependencies>
<properties>
    <aetherVersion>1.1.0</aetherVersion>
    <mavenVersion>3.3.9</mavenVersion>
</properties>

Then you can have:

public static void main(final String[] args) throws Exception {
    DefaultServiceLocator locator = MavenRepositorySystemUtils.newServiceLocator();
    RepositorySystem system = newRepositorySystem(locator);
    RepositorySystemSession session = newSession(system);

    RemoteRepository central = new RemoteRepository.Builder("central", "default", "http://repo1.maven.org/maven2/").build();

    Artifact artifact = new DefaultArtifact("groupId:artifactId:version");
    ArtifactDescriptorRequest request = new ArtifactDescriptorRequest(artifact, Arrays.asList(central), null);
    ArtifactDescriptorResult result = system.readArtifactDescriptor(session, request);

    for (Dependency dependency : result.getDependencies()) {
        System.out.println(dependency);
    }
}

private static RepositorySystem newRepositorySystem(DefaultServiceLocator locator) {
    locator.addService(RepositoryConnectorFactory.class, BasicRepositoryConnectorFactory.class);
    locator.addService(TransporterFactory.class, FileTransporterFactory.class);
    locator.addService(TransporterFactory.class, HttpTransporterFactory.class);
    return locator.getService(RepositorySystem.class);
}

private static RepositorySystemSession newSession(RepositorySystem system) {
    DefaultRepositorySystemSession session = MavenRepositorySystemUtils.newSession();
    LocalRepository localRepo = new LocalRepository("target/local-repo");
    session.setLocalRepositoryManager(system.newLocalRepositoryManager(session, localRepo));
    // set possible proxies and mirrors
    session.setProxySelector(new DefaultProxySelector().add(new Proxy(Proxy.TYPE_HTTP, "host", 3625), Arrays.asList("localhost", "127.0.0.1")));
    session.setMirrorSelector(new DefaultMirrorSelector().add("my-mirror", "http://mirror", "default", false, "external:*", null));
    return session;
}

What this does is creating a Aether repository system and telling it to read the artifact descriptor of a given artifact. The artifact is constructed with the constructor new DefaultArtifact("...") giving it the wanted coordinates.

A request object is created with this artifact and the list of repositories to fetch it from. In the above sample, only Maven Central was added, but you could add more RemoteRepository by creating them with the RemoteRepository.Builder class. After calling readArtifactDescriptor, the result contains the list of direct dependencies, that can be retrieved with getDependencies().

Proxies and mirrors can be configured with the help of the DefaultProxySelector and DefaultMirrorSelector respectively. DefaultProxySelector.add takes a Proxy as argument, which can be created with its constructor by passing it its type (like "http"), host, port and optionally an Authentication (take a look at the AuthenticationBuilder class to create authentication objects), and a list of non-proxied host. In the same way, DefaultMirrorSelector.add takes its id, URL, type (which is "default" for Maven, but you could have P2 for example), whether it is a repository manager, the actual repository ids mirrored (according to the mirror specification), and the repository type not mirrored.

like image 151
Tunaki Avatar answered Sep 30 '22 15:09

Tunaki


The following workflow seems to be ok:

  1. Download the pom from Maven central, put it a separate directory and name it pom.xml.

  2. Apply mvn dependency:list -DexcludeTransitive and grab the console output.

  3. Filter the list of dependencies from the console output.

like image 44
J Fabian Meier Avatar answered Sep 30 '22 16:09

J Fabian Meier