From 5cfa5be47598f19e689e47e70b0d8cf9619ce690 Mon Sep 17 00:00:00 2001 From: Tamas Cservenak Date: Sun, 13 Nov 2022 15:22:57 +0100 Subject: [PATCH] [MRESOLVER-294] Fix JapiCmp configuration and document it (#221) Fix JapiCmp and describe what we promise and what we expect And fix: no need for default interface method on an interface that is noimplement. Once fixed, the override can be removed from japicmp config as well. --- https://issues.apache.org/jira/browse/MRESOLVER-294 --- .../aether/collection/CollectStepData.java | 2 + .../basic/TestChecksumAlgorithmSelector.java | 12 ++ ...faultChecksumAlgorithmFactorySelector.java | 9 ++ ...sumsArtifactResolverPostProcessorTest.java | 9 ++ .../ChecksumAlgorithmFactorySelector.java | 9 +- pom.xml | 52 ++++++-- src/site/markdown/api-compatibility.md | 113 ++++++++++++++++++ src/site/site.xml | 1 + 8 files changed, 188 insertions(+), 19 deletions(-) create mode 100644 src/site/markdown/api-compatibility.md diff --git a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectStepData.java b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectStepData.java index 28036e9d7..632872dba 100644 --- a/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectStepData.java +++ b/maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectStepData.java @@ -29,6 +29,8 @@ * * @see org.eclipse.aether.RequestTrace * @since 1.8.1 + * @noimplement This interface is not intended to be implemented by clients. + * @noextend This interface is not intended to be extended by clients. */ public interface CollectStepData { diff --git a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java index 6a88470f7..574ab5adc 100644 --- a/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java +++ b/maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java @@ -22,7 +22,9 @@ import java.nio.ByteBuffer; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; +import java.util.Collection; import java.util.Collections; +import java.util.List; import java.util.Locale; import java.util.Set; @@ -32,6 +34,8 @@ import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport; import org.eclipse.aether.util.ChecksumUtils; +import static java.util.stream.Collectors.toList; + /** * Test implementation of {@link ChecksumAlgorithmFactorySelector}. */ @@ -86,6 +90,14 @@ public String checksum() return new MessageDigestChecksumAlgorithmFactory( algorithm ); } + @Override + public List selectList( Collection algorithmNames ) + { + return algorithmNames.stream() + .map( this::select ) + .collect( toList() ); + } + private static class MessageDigestChecksumAlgorithmFactory extends ChecksumAlgorithmFactorySupport { diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java index d1b2fd7cc..81d8b64df 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java @@ -24,6 +24,7 @@ import javax.inject.Singleton; import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -84,6 +85,14 @@ public ChecksumAlgorithmFactory select( String algorithmName ) return factory; } + @Override + public List selectList( Collection algorithmNames ) + { + return algorithmNames.stream() + .map( this::select ) + .collect( toList() ); + } + @Override public List getChecksumAlgorithmFactories() { diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessorTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessorTest.java index b07ded54f..49c3c09ee 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessorTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessorTest.java @@ -44,6 +44,7 @@ import org.junit.Before; import org.junit.Test; +import static java.util.stream.Collectors.toList; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; @@ -94,6 +95,14 @@ public ChecksumAlgorithmFactory select( String algorithmName ) throw new IllegalArgumentException("no alg factory for " + algorithmName); } + @Override + public List selectList( Collection algorithmNames ) + { + return algorithmNames.stream() + .map( this::select ) + .collect( toList() ); + } + @Override public Collection getChecksumAlgorithmFactories() { diff --git a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java index f81802d6c..55feea706 100644 --- a/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java +++ b/maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java @@ -22,8 +22,6 @@ import java.util.Collection; import java.util.List; -import static java.util.stream.Collectors.toList; - /** * Component performing selection of {@link ChecksumAlgorithmFactory} based on known factory names. * Note: this component is NOT meant to be implemented or extended by client, is exposed ONLY to make clients @@ -51,12 +49,7 @@ public interface ChecksumAlgorithmFactorySelector * @throws NullPointerException if passed in list of names is {@code null}. * @since 1.9.0 */ - default List selectList( Collection algorithmNames ) - { - return algorithmNames.stream() - .map( this::select ) - .collect( toList() ); - } + List selectList( Collection algorithmNames ); /** * Returns a collection of supported algorithms. This set represents ALL the algorithms supported by Resolver, diff --git a/pom.xml b/pom.xml index 205de8c26..898ec1479 100644 --- a/pom.xml +++ b/pom.xml @@ -312,24 +312,54 @@ ${project.packaging} - - true - true - - - METHOD_NEW_DEFAULT - true - false - - - + default-source-cmp verify cmp + + + + org.eclipse.aether.RepositoryListener + org.eclipse.aether.RepositorySystem + org.eclipse.aether.RepositorySystemSession + org.eclipse.aether.SessionData + org.eclipse.aether.artifact.Artifact + org.eclipse.aether.artifact.ArtifactType + org.eclipse.aether.collection.CollectStepData + org.eclipse.aether.collection.DependencyCollectionContext + org.eclipse.aether.collection.DependencyGraphTransformationContext + org.eclipse.aether.collection.VersionFilter.VersionFilterContext + org.eclipse.aether.graph.DependencyCycle + org.eclipse.aether.graph.DependencyNode + org.eclipse.aether.metadata.Metadata + org.eclipse.aether.repository.ArtifactRepository + org.eclipse.aether.transfer.TransferListener + org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector + org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider + org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider + org.eclipse.aether.spi.connector.transport.TransporterProvider + + false + true + + + + + default-binary-cmp + verify + + cmp + + + + true + false + + diff --git a/src/site/markdown/api-compatibility.md b/src/site/markdown/api-compatibility.md new file mode 100644 index 000000000..14290f1d3 --- /dev/null +++ b/src/site/markdown/api-compatibility.md @@ -0,0 +1,113 @@ +# API Compatibility + + + +Maven Resolver exposes three modules for clients and those extending Maven Resolver: +* maven-resolver-api (in short API) -- for clients and those extending it +* maven-resolver-spi (in short SPI) -- for those extending it +* maven-resolver-util (in short Util) -- for client and those extending it + +Each module guarantees non-breaking (source and binary) compatibility, as long +clients and extenders obey some rules. If you break any of these rules, you are +prone to breakage, and you are on your own. + +## Interface And (Abstract) Class Level Contracts + +In source, we use two important Javadoc tags to mark intent: +* `@noextend` -- classes (or interfaces) carrying this tag MUST NOT be extended +* `@noimplement` -- interfaces carrying this tag MUST NOT be directly or indirectly implemented, + UNLESS the Javadoc of given interface points to an abstract support class that makes indirect + implementation possible. + +Examples: + +* `RepositorySystem` interface. It carries both `@noextend` and `@noimplement` tags. This interface + MUST NOT be extended nor implemented. This is a component interface, that is usually injected into + client application. +* `TransferListener` interface. It carries both `@noextend` and `@noimplement` tags, but Javadoc + points at `AbstractTransferListener` as extension point. Hence, clients are NOT allowed to extend + this interface, nor to directly implement it, but, if custom listener is needed, it is warmly + advised to extend the given abstract class. This way we can protect you from future breakage. + +## Package Level Contracts + +Maven Resolver implements customary habit to name packages NOT meant to be accessed by clients. +If a Java package contains following names: + +* `impl` +* `internal` + +That Java package is meant as "internal" and does NOT offer guarantees of compatibility as API is. You +may use classes from these packages, but again, you are on your own to deal with (binary or source) +breakages. If you think a class from such package should be "pulled out" and made part of SPI or +maybe API, better inform us via [JIRA](https://issues.apache.org/jira/projects/MRESOLVER): create a +ticket and let's discuss. + +As a side note, the count of those names in Java package is directly proportional to possibility of +breaking changes: the more, the larger the possibility of breakage even in minor releases. + +## Version Level Contracts + +Maven Resolver does NOT use "semantic versioning", but still tries at best to reflect contained +changes using version number. We use "major.minor.patch" versioning on resolver with following +semantics: + +* On major version change, one should NOT expect any backward compatibility. +* On minor version change, we TRY to keep backward compatibility for those "exposed" 3 modules: + API, SPI and Util. Still, there are examples when we failed to do so, usually driven by new + features. +* On minor version change, we ENSURE backward compatibility for those "exposed" 3 modules: API, + SPI and Util. + +In any of three version changes above, in areas where we do not offer guarantees, everything +can happen. + +## Outside of Maven + +Applications integrating Maven Resolver outside of Maven has really simple job: all they have to +ensure is that API, SPI, Util and the rest of resolver (impl, basic-connector and transports) +have all same versions, and they can rely on these backward compatibility contracts as explained +above. + +## Inside of Maven + +Historically, Maven 3.1 (as Maven 3.0 used resolver from different package) provided API, SPI +and Impl from its own embedded resolver, while Util, Connector, if some plugin or extension +depended on those, was resolved. This caused that a plugin may work with different versions +of API, SPI, Impl or Connector. Given Resolver had API "frozen" for too long time, this was essentially +not a problem, but still weird. + +This changes in Maven 3.9+: Maven starting with version 3.9.0 will provide API, SPI, Impl +**and Util and Connector**. Reason for this change is that Impl and Connector bundled in Maven +implements things from both, API and SPI, and there was a binary incompatible change between +Resolver 1.8.0 and previous versions. + +Most Resolver users should not be affected by this change. + +The binary incompatible change happened in SPI class `RepositoryLayout` as part of work done for +[MRESOLVER-230](https://issues.apache.org/jira/browse/MRESOLVER-230), and affects both, Connector +and Impl. + +## Backward Compatibility Checks + +To ensure backward compatibility, starting from 1.9.0 version Maven Resolver uses +[JApiCmp](https://siom79.github.io/japicmp/MavenPlugin.html), +with two executions (for source and binary level checks). The plugin is enabled on 3 modules of +Resolver mentioned at page top: API, SPI and Util. For "baseline" we use version 1.8.0. diff --git a/src/site/site.xml b/src/site/site.xml index 3c855468b..2fc1739c3 100644 --- a/src/site/site.xml +++ b/src/site/site.xml @@ -26,6 +26,7 @@ under the License. +