This Confluence has been LDAP enabled, if you are an ASF Committer, please use your LDAP Credentials to login. Any problems file an INFRA jira ticket please.

Child pages
  • Project Dependency Trees schema

Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: project vs product (thanks to discussions with rfscholte)
Page properties
Status 
Status
titleDRAFT
Version 
Issue(s) 
Sources 
Developer(s) Stephen Connolly

Status

This RFC is currently in the DRAFT state. Nothing in this RFC has been agreed or confirmed.

...

The aim of the Project Dependency Trees model is to resolve these issues.

Project Dependency Trees documents are intended to be machine generated based on build time information. Build tools not able to generate these documents solely from build information are considered in need for corresponding enhancements.

Model evolution

One of the top level elements of the Maven POM is the modelVersion element that specifies the model version for the POM. To date there have been two model versions 3.0.0 and 4.0.0. In both cases, a critical issue for changing the model version is that older clients cannot parse the newer model. This required the forking of Central (which is why central is repo.maven.org/maven2 because 4.0.0 was introduced with Maven 2 and Maven 1 clients could not parse the new model version)

...

NOTE: while we need to ensure that artifacts can be consumed by both older clients, we do not have to ensure that the older clients get the exactly correct dependency tree. Rather we should make the best effort possible to give older clients as good a dependency tree as we can give them.

...

OPEN QUESTION: do we deploy the newer modelVersion POM as the groupId:artifactId::version::pom or as groupId:artifactId::version:build:pom? The first form ensures that the POM cannot be used as a parent by modelVersion 4.0.0 projects as they will blow up immediately, however there has been an established practice of using <packaging>pom</packaging> for projects that produce non-standard artifacts and want to opt-out of the standard lifecycle binding, and thus we would break consumption of those "side" artifacts by legacy clients. Perhaps the solution is to follow the second form (i.e. it gets deployed with <classifier>build</classifier> and either put a Maven enforcer execution into the modelVersion 4.0.0 POM or use the <prerequisites> tag to try and at least alert that the parent is invalid.

Open Questions

  • Hervé Boutemy: Should we move away from the term Project for this document but use Product, as Software Product in Agile?
    Issue: a "project" is either a "Top Level Project" (ex: Maven), either a "mono-module project" (ex: shared-utils), either one "module of a multi-module project" (ex: maven-artifact module of Maven core)
    And even see Wikipedia "Project (disambiguation)" article: "Project, a temporary endeavor undertaken to create a unique product or service"
    A build file (pom.xml when used by Maven to build an artifact) or description of attributes of an artifact (pom.xml when in repository) is clearly not temporary: in agile methodology, this issue has been fixed by having a product, with a product manager.

Project Dependency Trees

<project> element

The project dependency trees model consists of a top level <project> tag and three types of immediate children elements:

Code Block
languagexml
<project modelVersion="..." groupId="..." artifactId="..." [platformId="..."] version="...">

...


  <generator .../>
  <information .../>

...


  <license .../>

...


  <artifacts .../>

...


</project>

The following are mandatory elements:

  • modelVersion attribute - containing the model version of the project dependency trees, which can be used by consumers to select an XSLT tranformation to apply against the model if they need to translate a newer modelVersion to one that the consumer can parse.
  • groupId attribute - containing the groupId of the project
  • artifactId attribute - containing the artifactId of the project
  • version attribute - containing the version of the project
  • artifacts element - at least one element must be present, there are uniqueness constraints on this element relating to platformId attributes
  • generator element - there must be exactly one generator element present. This element identifies the build tool that generated the Project Dependency Trees document.

The following are optional elements:

  • platformId attribute - this is only present for additional atomic deployments of platform specific artifacts taking place after the initial deployment. When present there must be exactly one artifacts element and it must have the matching platformId as specified on the project element.
  • information element - there can be at most one of these, it contains additional information about the project and its artifacts
  • license elements - there can be any number of these, each element represents a set of licensing terms under which the project's artifacts are made available.

    In the vast majority of cases, projects are covered by a single set of license terms. Those cases will have a single <license> element that provides the SPDX expression for the license terms, e.g. <license spdx="(LGPL-2.0 AND GPL-2.0)"> which would indicate that portions of the code are LGPL and other portions are GPL.

    In other cases, projects are dual or multi-licensed. Those cases will have multiple <license> elements where the consumer is free to select any one of those expressions as the license terms that they will be complying with, thus <license spdx="GPL-2.0"/><license spdx="(BSD-2-Clause AND Apache-2.0)"/> would indicate that the consumer either has to comply with the terms of the GPL or both BSD and Apache licenses. While SPDX syntax would allow for <license spdx="(GPL-2.0 OR BSD-2-Clause AND Apache-2.0)"/> as an equivalent expression, dual licensing seems important enough that it should be separated out explicitly in separate elements as the priority rules of SPDX expression syntax - while clear and unambiguous - can be confusing to the uninitiated with regard to OR being lower priority than AND

<generator> element

The generator element identifies the build tool that created the document.

Code Block
languagexml
<generator name="..." version="..." url="..."/>

The following are mandatory elements

  • name the human readable name of the build tool, e.g. Apache MavenApache BuildrRakeGradle, etc.
  • version the version of the build tool
  • url the url of the home page of build tool, e.g. http://maven.apache.orghttp://buildr.apache.orghttp://rake.rubyforge.orghttp://gradle.org, etc. This is not the download URL for the build tool

There are no optional elements

<information> element

The information element consists of optional information about the project and its artifacts.

TODO: decide what, if any, additional content can go in here, SCM, Issue trackers, URLs, Mailing Lists, etc.

Code Block
languagexml
<information>

...


...

  <name .../>

...


...

  <description .../>

...


</information>

There are no mandatory elements

...

The license element consists of information about one set of licensing terms that the project and its artifacts is made available under.

Code Block
languagexml
<license spdx="..."/

...

There is one mandatory element

...

The artifacts element consists of details of all the artifacts produced by the project. The artifacts are partitioned by platformId.

Code Block
languagexml
<artifacts [platformId="..."]>

...


...

  <artifact .../>

...


</artifacts>

There is one mandatory element:

...

The artifact element consists of the details of a specific artifact produced by the project.

Code Block
languagexml
<artifact type="..."

...

 [classifier="..."]>

...


  <information .../>

...


  <license .../>

...


  <component .../>

...


  <provides .../>

...


  <requires .../>

...


  <supports .../>

...


</artifact>

There is one mandatory element:

  • type attribute - this is the file type of the artifact. NOTE: this is the actual file extension that the artifact is deployed with, not the "packaging" type nor the "dependency" type which would require consumers to have awareness of all "packaging" to file type mappings.

...

The component element consists of hints to the consumer of type specific components that are present within the artifact for consideration during conflict resolution.

Code Block
languagexml
<component id="..."/>

There is one mandatory element:

...

One anticipated usage of the component element is for JAR artifacts that the id would correspond to the Java 9+ module identifiers as in Java 9+ the module identifier must be unique on the module path and hence conflict resolution will be required to process the dependency tree into a flattened modulepath with validation of uniqueness of component identifiers enforced.

<provides> element

The provides element indicates that this artifact embeds equivalent content to the named dependency

Code Block
languagexml
<provides groupId="..." artifactId="..." [platformId="..."] [version="..."] range="..." type="..." [classifier="..."]/>

The following are mandatory elements

  • groupId attribute - the groupId of the embedded dependency
  • artifactId attribute - the artifactId of the embedded dependency
  • range attribute - the version range of the embedded dependency - this will either be a hard range, e.g. [1.0] where the exact dependency has been explicitly embedded or a compatibility range, e.g. [1.0,2.0) where there is an "aliasing" or equivalence within an agreed API contract
  • type attribute - this is the file type of the artifact. NOTE: this is the actual file extension that the artifact is deployed with, not the "packaging" type nor the "dependency" type which would require consumers to have awareness of all "packaging" to file type mappings.

The following are optional elements

  • platformId attribute - the platformId of the embedded dependency
  • classifier attribute - the classifier of the embedded dependency
  • version attribute - the version of the embedded dependency. When present, the range attribute should probably be a hard range for this version only. When absent, this indicates that there has been an "aliasing" and as such the range attribute should reflect the compatibility constraints of the alias implementation.

Some examples may assist in the relative use-cases of the range and version attributes.

  • org.slf4j:log4j-over-slf4j provides an alternative set of implementations of the log4j:log4j::[1.0,2.0) APIs. It does not actually include any content from any of the log4j jars. Rather the exact same public API contract has been re-implemented. Thus the org.slf4j:log4j-over-slf4j artifact might well state: <provides groupId="log4j" artifactId="log4j" range="[1.0,2.0)" type="jar"/> there is no version attribute because the content has not been replicated
  • ch.qos.logback:logback-classic is an SPI implementation for org.slf4j:slf4j-api. As slf4j-api requires that there is at most one SPI implementation on the classpath, it may be useful for all SPI implementations to declare <provides groupId="org.slf4j" artifactId="slf4j-spi-impl" range="[1.7.0,1.8.0)" type="jar"/> (this would also need slf4j-api to have a <supports groupId="org.slf4j" artifactId="slf4j-spi-impl" range="[1.7.0,1.8.0)" type="jar"/> tag to trigger conflict resolution. If slf4j-api did not have an internal fallback implementation then it would use a <requires> tag instead of a <supports> tag.
  • überjars which basically aggregate multiple jar files would specify the version tag. Thus org.hamcrest:hamcrest-all::1.3:jar would have the <provides groupId="org.hamcrest" artifactId="hamcrest-core" version="1.3" range="[1.3]" type="jar"/> because it literally duplicates the exact content of org.hamcrest:hamcrest-core::1.3. The range needs to be a hard range as it has been embedded directly and is an intrinsic part of the artifact.

<requires> element

The requires element indicates a mandatory transitive dependency.

Code Block
languagexml
<requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."] [modelVersion="..."]>
  <component .../>
  <license .../>
  <provides .../>
  <requires .../>
  <supports .../>
  <including>
    ...
  </including>
  <excluding>
    ...
  </excluding>
</requires>

The following are mandatory elements:

  • groupId attribute - the groupId of the dependency
  • artifactId attribute - the artifactId of the dependency
  • version attribute - the version of the dependency that was resolved at build time and is the recommended default version of the dependency to use. The child elements of this requires element represent the information for the specified version of the dependency
  • range attribute - the version range of the dependency. This may be the modelVersion 4.0.0 style "unspecified here is a hint" style version, e.g. 1.0. Preference would be that it uses the version attribute as a lower bound, but any valid Maven version range is acceptable.
  • type attribute - this is the file type of the artifact. NOTE: this is the actual file extension that the artifact is deployed with, not the "packaging" type nor the "dependency" type which would require consumers to have awareness of all "packaging" to file type mappings.

The following are optional elements:

  • platformId attribute - the platformId of the dependency
  • classifier attribute - the classifier of the dependency
  • modelVersion attribute - if the dependency's Project Dependency Tree uses a modelVersion less than or equal to the modelVersion of the root project tag in this Project Dependency Tree then this attribute must be omitted, otherwise the tag will contain the modelVersion of the dependency's Project Dependency Tree. The presence of this attribute is an indicator to the consumer that the contained elements were the result of an XSLT transformation of the dependency's tree and thus, if the consumer understands this newer modelVersion then a more correct view of the dependency tree could be obtained by fetching and parsing the dependency's Project Dependency Tree directly and substituting the parsed contents.
  • license elements - there can be any number of these, they reflect the license terms of the dependency as detailed from the dependency's tree.
  • component elements - there can be any number of these. If present they are a hint to the consumer about type specific components that are present within the dependency and that may need to be considered during conflict resolution. For example, with a JAR artifact, the components may be Java 9+ module identifiers. Consumers may ignore the component elements if they choose.
  • provides elements - there can be any number of these. If present they indicate that this dependency embeds equivalent content to the named dependency. The exact meaning of "embeds" is dependent on the type of artifact and the type of dependency.
  • requires elements - there can be any number of these. If present they indicate that the dependency has a mandatory transitive dependency.
  • supports element - there can be any number of these. If present they indicate that the dependency has an optional transitive dependency.  
  • including element - there can be at most one of these. If present it indicates that the dependency has been augmented by its consumer to "correct" the dependency tree.
  • excluding element - there can be at most one of these. If present it indicates that the dependency has been augmented by its consumer to "correct" the dependency tree.

<supports> element

The supports element indicates an optional transitive dependency.

Code Block
languagexml
<supports groupId="..." artifactId="..." [platformId="..."] [version="..."] range="..." type="..." [classifier="..."]/>

The following are mandatory elements

  • groupId attribute - the groupId of the dependency
  • artifactId attribute - the artifactId of the dependency
  • range attribute - the version range of the dependency. This may be the modelVersion 4.0.0 style "unspecified here is a hint" style version, e.g. 1.0. Preference would be that it uses the version attribute as a lower bound, but any valid Maven version range is acceptable.
  • type attribute - this is the file type of the artifact. NOTE: this is the actual file extension that the artifact is deployed with, not the "packaging" type nor the "dependency" type which would require consumers to have awareness of all "packaging" to file type mappings.

The following are optional attributes

  • platformId attribute - the platformId of the dependency
  • version attribute - the version of the dependency that was resolved at build time and is the recommended default version of the dependency to use. 
  • classifier attribute - the classifier of the dependency

<including> element

The including element indicates that a dependency has been augmented by its immediate consumer.

Code Block
languagexml
<including>
  <component .../>
  <provides .../>
  <requires .../>
  <supports .../>
</including>

There are no mandatory elements

The following are optional elements:

  • component elements - there can be any number of these. If present they are a hint to the consumer about type specific components that are present within the dependency and that may need to be considered during conflict resolution. For example, with a JAR artifact, the components may be Java 9+ module identifiers. Consumers may ignore the component elements if they choose.
  • provides elements - there can be any number of these. If present they indicate that this dependency embeds equivalent content to the named dependency. The exact meaning of "embeds" is dependent on the type of artifact and the type of dependency.
  • requires elements - there can be any number of these. If present they indicate that the dependency has a mandatory transitive dependency.
  • supports element - there can be any number of these. If present they indicate that the dependency has an optional transitive dependency.  

<excluding> element

The including element indicates that a dependency has been augmented by its immediate consumer.

Code Block
languagexml
<excluding>
  <component .../>
  <provides .../>
  <requires .../>
  <supports .../>
</excluding>

There are no mandatory elements

The following are optional elements:

  • component elements - there can be any number of these. If present they indicate that this dependency and its transitive dependency tree - from the point of view of the immediate parent - should have the corresponding <component> elements expunged. The id can be either exact match or * style wildcard matches.
  • provides elements - there can be any number of these. If present they indicate that this dependency and its transitive dependency tree - from the point of view of the immediate parent - should have the corresponding <provides> elements expunged. The groupIdartifactId, etc coordinates can be either exact matches or * style wildcard matches.
  • requires elements - there can be any number of these. If present they indicate that this dependency and its transitive dependency tree - from the point of view of the immediate parent - should have the corresponding <requires> elements expunged. The groupIdartifactId, etc coordinates can be either exact matches or * style wildcard matches.
  • supports element - there can be any number of these. If present they indicate that this dependency and its transitive dependency tree - from the point of view of the immediate parent - should have the corresponding <supports> elements expunged. The groupIdartifactId, etc coordinates can be either exact matches or * style wildcard matches.  

Example

The following is a pseudo-example of a Project Dependency Tree

...

Code Block
languagexml
 <project modelVersion="..." groupId="..." artifactId="..." [platformId="..."] version="...">

...


...

    <generator name="Apache Maven" version="5.0.0" url="http://maven.apache.org"/>
    <information>
        <!-- container for descriptive information -->

...


...

 

...

 

...

      [<name>...</name>]

...


...

 

...

 

...

      [<description>...</description>]

...


...

 

...

 

...

      ...

...


...

    </information>

...


    <license spdx="..."/>

...


    <license spdx="..."/>

...


    ...

...


    <license spdx="..."/>

...


...

    <artifacts [platformId="..."]>

...


...

 

...

 

...

      <artifact type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

       <information>
                <!-- optional element if need to override root level information for specific artifacts -->

...


...

 

...

 

...

 

...

 

...

        </information>

...


...

 

...

 

...

 

...

 

...

        <!--

...

 

...


...

 

...

 

...

 

...

 

...

          components are internal packaging constructs used by the packaging type but requiring more general validation

...


...

 

...

 

...

 

...

 

...

 

...

         e.g. for Java 9+ the ids could be the module ids if we wanted to validate that the module ids were unique in the

...


...

 

...

 

...

 

...

 

...

 

...

         effective tree.

...


...

 

...

 

...

 

...

 

...

        -->

...


...

 

...

 

...

 

...

 

...

        <component id="..."/>

...


...

 

...

 

...

 

...

 

...

        <component id="..."/>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

 

...

 

...

        <component id="..."/>

...


...

 

...

 

...

 

...

 

...

        <!--

...


              If the artifact has a different set of licenses from those defined at the project level, we define the licenses

...


              of this artifact here. Otherwise we defer to the licenses defined at the top level of the project.

...


...

 

...

 

...

 

...

 

...

 

...

         licensing is a top level concern, and legitimately can vary per artifact. Let's not solve license compatibility,

...

 

...


...

 

...

 

...

 

...

 

...

          rather 

...

leverage https://spdx.org/

...


...

 

...

 

...

 

...

 

...

        -->

...


...

 

...

 

...

 

...

 

...

        <license spdx="..."/>

...


...

 

...

 

...

 

...

 

...

        <license spdx="..."/>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

 

...

 

...

        <license spdx="..."/>

...


...

 

...

 

...

 

...

 

...

        <!--

...


...

 

...

 

...

 

...

 

...

 

...

         provides is a marker that we have duplication of content. This could be because we are much like the many servlet-api jar

...


...

 

...

 

...

 

...

 

...

 

...

         files where there are many GAV's of the same javax.servlet:servlet-api:3.0 thus we could have the case where

...


...

 

...


...

 

...

 

...

 

...

           org.jboss.spec.javax.servlet:jboss-servlet-api_3.0_spec:jar:1.0.2.Final PROVIDES javax.servlet:servlet-api:3.0

...


...

 

...

 

...

 

...

 

...

 

...

         org.jboss.spec.javax.servlet:jboss-servlet-api_3.0_spec:jar:1.0.1.Final PROVIDES javax.servlet:servlet-api:3.0

...


...

 

...

 

...

 

...

 

...

 

...

         org.jboss.spec.javax.servlet:jboss-servlet-api_3.0_spec:jar:1.0.0.Final PROVIDES javax.servlet:servlet-api:3.0

...


...

 

...

 

...

 

...

 

...

 

...

         org.mortbay.jetty:servlet-api-3.0:jar:7.0.0pre2 PROVIDES javax.servlet:servlet-api:3.0

...


...

 

...


...

 

...

 

...

 

...

           similarly
 
              org.slf4j:log4j-over-slf4j:jar:1.7.21 PROVIDES log4j:log4j:[1.0,2)

...


...

 

...


...

 

...

 

...

 

...

           The consumer of the tree can then decide if/when/how to collapse redundant nodes as they see fit.

...


...

 

...


...

 

...

 

...

 

...

           TODO: decide optionality of version and range attributes

...


...

 

...

 

...

 

...

 

...

        -->

...


...

 

...

 

...

 

...

 

...

        <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <!-- no elements here as we have "rebundled" hence implicitly promoted up one level-->

...


...

 

...

 

...

 

...

 

...

        </provides>

...


...

 

...

 

...

 

...

 

...

        <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

 

...

 

...

        <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

        <!--

...


...

 

...

 

...

 

...

 

...

 

...

         requires are the mandatory dependencies. This is effectively a recursive artifact where the GAV is not inherited and

...


...

 

...

 

...

 

...

 

...

 

...

         where we have discarded the information section. If you want those details, fetch that project's dependencies trees.

...


...

 

...

 

...

 

...

 

...

        -->

...


...

 

...

 

...

 

...

 

...

        <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <component id="..."/>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <license spdx:id="..."/>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

 

...

 

...

            ...

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          </requires>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

        </requires>

...


...

 

...

 

...

 

...

 

...

        <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          ...

...


...

 

...

 

...

 

...

 

...

        </requires>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

 

...

 

...

        <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]>

...


...

 

...

 

...

 

...

 

...

 

...

 

...

          ...

...


...

 

...

 

...

 

...

 

...

        </requires>

...


...

 

...

 

...

 

...

 

...

        <!--

...


...

 

...

 

...

 

...

 

...

 

...

         supports are the optional dependencies. We list them here to aid in conflict resolution. We do not include a nested tree

...


...

 

...

 

...

 

...

 

...

 

...

         as a consumer would only pull them in if the consumer already has its own a requires for them, so we really only

...


...

 

...

 

...

 

...

 

...

 

...

         need to validate the range.

...

 

...


...

 

...


...

 

...

 

...

            TODO: decide optionality of range attribute

...


...

 

...

 

...

 

...

 

...

 

...

         TODO: decide if we want a version 

...

attribute 

...


...

 

...

 

...

 

...

         -->

...


...

 

...

 

...

 

...

 

...

        <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

        <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

 

...

 

...

        <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>

...


...

 

...

 

...

          <including>
                <component id="..."/>
                <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>
                <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]>
                    ...
                </requires>
                <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>
            </including>
            <excluding>
                <component id="..."/>
                <provides groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>
                <requires groupId="..." artifactId="..." [platformId="..."] version="..." range="..." type="..." [classifier="..."]/>
                <supports groupId="..." artifactId="..." [platformId="..."] version="..." [range="..."] type="..." [classifier="..."]/>
            </excluding>
        </artifact>
        <artifact ...>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

      </artifact>

...


...

 

...

 

...

      ...

...


...

 

...

 

...

      <artifact ...>

...


...

 

...

 

...

 

...

 

...

        ...

...


...

 

...

 

...

      </artifact>

...


...

    </artifacts>

...


    <!-- if the project does not specify a platformId then we can include additional platform details that were part of the atomic deployment -->

...


    <artifacts platformId="...">

...


        ...

...


    </artifacts>

...


        ...

...


    <artifacts platformId="...">

...


        ...

...


    </artifacts>

...


</project>

Constructing a Project Dependency Trees model

The following process will be used to construct a Project Dependency Trees model:

  1. For each artifact, construct the list of direct mandatory dependencies
  2. For each artifact, construct the list of direct optional dependencies
  3. For each artifact, construct the list of embedded dependencies
  4. For each artifact, construct the list of licenses
  5. For each artifact, construct the list of components
  6. Construct the Project Dependency Trees of the embedded dependencies
  7. Process the embedded dependency trees. 
    1. Any provides elements should be appended to the list of embedded dependencies. 
    2. Any requires elements should be appended to the list of direct mandatory dependencies. 
    3. Any supports elements should be appended to the list of direct optional dependencies.
    4. Any component elements should be appended to the list of components
    5. Licensing will be assumed to have been correctly defined by the project when the decision was made to embed dependencies
  8. Process the list of direct optional dependencies, removing any duplicates with the list of embedded dependencies (i.e. if in promoting an embedded dependency's supports tags we support it and have also embedded it, then we just have embedded it)
  9. Process the list of direct mandatory dependencies, removing any duplicates with the list of embedded dependencies (i.e. if in promoting an embedded dependency's provides tags we provide it and have also required it, then we just have provided it)
  10. Process the list of direct optional dependencies, removing any duplicates with the list of mandatory dependencies (i.e. if in promoting an embedded dependency's supports tags we support it and have also required it, then we just have required it)
  11. Construct the Project Dependency Trees of the mandatory dependencies

The principle is that 

  • provides tags effectively ensure that the dependency is "promoted up".
  • requires tags retain the tree nesting
  • supports tags do not detail any transitive dependencies as this only comes into play if the consumer already has a requires dependency on the same coordinates and needs to perform conflict resolution.

If a dependency is missing a Project Dependency Trees model, then the same process can be used to construct that model from the modelVersion 4.0.0 POM

TODO define the process for constructing the effective modelVersion 4.0.0 POM

TODO decide if we should include some "well known" conventions, e.g. that:

  • the javadoc and source jar files probably do not have any dependencies
  • the test-jar probably has the test scope dependencies
  • that war artifacts probably have <provides> tags for all jar dependencies
  • etc

The above would probably be generally useful but would complicate the specification of the process for other consumers

Test data set

TODO: We need a cohort of Project Dependency Tree documents for implementations to validate their parsers against and to validate their convertion into modelVersion 4.0.0 POMs (though we may do this using a provided XSLT file, implementations will still need to validate that their have configured their XSLT engine correctly)

TODO: We need a cohort of modelVersion 4.0.0 POMs for implementations to validate their generation of effective Project Dependency Trees in the absence of a deployed Project Dependency Trees document along with the expected effective Project Dependency Tree documents

TODO: We need a cohort of sample transformations of trees to ensure that implementations can correctly aggregate Project Dependency Trees when building new projects that depend on other projects.

Schema

Here is a draft XML schema:

...

TODO: Add the including and excluding elements to the schema

Code Block
languagexml
 <xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xs="http://www.w3.org/2001/XMLSchema" >

...


  <xsd:simpleType name=”coordinate”>

...


    <xsd:restriction base=”xsd:string”>

...


      <!-- TODO add pattern for groupId/artifactId/platformId/version/type/classifier valid values -->

...


    </xsd:restriction>

...


  </xsd:simpleType>

...


  <xs:element name="project">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;project&gt;</code> element is the root of the project

...


        dependency trees.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="modelVersion" type="xs:string"/>

...


      <xs:attribute name="groupId" type="coordinate"/>

...


      <xs:attribute name="artifactId" type="coordinate"/>

...


      <xs:attribute name="version" type="coordinate"/>

...


      <xs:attribute name="platformId" type="coordinate" use="optional"/>

...


      <xs:all>

...


        <xs:element ref="generator" minOccurs="1" maxOccurs="1"/>
        <xs:element ref="information" minOccurs="0" maxOccurs="1"/>

...


        <xs:element ref="license" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="artifacts" minOccurs="1" maxOccurs="unbounded"/>

...


      </xs:all>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="

...

generator">
    <xs:annotation>
      <xs:documentation source="version">5.0.0+</xs:documentation>
      <xs:documentation source="description">
        The <code>&lt;generator&gt;</code> element identifies the build tool
        responsible for creating this document
      </xs:documentation>
    </xs:annotation>
    <xs:complexType>
      <xs:attribute name="name" type="xs:string"/>
      <xs:attribute name="version" type="xs:string"/>
      <xs:attribute name="url" type="xs:string"/>
    </xs:complexType>
  </xs:element>
  <xs:element name="information">
    <xs:annotation>
      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;information&gt;</code> element is a container for 

...


        descriptive information about either all the artifacts in a project or 

...


        a specific artifact.
      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:all>

...


        <xs:element name="name" type="xs:string" maxOccurs="1"/>

...


        <xs:element name="description" type="xs:string" maxOccurs="1"/>

...


        <!-- TODO add additional elements -->

...


      </xs:all>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="license" xmlns:spdx="http://spdx.org/rdf/terms#">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;license&gt;</code> element defines one of the licenses

...


        under which the artifacts are made available. Where a license is 

...


        attached to the <code>&lt;project&gt;</code> element this defines the 

...


        default licenses for all artifacts in the project. Where a license is 

...


        attached to an <code>&lt;artifact&gt;</code> element this signifies 

...


        that the specific artifact is covered by the 

...


        <code>&lt;license&gt;</code> elements defined within that 

...


        <code>&lt;artifact&gt;</code> element. Licenses are identified using 

...


        the <a href="http://spdx.org">SPDX</

...

a> identifiers
     </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="spdx" type="xs:string"/>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="artifacts">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;artifacts&gt;</code> element is a container for 

...


        details of artifacts. When the <code>&lt;artifacts&gt;</code> attribute

...


        is missing, then the artifacts listed are not platform specific.

...


        The <code>&lt;artifacts&gt;</code> must be unique with respect to their

...


        <code>&lt;platformId&gt;</code>, i.e. it cannot be repeated.

...


        If the <code>&lt;project&gt;</code> element has a 

...


        <code>&lt;platformId&gt;</code> then there must be only one

...


        <code>&lt;artifacts&gt;</code> element and it must have the matching

...


        <code>&lt;platformId&gt;</code>.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="platformId" type="coordinate" use="optional"/>

...


      <xs:sequence>

...


        <xs:element ref="artifact" minOccurs="1" maxOccurs="unbounded"/>

...


      </xs:sequence>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="artifact">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;artifact&gt;</code> element represents an artifact

...


        associated with the project.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="type" type="coordinate"/>

...


      <xs:attribute name="classifier" type="coordinate" use="optional"/>

...


      <xs:all>

...


        <xs:element ref="information" minOccurs="0" maxOccurs="1"/>

...


        <xs:element ref="license" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="component" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="supports" minOccurs="0" maxOccurs="unbounded"/>

...


      </xs:all>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="component">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;component&gt;</code> element represents a type specific

...


        component that is present within the artifact. For example a "jar"

...


        artifact might list the Java 9+ modules that are included within

...


        the "jar". Other file types can use the component according to the

...


        conventions of that file type. The component information is intended

...


        to assist build time tools in conflict detection when resolving

...


        the composite dependency tree according to the build tools

...


        dependency resolution strategy.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="id" type="xs:string"/>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="provides">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;provides&gt;</code> element represents a semantic

...


        equivalence with another artifact. There are several ways the element

...


        can be used.

...


        <nl>
          <li>
            When an artifact directly includes the same content as another 

...


            project's artifacts, for example there are some "jar" files that 

...


            will embed other artifacts to produce a so-called "uber-jar".

...


          </li>

...


          <li>
            When an artifact re-implements the API of another project's 

...


            artifact. For example: log4j-over-slf4j reimplements the log4j

...


            API.

...


          </li> 

...


          <li>
            When a set of projects are co-operating to provide multiple

...


            implementations of a "virtual" project artifact. For example:

...


            slf4j-log4j, slf4j-jul, and logback could all be considered

...


            as providing a slf4j-impl virtual project artifact. There would

...


            be no actual project at the slf4j-impl coordinates, but

...


            slf4j-api could declare a requirement on the "virtual" project

...


            artifact in order to ensure that an implementation is available

...


            to consumers of the API

...


          </li>
        </nl>
      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="groupId" type="coordinate"/>

...


      <xs:attribute name="artifactId" type="coordinate"/>

...


      <xs:attribute name="platformId" type="coordinate" use="optional"/>

...


      <xs:attribute name="version" type="coordinate"/>

...


      <xs:attribute name="range" type="xs:string"/>

...


      <xs:attribute name="type" type="coordinate"/>

...


      <xs:attribute name="classifier" type="coordinate" use="optional"/>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="requires">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;requires&gt;</code> element represents a hard dependency

...


        on another project's artifact. If the <code>&lt;version&gt;</code>

...


        attribute is missing then this indicates that the dependency is

...


        a virtual dependency, and there must be no child elements.

...


        The <code>&lt;modelVersion&gt;</code> attribute must only be present

...


        if the dependent project's <code>&lt;modelVersion&gt;</code> is newer

...


        than the <code>&lt;modelVersion&gt;</code> specified on the root 

...


        <code>&lt;project&gt;</code> element. The presence of this element

...


        indicates that the child information was the result of an XSLT

...


        transformation of a newer <code>&lt;modelVersion&gt;</code> and

...


        indicates that a build tool understanding the newer 

...


        <code>&lt;modelVersion&gt;</code> may want to fetch the dependencies

...


        tree and process it directly in order to obtain the most correct

...


        model of the dependency.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="groupId" type="coordinate"/>

...


      <xs:attribute name="artifactId" type="coordinate"/>

...


      <xs:attribute name="platformId" type="coordinate" use="optional"/>

...


      <xs:attribute name="version" type="coordinate" use="optional"/>

...


      <xs:attribute name="range" type="xs:string"/>

...


      <xs:attribute name="type" type="coordinate"/>

...


      <xs:attribute name="classifier" type="coordinate" use="optional"/>

...


      <xs:attribute name="modelVersion" type="xs:string" use="optional"/>

...


      <xs:all>

...


        <xs:element ref="license" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="component" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="provides" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="requires" minOccurs="0" maxOccurs="unbounded"/>

...


        <xs:element ref="supports" minOccurs="0" maxOccurs="unbounded"/>

...


      </xs:all>

...


    </xs:complexType>

...


  </xs:element>

...


  <xs:element name="supports">

...


    <xs:annotation>

...


      <xs:documentation source="version">5.0.0+</xs:documentation>

...


      <xs:documentation source="description">

...


        The <code>&lt;supports&gt;</code> element represents a soft dependency

...


        on another project's artifact. This element is provided in order to

...


        allow build time tools to perform conflict resolution when determining

...


        the effective tree from multiple dependencies.

...


      </xs:documentation>

...


    </xs:annotation>

...


    <xs:complexType>

...


      <xs:attribute name="groupId" type="coordinate"/>

...


      <xs:attribute name="artifactId" type="coordinate"/>

...


      <xs:attribute name="platformId" type="coordinate" use="optional"/>

...


      <xs:attribute name="version" type="coordinate"/>

...


      <xs:attribute name="range" type="xs:string"/>

...


      <xs:attribute name="type" type="coordinate"/>

...


      <xs:attribute name="classifier" type="coordinate" use="optional"/>

...


    </xs:complexType>

...


  </xs:element>

...


</xs:schema>