Home

Skip to end of metadata
Go to start of metadata
Aether has moved to Eclipse
This wiki is obsolete and no longer maintained. Visit http://www.eclipse.org/aether/support/ instead.









































What is Aether?

Did you ever want to integrate Maven's dependency resolution mechanism into your application and ended up trying to embed Plexus and an entire Maven distribution? Did you ever want to use Maven's dependency resolution mechanism in a multi-threaded fashion and got burned by the stateful singletons in there? Did you ever want to have a little more control over how Maven calculates the resolved dependency graph, say use another strategy for conflict resolution?

Well, Aether is the answer. It's a standalone library to resolve, install and deploy artifacts the Maven way.

Getting Aether

If you would like to take Aether for a test drive, these are the XML bits for your POM to get it onto your class path:

<project>
  ...
  <properties>
    <aetherVersion>1.12</aetherVersion>
    <mavenVersion>3.0.3</mavenVersion>
    <wagonVersion>1.0-beta-7</wagonVersion>
  </properties>
  ...
  <dependencies>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-api</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-util</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-impl</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-connector-file</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-connector-asynchttpclient</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.sonatype.aether</groupId>
      <artifactId>aether-connector-wagon</artifactId>
      <version>${aetherVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-aether-provider</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven.wagon</groupId>
      <artifactId>wagon-ssh</artifactId>
      <version>${wagonVersion}</version>
    </dependency>
  </dependencies>
  ...
</project>

Let's have a closer look at these dependencies and what they are used for:

  • aether-api
    This JAR contains the application programming interfaces that clients of Aether use. The entry point to the system is org.sonatype.aether.RepositorySystem.
  • aether-util
    Here are various utility classes and ready-made components of the repository system collected.
  • aether-impl
    This archive hosts many actual implementation classes of the repository system. Unless one intents to customize internals of the system or needs to manually wire it together, clients should not access any classes from this JAR directly.
  • aether-connector-file
    The transport layer that handles the uploads/downloads of artifacts is realized by so called repository connectors. This particular connector adds support for transfers to and from file: URLs.
  • aether-connector-asynchttpclient
    This connector enables access to http: and https: based repositories.
  • aether-connector-wagon
    This connector is based on Maven Wagon and can employ any existing Wagon providers.
  • maven-aether-provider
    This dependency provides the pieces to employ Maven POMs as artifact descriptors and extract dependency information from them. Furthermore, it provides the handling of the other metadata files used in a Maven repository.
  • wagon-ssh
    This dependency adds support for tranfers using the scp: and sftp: schemes. Its inclusion in the above POM snippet is merely a suggestion, use whatever Wagon providers fit your needs.

Note: Aether targets Java 1.5+ so be sure to set your compiler settings accordingly.

Setting Aether Up

Aether's implementation consists of a bunch of components that need to be wired together to get a complete repository system. To do so, one can still use a Plexus container (or any other IoC container that supports Plexus components like Sisu). For instance, assuming you add a dependency on org.codehaus.plexus:plexus-container-default:1.5.5 to your POM the following code fragment discovers the various Aether components from the thread context class loader and wires the system together:

import org.codehaus.plexus.DefaultPlexusContainer;
import org.sonatype.aether.RepositorySystem;

...
    private static RepositorySystem newRepositorySystem()
        throws Exception
    {
        return new DefaultPlexusContainer().lookup( RepositorySystem.class );
    }
...

To get an instance of the repository system without an IoC container, the classes from the default implementation of Aether provide no-arg constructors and setters to manually wire the components together. Since this isn't really fun to code, the repository system additionally supports wiring via a lightweight service locator pattern. This service locator infrastructure consists of merely two small interfaces, namely org.sonatype.aether.spi.locator.Service and org.sonatype.aether.spi.locator.ServiceLocator. The components themselves implement the Service interface, and the client of the repository system provides to them an implementation of the ServiceLocator to query other components from. The module maven-aether-provider provides a simple service locator whose usage looks like shown below:

import org.apache.maven.repository.internal.DefaultServiceLocator;
import org.sonatype.aether.connector.wagon.WagonProvider;
import org.sonatype.aether.connector.wagon.WagonRepositoryConnectorFactory;

...
    private static RepositorySystem newRepositorySystem()
    {
        DefaultServiceLocator locator = new DefaultServiceLocator();
        locator.setServices( WagonProvider.class, new ManualWagonProvider() );
        locator.addService( RepositoryConnectorFactory.class, WagonRepositoryConnectorFactory.class );

        return locator.getService( RepositorySystem.class );
    }
...

The DefaultServiceLocator already knows about all the components from aether-impl and maven-aether-provider, so the remaining missing bits that it needs to be told about are zero or more repository connectors. Once the locator's internal service registry is populated, the call to getService() will create the repository system and recursively initialize its sub components.

For the future, it's intended to provide an additional service locator implementation that is capable of discovering components automatically from the class path.

Creating a Repository System Session

Aether and its components are designed to be stateless and as such all configuration has be passed into the methods. When one makes multiple requests to resolve dependencies, a fair amount of settings usually remains the same across these method calls, like the proxy settings or the path to the local repository. Those settings that tend to be the same for an entire usage session of the repository system are represented by an instance of org.sonatype.aether.RepositorySystemSession. Using classes from maven-aether-provider, creating such a session that mimics Maven's setup can be done like this:

import org.apache.maven.repository.internal.MavenRepositorySystemSession;

...
    private static RepositorySystemSession newSession( RepositorySystem system )
    {
        MavenRepositorySystemSession session = new MavenRepositorySystemSession();

        LocalRepository localRepo = new LocalRepository( "target/local-repo" );
        session.setLocalRepositoryManager( system.newLocalRepositoryManager( localRepo ) );

        return session;
    }

As you see, the only setting that must be specified is the local repository, other settings are initialized with default values. Please have a look at the API docs for MavenRepositorySystemSession to learn about all the other things you can configure for a session.

If you seek a close cooperation with stock Maven and want to read configuration from the user's settings.xml, you should have a look at the library org.apache.maven:maven-settings-builder which provides the necessary bits.

Resolving Dependencies

Extending the previous code snippets, the snippet below demonstrates how to actually resolve the transitive dependencies of org.apache.maven:maven-profile:2.2.1 in this example and to dump the result as a class path to the console:

    public static void main( String[] args )
        throws Exception
    {
        RepositorySystem repoSystem = newRepositorySystem();

        RepositorySystemSession session = newSession( repoSystem );

        Dependency dependency =
            new Dependency( new DefaultArtifact( "org.apache.maven:maven-profile:2.2.1" ), "compile" );
        RemoteRepository central = new RemoteRepository( "central", "default", "http://repo1.maven.org/maven2/" );

        CollectRequest collectRequest = new CollectRequest();
        collectRequest.setRoot( dependency );
        collectRequest.addRepository( central );
        DependencyNode node = repoSystem.collectDependencies( session, collectRequest ).getRoot();

        DependencyRequest dependencyRequest = new DependencyRequest( node, null );

        repoSystem.resolveDependencies( session, dependencyRequest  );

        PreorderNodeListGenerator nlg = new PreorderNodeListGenerator();
        node.accept( nlg );
        System.out.println( nlg.getClassPath() );
    }

So once you have initialized the repository system and created a session, the general pattern is to create some request object, call its setters to configure the request, do the operation and evaluate the result object. The module aether-demo from the Aether source repository provides a more extensive demonstration of Aether and its use, so feel free to play with that.

To learn about how you can control the calculation of transitive dependencies, please see the article about the Introduction.

Aether inside Maven

Aether is not just another way to do Maven-like dependency resolution, it is the library that Maven 3 actually integrates for all the dependency related work. So if you are curious how to use Aether from your Maven plugin, check out Using Aether in Maven Plugins.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.
  1. Sep 16, 2010

    Anonymous says:

    Hi, The sniplet to initialize aether without plexus, seems to be wrong. I can't...

    Hi,

    The sniplet to initialize aether without plexus, seems to be wrong. I can't locate ManualWagonProvider class (not found in aether-impl-1.4, aether-connector-wagon-1.4, maven-aether-provider).

  2. Sep 20, 2010

    Luke Patterson says:

    the snippets are great it would be awesome though to have a sample project that...

    the snippets are great

    it would be awesome though to have a sample project that I can just check out and start messing around with, preferably one that uses SPI component lookup

  3. Sep 27, 2010

    Baptiste MATHUS says:

    Hi, ManualWagonProvider: http://github.com/sonatype/sonatype-aether/blob/m...
  4. Dec 10, 2010

    Anonymous says:

    The snippets don't compile.  DefaultServiceLocator#setServices() expects a...

    The snippets don't compile. 

    DefaultServiceLocator#setServices() expects an Object array as second argument.

    When fixing that one, an exception is thrown when running the example:

    java.lang.IllegalArgumentException: version resolver has not been specified at org.sonatype.aether.impl.internal.DefaultRepositorySystem.setVersionResolver(DefaultRepositorySystem.java:143) at org.sonatype.aether.impl.internal.DefaultRepositorySystem.initService(DefaultRepositorySystem.java:123) at org.sonatype.aether.impl.internal.DefaultServiceLocator.getServices(DefaultServiceLocator.java:172) at org.sonatype.aether.impl.internal.DefaultServiceLocator.getService(DefaultServiceLocator.java:124) at be.argenta.AehterMain.newRepositorySystem(AehterMain.java:54) at be.argenta.AehterMain.main(AehterMain.java:20)
    Exception in thread "main" java.lang.NullPointerException at be.argenta.AehterMain.newSession(AehterMain.java:44) at be.argenta.AehterMain.main(AehterMain.java:22)
    java.lang.IllegalArgumentException: version resolver has not been specified

    at org.sonatype.aether.impl.internal.DefaultRepositorySystem.setVersionResolver(DefaultRepositorySystem.java:143)

    at org.sonatype.aether.impl.internal.DefaultRepositorySystem.initService(DefaultRepositorySystem.java:123)

    at org.sonatype.aether.impl.internal.DefaultServiceLocator.getServices(DefaultServiceLocator.java:172)

    at org.sonatype.aether.impl.internal.DefaultServiceLocator.getService(DefaultServiceLocator.java:124)

    1. Dec 10, 2010

      Benjamin Bentmann says:

      DefaultServiceLocator#setServices() expects an Object array as second argument. ...

      DefaultServiceLocator#setServices() expects an Object array as second argument.

      Actually, the second argument is a varargs so be sure to use Java 1.5+.

      java.lang.IllegalArgumentException: version resolver has not been specified

      Be sure to use the right service locator, i.e. org.apache.maven.repository.internal.DefaultServiceLocator.

      1. Dec 13, 2010

        Anonymous says:

        Weird, I was using Java 6, got no other jdk installed. Ah yes, I was using ...

        Weird, I was using Java 6, got no other jdk installed.

        Ah yes, I was using org.sonatype.aether.impl.internal.DefaultServiceLocator, thanks

  5. Dec 12, 2010

    Anonymous says:

    thank you for you valuable post. diagnostic scanner

    thank you for you valuable post.

    diagnostic scanner

  6. Dec 14, 2010

    Anonymous says:

    Hey Benjamin, I am currently working on a project dealing with m2 repositories,...

    Hey Benjamin,

    I am currently working on a project dealing with m2 repositories, and I have the task of given some projects to find and copy the artifacts from the local m2 repository. My question is whether Aether (or maybe maven itself) has the framework for locating the built artifacts given a group id, artifact id, and version in the m2 repo. Also, if such a framework exists, I was wondering at a high-level how it knows the directory structure in the m2 repo. Does it simply convert a group id to a file path and hope for the best? Or does maven actually have the mechanism to keep track of where an artifact is stored? I thought of building a dummy framework that looks for artifacts this way, but would hate to have to maintain it if file structure changes in future maven releases. Any help is appreciated. If there is a forum or something else that this question would better be facilitated please point me in the right direction. Thanks! Daniel Johnson

    1. Dec 14, 2010

      Benjamin Bentmann says:

      My question is whether Aether (or maybe maven itself) has the framework for loca...

      My question is whether Aether (or maybe maven itself) has the framework for locating the built artifacts given a group id, artifact id, and version in the m2 repo.

      That sounds pretty much like what the example snippet in the section "Resolving Dependencies" does.

      Also, if such a framework exists, I was wondering at a high-level how it knows the directory structure in the m2 repo.

      Repositories have a layout or more generally content type as Aether calls it. This is a simple string identifier which basically denotes the convention/structure by which artifacts are organized.

      Does it simply convert a group id to a file path and hope for the best?

      Yes.

      If there is a forum or something else that this question would better be facilitated please point me in the right direction.

      The Aether user list, see the readme at https://github.com/sonatype/sonatype-aether.

  7. Dec 20, 2010

    Anonymous says:

    Hi How about makeing your own repository layout? Is that as easy as it was in ...

    Hi

    How about makeing your own repository layout?

    Is that as easy as it was in Maven2?

    Thanks

    Lucas

    1. Dec 20, 2010

      Benjamin Bentmann says:

      How about makeing your own repository layout? That is accomplished by providing ...

      How about makeing your own repository layout?

      That is accomplished by providing your own implementation of org.sonatype.aether.spi.connector.RepositoryConnectorFactory (see aether-spi module).

  8. Jan 04, 2011

    Anonymous says:

    When will the Aether Ant Tasks be released?  I am currently making extensiv...

    When will the Aether Ant Tasks be released?  I am currently making extensive use of the Maven Ant Tasks which do not support Maven 3.

  9. Mar 14, 2011

    Yegor Bugayenko says:

    Would be nice to know how to integrate Aether with slf4j or log4j (or any other ...

    Would be nice to know how to integrate Aether with slf4j or log4j (or any other logging facility).

  10. Apr 14, 2011

    Anonymous says:

    I believe there is a typo in the example.  The dependency shows <artifa...

    I believe there is a typo in the example.  The dependency shows

    <artifactId>wagon-http-ssh</artifactId>

    It should be

    <artifactId>wagon-ssh</artifactId>
  11. Jun 01, 2011

    Anonymous says:

    I am currently working on a project dealing with m2 repositories, and Iipad2 Cab...

    I am currently working on a project dealing with m2 repositories, and Iipad2 Cables have the task of given some projects to find and copy the artifacts from the local m2 repository. My question is whether Aether (or maybe maven itself) has the framework for locating the built artifacts given a group id, artifact id, and version in the m2 repo. Also, if such a framework exists, I was wondering at a high-level how it knows the directory structure in the m2 repo.

  12. Jun 24, 2011

    Anonymous says:

    Hi, I am using aether to query the maven repository. I need to get the age of an...

    Hi, I am using aether to query the maven repository. I need to get the age of an artifact. The repository is artifactory and the age indicates time since that artifact was deployed on the repository.

    I did not see any API in aether to get this...is there anyway I can get this information using the aether APIs?

    1. Jun 24, 2011

      Benjamin Bentmann says:

      No, Aether and the Maven repository format in general do not track the upload ti...

      No, Aether and the Maven repository format in general do not track the upload time of an artifact.

  13. Jul 13, 2011

    Anonymous says:

    Hi!  I'm working on a tool at work that is using Aether to resolve arti...

    Hi!  I'm working on a tool at work that is using Aether to resolve artifacts from our remote repo, so that we can launch them.  We're giving the users a combo box with a list of available versions of software to launch, and we're populating it by using a VersionRangeRequest. Problem is, it seems to be favoring the local metadata cache instead of the remote metadata, and we're not seeing new versions as they are deployed into the remote repo.  The user has to blow away their local repo to see new versions. Any gotchas I should know about here?

    1. Jul 13, 2011

      Benjamin Bentmann says:

      The local repo is a cache, so what you describe is expected behavior. To enforce...

      The local repo is a cache, so what you describe is expected behavior. To enforce refetching from the remote repo at the time the VersionRangeRequest is made, you can set the update policy on the RemoteRepository or the repo session to "always".

  14. Feb 13, 2013

    Anonymous says:

    I'm having issues with programmatic deployment of artifact(s) to the Nexus repo....

    I'm having issues with programmatic deployment of artifact(s) to the Nexus repo. I'm using code that is provided here and in https://github.com/sonatype/sonatype-aether/blob/master/aether-demo/src/main/java/demo/DeployArtifacts.java. Exception that I am getting is java.lang.RuntimeException: org.sonatype.aether.deployment.DeploymentException: Failed to deploy artifacts/metadata: No connector available to access repository repoId (_file:///path/to/repo_) of type using the available factories WagonRepositoryConnectorFactory, FileRepositoryConnectorFactory...

    Protocol used to connect with repo is file:// and as per maven documentation it is supported by default, without the need for Wagon connector usage. Please advise what to do.

    1. Feb 13, 2013

      Benjamin Bentmann says:

      No connector available to access repository repoId (_file:///path/to/repo_) of t...

      No connector available to access repository repoId (_file:///path/to/repo_) of type using the available factories

      Your RemoteRepository appears to have an empty content type, you want to set "default" for a Maven-2 layout.

      1. Feb 13, 2013

        Anonymous says:

        Thanks Benjamin! Issue is solved now. Just one more question if you don't m...

        Thanks Benjamin! Issue is solved now.

        Just one more question if you don't mind. Is there a way to mimic "generatePom=true" feature of maven's deploy:deploy-file plugin?

        Thanks

        1. Feb 13, 2013

          Benjamin Bentmann says:

          Is there a way to mimic "generatePom=true" feature of maven's deploy:deploy-file...

          Is there a way to mimic "generatePom=true" feature of maven's deploy:deploy-file plugin?

          No, but you can easily implement this yourself, the output of "generatePom=true" is not more than a string template with some coordinates inserted. If your artifacts have dependencies on their own, you might however want to consider crafting a proper POM for them, artifacts without proper dependency declarations tend to cause frustration down the road.

          For any further questions, please use the support infrastructure at Eclipse as indicated at the top of this page.

Add Comment