Skip to content

Commit 5cfa5be

Browse files
authored
[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
1 parent 3726666 commit 5cfa5be

File tree

8 files changed

+188
-19
lines changed

8 files changed

+188
-19
lines changed

maven-resolver-api/src/main/java/org/eclipse/aether/collection/CollectStepData.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929
*
3030
* @see org.eclipse.aether.RequestTrace
3131
* @since 1.8.1
32+
* @noimplement This interface is not intended to be implemented by clients.
33+
* @noextend This interface is not intended to be extended by clients.
3234
*/
3335
public interface CollectStepData
3436
{

maven-resolver-connector-basic/src/test/java/org/eclipse/aether/connector/basic/TestChecksumAlgorithmSelector.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,9 @@
2222
import java.nio.ByteBuffer;
2323
import java.security.MessageDigest;
2424
import java.security.NoSuchAlgorithmException;
25+
import java.util.Collection;
2526
import java.util.Collections;
27+
import java.util.List;
2628
import java.util.Locale;
2729
import java.util.Set;
2830

@@ -32,6 +34,8 @@
3234
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySupport;
3335
import org.eclipse.aether.util.ChecksumUtils;
3436

37+
import static java.util.stream.Collectors.toList;
38+
3539
/**
3640
* Test implementation of {@link ChecksumAlgorithmFactorySelector}.
3741
*/
@@ -86,6 +90,14 @@ public String checksum()
8690
return new MessageDigestChecksumAlgorithmFactory( algorithm );
8791
}
8892

93+
@Override
94+
public List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames )
95+
{
96+
return algorithmNames.stream()
97+
.map( this::select )
98+
.collect( toList() );
99+
}
100+
89101
private static class MessageDigestChecksumAlgorithmFactory
90102
extends ChecksumAlgorithmFactorySupport
91103
{

maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/checksum/DefaultChecksumAlgorithmFactorySelector.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import javax.inject.Singleton;
2525

2626
import java.util.ArrayList;
27+
import java.util.Collection;
2728
import java.util.HashMap;
2829
import java.util.List;
2930
import java.util.Map;
@@ -84,6 +85,14 @@ public ChecksumAlgorithmFactory select( String algorithmName )
8485
return factory;
8586
}
8687

88+
@Override
89+
public List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames )
90+
{
91+
return algorithmNames.stream()
92+
.map( this::select )
93+
.collect( toList() );
94+
}
95+
8796
@Override
8897
public List<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories()
8998
{

maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessorTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import org.junit.Before;
4545
import org.junit.Test;
4646

47+
import static java.util.stream.Collectors.toList;
4748
import static org.hamcrest.MatcherAssert.assertThat;
4849
import static org.hamcrest.Matchers.containsString;
4950
import static org.hamcrest.Matchers.empty;
@@ -94,6 +95,14 @@ public ChecksumAlgorithmFactory select( String algorithmName )
9495
throw new IllegalArgumentException("no alg factory for " + algorithmName);
9596
}
9697

98+
@Override
99+
public List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames )
100+
{
101+
return algorithmNames.stream()
102+
.map( this::select )
103+
.collect( toList() );
104+
}
105+
97106
@Override
98107
public Collection<ChecksumAlgorithmFactory> getChecksumAlgorithmFactories()
99108
{

maven-resolver-spi/src/main/java/org/eclipse/aether/spi/connector/checksum/ChecksumAlgorithmFactorySelector.java

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,6 @@
2222
import java.util.Collection;
2323
import java.util.List;
2424

25-
import static java.util.stream.Collectors.toList;
26-
2725
/**
2826
* Component performing selection of {@link ChecksumAlgorithmFactory} based on known factory names.
2927
* 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
5149
* @throws NullPointerException if passed in list of names is {@code null}.
5250
* @since 1.9.0
5351
*/
54-
default List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames )
55-
{
56-
return algorithmNames.stream()
57-
.map( this::select )
58-
.collect( toList() );
59-
}
52+
List<ChecksumAlgorithmFactory> selectList( Collection<String> algorithmNames );
6053

6154
/**
6255
* Returns a collection of supported algorithms. This set represents ALL the algorithms supported by Resolver,

pom.xml

Lines changed: 41 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -312,24 +312,54 @@
312312
<type>${project.packaging}</type>
313313
</dependency>
314314
</oldVersion>
315-
<parameter>
316-
<onlyBinaryIncompatible>true</onlyBinaryIncompatible>
317-
<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
318-
<overrideCompatibilityChangeParameters>
319-
<overrideCompatibilityChangeParameter>
320-
<compatibilityChange>METHOD_NEW_DEFAULT</compatibilityChange>
321-
<binaryCompatible>true</binaryCompatible>
322-
<sourceCompatible>false</sourceCompatible>
323-
</overrideCompatibilityChangeParameter>
324-
</overrideCompatibilityChangeParameters>
325-
</parameter>
326315
</configuration>
327316
<executions>
328317
<execution>
318+
<id>default-source-cmp</id>
329319
<phase>verify</phase>
330320
<goals>
331321
<goal>cmp</goal>
332322
</goals>
323+
<configuration>
324+
<parameter>
325+
<excludes>
326+
<exclude>org.eclipse.aether.RepositoryListener</exclude>
327+
<exclude>org.eclipse.aether.RepositorySystem</exclude>
328+
<exclude>org.eclipse.aether.RepositorySystemSession</exclude>
329+
<exclude>org.eclipse.aether.SessionData</exclude>
330+
<exclude>org.eclipse.aether.artifact.Artifact</exclude>
331+
<exclude>org.eclipse.aether.artifact.ArtifactType</exclude>
332+
<exclude>org.eclipse.aether.collection.CollectStepData</exclude>
333+
<exclude>org.eclipse.aether.collection.DependencyCollectionContext</exclude>
334+
<exclude>org.eclipse.aether.collection.DependencyGraphTransformationContext</exclude>
335+
<exclude>org.eclipse.aether.collection.VersionFilter.VersionFilterContext</exclude>
336+
<exclude>org.eclipse.aether.graph.DependencyCycle</exclude>
337+
<exclude>org.eclipse.aether.graph.DependencyNode</exclude>
338+
<exclude>org.eclipse.aether.metadata.Metadata</exclude>
339+
<exclude>org.eclipse.aether.repository.ArtifactRepository</exclude>
340+
<exclude>org.eclipse.aether.transfer.TransferListener</exclude>
341+
<exclude>org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector</exclude>
342+
<exclude>org.eclipse.aether.spi.connector.checksum.ChecksumPolicyProvider</exclude>
343+
<exclude>org.eclipse.aether.spi.connector.layout.RepositoryLayoutProvider</exclude>
344+
<exclude>org.eclipse.aether.spi.connector.transport.TransporterProvider</exclude>
345+
</excludes>
346+
<breakBuildOnBinaryIncompatibleModifications>false</breakBuildOnBinaryIncompatibleModifications>
347+
<breakBuildOnSourceIncompatibleModifications>true</breakBuildOnSourceIncompatibleModifications>
348+
</parameter>
349+
</configuration>
350+
</execution>
351+
<execution>
352+
<id>default-binary-cmp</id>
353+
<phase>verify</phase>
354+
<goals>
355+
<goal>cmp</goal>
356+
</goals>
357+
<configuration>
358+
<parameter>
359+
<breakBuildOnBinaryIncompatibleModifications>true</breakBuildOnBinaryIncompatibleModifications>
360+
<breakBuildOnSourceIncompatibleModifications>false</breakBuildOnSourceIncompatibleModifications>
361+
</parameter>
362+
</configuration>
333363
</execution>
334364
</executions>
335365
</plugin>
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# API Compatibility
2+
3+
<!--
4+
Licensed to the Apache Software Foundation (ASF) under one
5+
or more contributor license agreements. See the NOTICE file
6+
distributed with this work for additional information
7+
regarding copyright ownership. The ASF licenses this file
8+
to you under the Apache License, Version 2.0 (the
9+
"License"); you may not use this file except in compliance
10+
with the License. You may obtain a copy of the License at
11+
12+
http://www.apache.org/licenses/LICENSE-2.0
13+
14+
Unless required by applicable law or agreed to in writing,
15+
software distributed under the License is distributed on an
16+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17+
KIND, either express or implied. See the License for the
18+
specific language governing permissions and limitations
19+
under the License.
20+
-->
21+
22+
Maven Resolver exposes three modules for clients and those extending Maven Resolver:
23+
* maven-resolver-api (in short API) -- for clients and those extending it
24+
* maven-resolver-spi (in short SPI) -- for those extending it
25+
* maven-resolver-util (in short Util) -- for client and those extending it
26+
27+
Each module guarantees non-breaking (source and binary) compatibility, as long
28+
clients and extenders obey some rules. If you break any of these rules, you are
29+
prone to breakage, and you are on your own.
30+
31+
## Interface And (Abstract) Class Level Contracts
32+
33+
In source, we use two important Javadoc tags to mark intent:
34+
* `@noextend` -- classes (or interfaces) carrying this tag MUST NOT be extended
35+
* `@noimplement` -- interfaces carrying this tag MUST NOT be directly or indirectly implemented,
36+
UNLESS the Javadoc of given interface points to an abstract support class that makes indirect
37+
implementation possible.
38+
39+
Examples:
40+
41+
* `RepositorySystem` interface. It carries both `@noextend` and `@noimplement` tags. This interface
42+
MUST NOT be extended nor implemented. This is a component interface, that is usually injected into
43+
client application.
44+
* `TransferListener` interface. It carries both `@noextend` and `@noimplement` tags, but Javadoc
45+
points at `AbstractTransferListener` as extension point. Hence, clients are NOT allowed to extend
46+
this interface, nor to directly implement it, but, if custom listener is needed, it is warmly
47+
advised to extend the given abstract class. This way we can protect you from future breakage.
48+
49+
## Package Level Contracts
50+
51+
Maven Resolver implements customary habit to name packages NOT meant to be accessed by clients.
52+
If a Java package contains following names:
53+
54+
* `impl`
55+
* `internal`
56+
57+
That Java package is meant as "internal" and does NOT offer guarantees of compatibility as API is. You
58+
may use classes from these packages, but again, you are on your own to deal with (binary or source)
59+
breakages. If you think a class from such package should be "pulled out" and made part of SPI or
60+
maybe API, better inform us via [JIRA](https://issues.apache.org/jira/projects/MRESOLVER): create a
61+
ticket and let's discuss.
62+
63+
As a side note, the count of those names in Java package is directly proportional to possibility of
64+
breaking changes: the more, the larger the possibility of breakage even in minor releases.
65+
66+
## Version Level Contracts
67+
68+
Maven Resolver does NOT use "semantic versioning", but still tries at best to reflect contained
69+
changes using version number. We use "major.minor.patch" versioning on resolver with following
70+
semantics:
71+
72+
* On major version change, one should NOT expect any backward compatibility.
73+
* On minor version change, we TRY to keep backward compatibility for those "exposed" 3 modules:
74+
API, SPI and Util. Still, there are examples when we failed to do so, usually driven by new
75+
features.
76+
* On minor version change, we ENSURE backward compatibility for those "exposed" 3 modules: API,
77+
SPI and Util.
78+
79+
In any of three version changes above, in areas where we do not offer guarantees, everything
80+
can happen.
81+
82+
## Outside of Maven
83+
84+
Applications integrating Maven Resolver outside of Maven has really simple job: all they have to
85+
ensure is that API, SPI, Util and the rest of resolver (impl, basic-connector and transports)
86+
have all same versions, and they can rely on these backward compatibility contracts as explained
87+
above.
88+
89+
## Inside of Maven
90+
91+
Historically, Maven 3.1 (as Maven 3.0 used resolver from different package) provided API, SPI
92+
and Impl from its own embedded resolver, while Util, Connector, if some plugin or extension
93+
depended on those, was resolved. This caused that a plugin may work with different versions
94+
of API, SPI, Impl or Connector. Given Resolver had API "frozen" for too long time, this was essentially
95+
not a problem, but still weird.
96+
97+
This changes in Maven 3.9+: Maven starting with version 3.9.0 will provide API, SPI, Impl
98+
**and Util and Connector**. Reason for this change is that Impl and Connector bundled in Maven
99+
implements things from both, API and SPI, and there was a binary incompatible change between
100+
Resolver 1.8.0 and previous versions.
101+
102+
Most Resolver users should not be affected by this change.
103+
104+
The binary incompatible change happened in SPI class `RepositoryLayout` as part of work done for
105+
[MRESOLVER-230](https://issues.apache.org/jira/browse/MRESOLVER-230), and affects both, Connector
106+
and Impl.
107+
108+
## Backward Compatibility Checks
109+
110+
To ensure backward compatibility, starting from 1.9.0 version Maven Resolver uses
111+
[JApiCmp](https://siom79.github.io/japicmp/MavenPlugin.html),
112+
with two executions (for source and binary level checks). The plugin is enabled on 3 modules of
113+
Resolver mentioned at page top: API, SPI and Util. For "baseline" we use version 1.8.0.

src/site/site.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ under the License.
2626
<body>
2727
<menu name="Overview">
2828
<item name="Introduction" href="index.html"/>
29+
<item name="API Compatibility" href="api-compatibility.html"/>
2930
<item name="Configuration" href="configuration.html"/>
3031
<item name="About Checksums" href="about-checksums.html"/>
3132
<item name="About Local Repository" href="local-repository.html"/>

0 commit comments

Comments
 (0)