[ 
https://issues.apache.org/jira/browse/MNG-5652?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17748076#comment-17748076
 ] 

Vladimir Sitnikov commented on MNG-5652:
----------------------------------------

Version ranges often create complexity issues. Would it be enough to use a 
fixed capability version rather than a range?

For instance, Gradle supports single-version capabilities for quite some time 
now, and it is enough to describe many cases in JVM ecosystem.

See
 * [https://docs.gradle.org/current/userguide/component_capabilities.html]
 * [https://github.com/gradlex-org/java-ecosystem-capabilities] 

 

At the same time, Gradle Module Metadata can already describe the capabilities 
(see 
[https://github.com/gradle/gradle/blob/48257a8256a089c426df1a787d1dec5b233cd77b/subprojects/docs/src/docs/design/gradle-module-metadata-latest-specification.md#capabilities-value]
 )

> "supplies"/"provides"/"proffers" concept proposal
> -------------------------------------------------
>
>                 Key: MNG-5652
>                 URL: https://issues.apache.org/jira/browse/MNG-5652
>             Project: Maven
>          Issue Type: New Feature
>          Components: FDPFC
>            Reporter: Stephen Connolly
>            Priority: Major
>
> The exact name is still undecided. Some candidate names are: "supplies", 
> "provides", and "proffers"
> h2. "supplies" concept proposal
> ===========================
> h3. Introduction
> ------------
> The following is a proposal for Maven in a post-modelVersion-4.0.0 era. The 
> aim of this proposal is to simplify the management of dependency trees in the 
> decentralised era of artifact production that we find ourselves in.
> The core issue is that different organisations can produce artifacts that may 
> overlap. The easiest example is the servlet-api. If we restrict ourselves to 
> version 2.5 of the servlet specification there are quite a few artifacts that 
> all deliver the exact same content:
> * {{jetty:servlet-api:2.5-6.0.2}}
> * {{org.daisy.libs:servlet-api:2.5.0}}
> * {{org.mortbay.jetty:servlet-api-2.5:6.1.14}}
> * {{org.jboss.spec.javax.servlet:jboss-servlet-api_2.5_spec:1.0.1.Final}}
> * etc
> **Note:** this is a generic problem that is not restricted to the 
> servlet-api, the servlet-api just provides the example that will be most 
> familiar to everyone.
> So where these multiple artifacts supplying the equivalent content becomes a 
> problem is when the dependency tree is being calculated. If you have two 
> dependencies each declaring transitive dependencies on different artifacts 
> that supply equivalent content, then you end up with two copies of the same 
> JAR file in your classpath.
> In the case of the servlet-api, the hack most people use is to declare the 
> servlet-api with scope `provided` thus preventing it from being transitive. 
> This is, however, a hack. In a more ideal world it would be better to let the 
> servlet-api be transitive and only when we get to the WAR module would we 
> declare that a specific servlet-api is to be provided in the containers that 
> the WAR is targets for deployment into. 
> We can take a second example that does not have the luxury of a *de facto* 
> hack.
> * {{javax.faces:jsf-api:2.1}}
> * {{org.jboss.spec.javax.faces:jboss-jsf-api_2.1_spec:2.1.28.Final}}
> * {{org.apache.myfaces.core:myfaces-api:2.1.13}}
> Now in the case of the JSF API, you are supposed to bundle the JSF API in 
> your WAR file. So if I use three JSF component libraries, I could very well 
> end up with three different but equivalent JSF API jars in my WAR file.
> Ideally what we want is some way of telling Maven that these artifacts are 
> equivalent.
> Proposal
> --------
> Introduce the concept of "supplies" to the project model. The concept needs 
> three changes to the project model:
> 1. An explicit top level construct for a project to explicitly declare 
> up-front artifacts that it knows - at the time the project is being authored 
> - to contain equivalent content to at least a subset of the project's 
> content. Declarations could include a claim from: `subset`, `superset`, 
> `disjoint` and `equivalent` with the default being `disjoint`.
> 2. An explicit sub-element of the `dependency` construct to allow consumers 
> to *post-facto* declare a specific dependency as supplying equivalent content 
> for other dependencies
> 3. An extension to the `dependency/excludes/exclude` construct to allow 
> consumers to remove claims a dependency makes with respect to supplying 
> equivalent content
> By way of illustration, here are some examples of these constructs mapped to 
> a Model Version 4.0.0 like XML schema. As the post-modelVersion-4.0.0 schema 
> is not yet known, this represents the best way to illustrate how the concept 
> will work, but note that this proposal does not suggest a schema for this 
> concept.
> h3. Example 1
> This illustrates how we would want, say, the `myfaces-api` project model to 
> look.
> {code:xml}
> <project>
>   <groupId>org.apache.myfaces.core</groupId>
>   <artifactId>myfaces-api</artifactId>
>   <version>2.1.3</version>
>   ...
>   <supplyManagement>
>     <supplies>
>       <groupId>javax.faces</groupId>
>       <artifactId>jsf-api</artifactId>
>       <version>[2.1,2.2)</version>
>       <claim>superset</claim>
>     <supplies>
>     <supplies>
>       <groupId>org.jboss.spec.javax.faces</groupId>
>       <artifactId>jboss-jsf-api_2.1_spec</artifactId>
>       <claim>equivalent</claim>
>     <supplies>
>   </supplyManagement>
>   ...
> </project>
> {code}
> This indicates that the {{myfaces-api}} artifact is intended to be useable as 
> a drop-in replacement for either the {{javax.faces:jsf-api}} artifact within 
> a bounded range or for any version of the 
> {{org.jboss.spec.javax.faces:jboss-jsf-api_2.1_spec}} artifact. If you get a 
> supplier conflict in your classpath, then Maven should fail the build.
> For example if somebody forked {{myfaces-api}} but did not list 
> {{myfaces-api}} in the fork's supplyManagement and you end up with both 
> {{myfaces-api}} and {{myfaces-fork-api}} in your classpath. Maven can detect 
> that there are two dependencies that both claim to supply 
> {{javax.faces:jsf-api}} and fail the build, thereby letting the user add 
> either exclusions or additional supplies information to one of the artifacts 
> and preventing duplicate artifacts on the classpath. The build need not be 
> failed if the supplies claims provide a resolution. e.g. if the claim is 
> {{equivalent}} then that implies that there is a 1:1 mapping and hence the 
> artifacts are drop-in replacements. However where the claim is {{superset}} 
> we cannot know that the extra content in our artifact is the same as the 
> extra content in another artifact which has a superset of 
> `javax.faces:jsf-api`.
> h3. Example 2
> This illustrates a JSF component library that is working with the existing 
> JSF APIs
> {code:xml}
> <project>
>   ...
>   <dependencies>
>     <dependency>
>       <groupId>javax.faces</groupId>
>       <artifactId>jsf-api</artifactId>
>       <version>2.1</version>
>       <supplyManagement>
>         <supplies>
>           <groupId>org.jboss.spec.javax.faces</groupId>
>           <artifactId>jboss-jsf-api_2.1_spec</artifactId>
>           <claim>equivalent</claim>
>         <supplies>
>         <supplies>
>           <groupId>org.apache.myfaces.core</groupId>
>           <artifactId>myfaces-api</artifactId>
>           <version>[2.1,2.2)</version>
>           <claim>equivalent</claim>
>         </supplies>
>       </supplyManagement>
>     <dependency>
>   </dependencies>
>   ...
> </project>
> {code}
> In this case we are publishing a transitive dependency with additional 
> supplyManagement injected. Consumers of this project would thus gain the 
> benefit of collapsing their transitive dependencies for any of these three 
> artifacts. As all artifacts are declared with `equivalent` claim, thus the 
> nearest of those three artifacts to the project will win as per the standard 
> dependency resolution rules when dealing with conflicting version 
> requirements in the transitive dependency tree.
> h3. Example 3
> Finally, there is the case where you need to correct an incorrect claim of 
> supply
> {code:xml}
> <project>
>   ...
>   <dependencies>
>     <dependency>
>       <groupId>javax.faces</groupId>
>       <artifactId>jsf-api</artifactId>
>       <version>2.1</version>
>       <exclusions>
>         <exclusion>
>           <groupId>org.jboss.spec.javax.faces</groupId>
>           <artifactId>jboss-jsf-api_2.2_spec</artifactId>
>           <scope>supplies</scope>
>         <exclusion>
>       </exclusions>
>     <dependency>
>   </dependencies>
>   ...
> </project>
> {code}
> This would typically be coupled with adding back in a correct supplies 
> definition, but we need to allow for people to correct the graph after the 
> fact of their dependencies being deployed to the remote repository.
> h3. Claim conflict resolution
> The four classes of claim can be resolved using the following matrix
> |    |                   | A           | A               | A            | A   
>           |
> |    |                   | subset   | equivalent | superset | disjoint   |
> | B | subset       | conflict  | A wins       | A wins     | conflict   |
> | B | equivalent | B wins   | A or B       | A wins     | conflict   |
> | B | superset   | B wins    | B wins      | conflict     | conflict   |
> | B | disjoint      | conflict   | conflict     | conflict     | conflict   |
> The default unspecified claim is {{disjoint}} which indicates that some of 
> the content is reproduced, but not all and there is additional content added. 
> With such a claim there will always be conflict and the build should fail 
> until the Project Model is updated to either remove some of the claims or 
> resolve the dependency clash.
> The ideal claim is {{equivalent}} which indicates that the two artifacts are 
> bi-directionally substitutable. This does not mean that the contents are 
> identical. It does mean that they both deliver on the same contract in an 
> equivalent fashion.
> The {{subset}}` and {{superset}} claims are for aggregation APIs. So for 
> example the Java EE Web Profile API is a superset of the various spec APIs 
> that make up the Java EE Web Profile and a subset of the full Java EE 
> specification. The use of the {{subset}}` claim should be reserved to those 
> cases that are strict subsets. If anything is added that is not in the 
> supplied artifact then the correct claim is {{disjoint}}.
> h3. Validation of supplies claims
> We do not want to introduce Java bias with this feature. As a result the 
> validation of claims and supplies directives will be left to plugins. For the 
> Java case we should probably provide either/both an enforcer rule or a maven 
> hosted plugin to assist in checking JAR projects against the declared 
> supplies declarations, but Maven core should not be concerned with solving 
> the validation problem.
> Similarly, while there may be advantages in a more fine grained API contract 
> negotiation between dependencies, to bind such a concept into the project 
> model would significantly taint the Maven project model with more 
> Java-centric concepts. Given that current software development typically uses 
> at least two core languages: Java and JavaScript, we should be aiming to 
> reduce Java-centric constructs from Maven rather than increase them.
> h3. Backporting
> It will not be possible to fully express this concept in a modelVersion 4.0.0 
> project model. Thus if generating 4.0.0 compatible project models, the aim 
> should be to fully resolve the dependencies of the project using all 
> available information and express that as the transitive dependencies.
> Thus we will not expose the "supplies" information to modelVersion 4.0.0 
> parsers but we will expose the end results of that and present the final 
> effective flattened dependency tree.
> modelVersion 4.0.0 consumers will thus be no worse off than they already are 
> and those consumers understanding newer modelVersions can get the enhanced 
> tree resolution that they would not get otherwise. 



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to