This is an automated email from the ASF dual-hosted git repository. michaelo pushed a commit to branch MRESOLVER-141 in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
commit a932eacf6ccad6db1f8b1b39b7f769bb858fa46f Author: Michael Boyles <[email protected]> AuthorDate: Sun Oct 11 22:34:39 2020 +0100 [MRESOLVER-141] Review index-based access to collections This closes #76 --- .../aether/internal/impl/DefaultDeployer.java | 8 +- .../aether/internal/impl/DefaultInstaller.java | 7 +- .../internal/impl/PrioritizedComponents.java | 6 +- .../aether/internal/impl/collect/DataPool.java | 8 +- .../impl/collect/DefaultDependencyCycle.java | 7 +- .../impl/collect/DefaultVersionFilterContext.java | 118 +------------- .../internal/impl/PrioritizedComponentsTest.java | 17 ++ .../aether/internal/impl/collect/DataPoolTest.java | 18 +++ .../impl/collect/DefaultDependencyCycleTest.java | 44 ++++++ .../collect/DefaultVersionFilterContextTest.java | 170 ++++++++++++++++++++ .../aether/internal/test/util/TestVersion.java | 4 +- .../internal/test/util/TestVersionConstraint.java | 6 +- .../util/graph/transformer/ConflictResolver.java | 14 +- .../graph/transformer/ConflictResolverTest.java | 175 +++++++++++++++++++++ 14 files changed, 463 insertions(+), 139 deletions(-) diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java index 78c83ff..4f76175 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultDeployer.java @@ -27,6 +27,8 @@ import java.util.Collection; import java.util.IdentityHashMap; import java.util.List; import static java.util.Objects.requireNonNull; + +import java.util.ListIterator; import java.util.Set; import javax.inject.Inject; @@ -257,16 +259,16 @@ public class DefaultDeployer processedMetadata.put( metadata, null ); } - for ( int i = 0; i < artifacts.size(); i++ ) + for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) { - Artifact artifact = artifacts.get( i ); + Artifact artifact = iterator.next(); for ( MetadataGenerator generator : generators ) { artifact = generator.transformArtifact( artifact ); } - artifacts.set( i, artifact ); + iterator.set( artifact ); Collection<FileTransformer> fileTransformers = fileTransformerManager.getTransformersForArtifact( artifact ); diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java index 38cb2a0..0310524 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/DefaultInstaller.java @@ -27,6 +27,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.IdentityHashMap; import java.util.List; +import java.util.ListIterator; import java.util.Set; import javax.inject.Inject; @@ -170,16 +171,16 @@ public class DefaultInstaller result.addMetadata( metadata ); } - for ( int i = 0; i < artifacts.size(); i++ ) + for ( ListIterator<Artifact> iterator = artifacts.listIterator(); iterator.hasNext(); ) { - Artifact artifact = artifacts.get( i ); + Artifact artifact = iterator.next(); for ( MetadataGenerator generator : generators ) { artifact = generator.transformArtifact( artifact ); } - artifacts.set( i, artifact ); + iterator.set( artifact ); install( session, trace, artifact ); result.addArtifact( artifact ); diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java index fb17b8d..8877bdc 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/PrioritizedComponents.java @@ -133,13 +133,13 @@ final class PrioritizedComponents<T> public void list( StringBuilder buffer ) { - for ( int i = 0; i < components.size(); i++ ) + int i = 0; + for ( PrioritizedComponent<?> component : components ) { - if ( i > 0 ) + if ( i++ > 0 ) { buffer.append( ", " ); } - PrioritizedComponent<?> component = components.get( i ); buffer.append( component.getType().getSimpleName() ); if ( component.isDisabled() ) { diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java index 41b5703..0d3187c 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DataPool.java @@ -22,6 +22,7 @@ package org.eclipse.aether.internal.impl.collect; import java.util.Collection; import java.util.Collections; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; @@ -320,10 +321,11 @@ final class DataPool { return false; } - for ( int i = 0, n = repos1.size(); i < n; i++ ) + for ( Iterator<RemoteRepository> it1 = repos1.iterator(), it2 = repos2.iterator(); + it1.hasNext() && it2.hasNext(); ) { - RemoteRepository repo1 = repos1.get( i ); - RemoteRepository repo2 = repos2.get( i ); + RemoteRepository repo1 = it1.next(); + RemoteRepository repo2 = it2.next(); if ( repo1.isRepositoryManager() != repo2.isRepositoryManager() ) { return false; diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java index 15e1835..42a56c2 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycle.java @@ -73,13 +73,14 @@ final class DefaultDependencyCycle public String toString() { StringBuilder buffer = new StringBuilder( 256 ); - for ( int i = 0, n = dependencies.size(); i < n; i++ ) + int i = 0; + for ( Dependency dependency : dependencies ) { - if ( i > 0 ) + if ( i++ > 0 ) { buffer.append( " -> " ); } - buffer.append( ArtifactIdUtils.toVersionlessId( dependencies.get( i ).getArtifact() ) ); + buffer.append( ArtifactIdUtils.toVersionlessId( dependency.getArtifact() ) ); } return buffer.toString(); } diff --git a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext.java b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext.java index 4488492..bfea062 100644 --- a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext.java +++ b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContext.java @@ -21,10 +21,8 @@ package org.eclipse.aether.internal.impl.collect; import java.util.ArrayList; import java.util.Collections; -import java.util.ConcurrentModificationException; import java.util.Iterator; import java.util.List; -import java.util.NoSuchElementException; import org.eclipse.aether.RepositorySystemSession; import org.eclipse.aether.collection.VersionFilter; @@ -47,9 +45,7 @@ final class DefaultVersionFilterContext VersionRangeResult result; - int count; - - byte[] deleted = new byte[64]; + private List<Version> versions; DefaultVersionFilterContext( RepositorySystemSession session ) { @@ -60,40 +56,12 @@ final class DefaultVersionFilterContext { this.dependency = dependency; this.result = result; - count = result.getVersions().size(); - if ( deleted.length < count ) - { - deleted = new byte[count]; - } - else - { - for ( int i = count - 1; i >= 0; i-- ) - { - deleted[i] = (byte) 0; - } - } + this.versions = new ArrayList<>( result.getVersions() ); } public List<Version> get() { - if ( count == result.getVersions().size() ) - { - return result.getVersions(); - } - if ( count <= 1 ) - { - if ( count <= 0 ) - { - return Collections.emptyList(); - } - return Collections.singletonList( iterator().next() ); - } - List<Version> versions = new ArrayList<>( count ); - for ( Version version : this ) - { - versions.add( version ); - } - return versions; + return new ArrayList<>( versions ); } public RepositorySystemSession getSession() @@ -113,7 +81,7 @@ final class DefaultVersionFilterContext public int getCount() { - return count; + return versions.size(); } public ArtifactRepository getRepository( Version version ) @@ -128,7 +96,7 @@ final class DefaultVersionFilterContext public Iterator<Version> iterator() { - return ( count > 0 ) ? new VersionIterator() : Collections.<Version>emptySet().iterator(); + return versions.iterator(); } @Override @@ -136,80 +104,4 @@ final class DefaultVersionFilterContext { return dependency + " " + result.getVersions(); } - - private class VersionIterator - implements Iterator<Version> - { - - private final List<Version> versions; - - private final int size; - - private int count; - - private int index; - - private int next; - - VersionIterator() - { - count = DefaultVersionFilterContext.this.count; - index = -1; - next = 0; - versions = result.getVersions(); - size = versions.size(); - advance(); - } - - @SuppressWarnings( "StatementWithEmptyBody" ) - private void advance() - { - for ( next = index + 1; next < size && deleted[next] != (byte) 0; next++ ) - { - // just advancing index - } - } - - public boolean hasNext() - { - return next < size; - } - - public Version next() - { - if ( count != DefaultVersionFilterContext.this.count ) - { - throw new ConcurrentModificationException(); - } - if ( next >= size ) - { - throw new NoSuchElementException(); - } - index = next; - advance(); - return versions.get( index ); - } - - public void remove() - { - if ( count != DefaultVersionFilterContext.this.count ) - { - throw new ConcurrentModificationException(); - } - if ( index < 0 || deleted[index] == (byte) 1 ) - { - throw new IllegalStateException(); - } - deleted[index] = (byte) 1; - count = --DefaultVersionFilterContext.this.count; - } - - @Override - public String toString() - { - return ( index < 0 ) ? "null" : String.valueOf( versions.get( index ) ); - } - - } - } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java index 764a130..379fe53 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/PrioritizedComponentsTest.java @@ -23,6 +23,7 @@ import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -112,4 +113,20 @@ public class PrioritizedComponentsTest assertSame( comp1, sorted.get( 0 ).getComponent() ); assertSame( comp2, sorted.get( 1 ).getComponent() ); } + + @Test + public void testList() + { + Exception comp1 = new IllegalArgumentException(); + Exception comp2 = new NullPointerException(); + + PrioritizedComponents<Exception> components = new PrioritizedComponents<>( Collections.emptyMap() ); + components.add( comp1, 1 ); + components.add( comp2, 0 ); + + StringBuilder stringBuilder = new StringBuilder(); + components.list( stringBuilder ); + + assertEquals( "IllegalArgumentException, NullPointerException", stringBuilder.toString() ); + } } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DataPoolTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DataPoolTest.java index 6baffd2..d8f5524 100644 --- a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DataPoolTest.java +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DataPoolTest.java @@ -25,8 +25,11 @@ import org.eclipse.aether.graph.Dependency; import org.eclipse.aether.repository.RemoteRepository; import org.eclipse.aether.resolution.ArtifactDescriptorRequest; import org.eclipse.aether.resolution.ArtifactDescriptorResult; +import org.eclipse.aether.resolution.VersionRangeRequest; import org.junit.Test; +import java.util.Collections; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -64,4 +67,19 @@ public class DataPoolTest assertEquals( result.getAliases(), cached.getAliases() ); } + @Test + public void testConstraintKey() + { + VersionRangeRequest request = new VersionRangeRequest(); + request.setRepositories( + Collections.singletonList( new RemoteRepository.Builder( "some-id", "some-type", "http://www.example.com" ).build() ) + ); + request.setArtifact( new DefaultArtifact("group:artifact:1.0") ); + + DataPool pool = newDataPool(); + + Object key1 = pool.toKey( request ); + Object key2 = pool.toKey( request ); + assertEquals(key1, key2); + } } diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java new file mode 100644 index 0000000..53cddc2 --- /dev/null +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultDependencyCycleTest.java @@ -0,0 +1,44 @@ +package org.eclipse.aether.internal.impl.collect; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.DefaultDependencyNode; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyCycle; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class DefaultDependencyCycleTest +{ + private static final Dependency FOO_DEPENDENCY = new Dependency( new DefaultArtifact( "group-id:foo:1.0" ), "test" ); + private static final Dependency BAR_DEPENDENCY = new Dependency( new DefaultArtifact( "group-id:bar:1.0" ), "test" ); + + @Test + public void testToString() + { + NodeStack nodeStack = new NodeStack(); + nodeStack.push( new DefaultDependencyNode( FOO_DEPENDENCY ) ); + DependencyCycle cycle = new DefaultDependencyCycle( nodeStack, 1, BAR_DEPENDENCY ); + + assertEquals( "group-id:foo:jar -> group-id:bar:jar", cycle.toString() ); + } +} \ No newline at end of file diff --git a/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContextTest.java b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContextTest.java new file mode 100644 index 0000000..b6fbf5f --- /dev/null +++ b/maven-resolver-impl/src/test/java/org/eclipse/aether/internal/impl/collect/DefaultVersionFilterContextTest.java @@ -0,0 +1,170 @@ +package org.eclipse.aether.internal.impl.collect; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.DefaultRepositorySystemSession; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.internal.test.util.TestVersion; +import org.eclipse.aether.resolution.VersionRangeRequest; +import org.eclipse.aether.resolution.VersionRangeResult; +import org.eclipse.aether.version.Version; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class DefaultVersionFilterContextTest +{ + private static final Dependency FOO_DEPENDENCY = new Dependency( new DefaultArtifact( "group-id:foo:1.0" ), "test" ); + private static final Dependency BAR_DEPENDENCY = new Dependency( new DefaultArtifact( "group-id:bar:1.0" ), "test" ); + + @Test + public void iteratorOneItem() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + assertTrue( iterator.hasNext() ); + assertEquals( new TestVersion( "1.0" ), iterator.next() ); + } + + @Test + public void getCountOneItem() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + assertEquals(1, context.getCount()); + } + + @Test + public void getOneItem() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + assertEquals( Collections.singletonList( new TestVersion( "1.0") ), context.get() ); + } + + @Test + public void iteratorDelete() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + iterator.next(); + iterator.remove(); + + assertEquals( 0, context.getCount() ); + } + + @Test(expected = NoSuchElementException.class) + public void nextBeyondEnd() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + iterator.next(); + iterator.next(); + } + + @Test + public void removeOneOfOne() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + iterator.next(); + iterator.remove(); + + assertEquals( Collections.emptyList(), context.get() ); + } + + @Test + public void removeOneOfTwo() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + result.addVersion( new TestVersion( "2.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + iterator.next(); + iterator.remove(); + + assertEquals( Collections.singletonList( new TestVersion( "2.0") ), context.get() ); + } + + @Test + public void removeOneOfThree() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult result = new VersionRangeResult( new VersionRangeRequest() ); + result.addVersion( new TestVersion( "1.0" ) ); + result.addVersion( new TestVersion( "2.0" ) ); + result.addVersion( new TestVersion( "3.0" ) ); + context.set( FOO_DEPENDENCY, result ); + + Iterator<Version> iterator = context.iterator(); + iterator.next(); + iterator.remove(); + + assertEquals( Arrays.asList( new TestVersion( "2.0" ), new TestVersion( "3.0" ) ), context.get() ); + } + + @Test + public void setTwice() + { + DefaultVersionFilterContext context = new DefaultVersionFilterContext( new DefaultRepositorySystemSession() ); + VersionRangeResult fooResult = new VersionRangeResult( new VersionRangeRequest() ); + fooResult.addVersion( new TestVersion( "1.0" ) ); + context.set( FOO_DEPENDENCY, fooResult ); + + VersionRangeResult barResult = new VersionRangeResult( new VersionRangeRequest() ); + barResult.addVersion( new TestVersion( "1.0" ) ); + barResult.addVersion( new TestVersion( "2.0" ) ); + context.set( BAR_DEPENDENCY, barResult ); + + assertEquals( Arrays.asList( new TestVersion( "1.0" ), new TestVersion( "2.0" ) ), context.get() ); + } +} \ No newline at end of file diff --git a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersion.java b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersion.java index 7d77a16..8109beb 100644 --- a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersion.java +++ b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersion.java @@ -24,13 +24,13 @@ import org.eclipse.aether.version.Version; /** * Version ordering by {@link String#compareToIgnoreCase(String)}. */ -final class TestVersion +public final class TestVersion implements Version { private String version; - TestVersion( String version ) + public TestVersion( String version ) { this.version = version == null ? "" : version; } diff --git a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersionConstraint.java b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersionConstraint.java index 0f93a59..9edd1c9 100644 --- a/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersionConstraint.java +++ b/maven-resolver-test-util/src/main/java/org/eclipse/aether/internal/test/util/TestVersionConstraint.java @@ -30,7 +30,7 @@ import java.util.Objects; /** * A constraint on versions for a dependency. */ -final class TestVersionConstraint +public final class TestVersionConstraint implements VersionConstraint { @@ -43,7 +43,7 @@ final class TestVersionConstraint * * @param range The version range, must not be {@code null}. */ - TestVersionConstraint( VersionRange range ) + public TestVersionConstraint( VersionRange range ) { this.range = requireNonNull( range, "version range cannot be null" ); this.version = null; @@ -54,7 +54,7 @@ final class TestVersionConstraint * * @param version The version, must not be {@code null}. */ - TestVersionConstraint( Version version ) + public TestVersionConstraint( Version version ) { this.version = requireNonNull( version, "version cannot be null" ); this.range = null; diff --git a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java index 149dc2e..e4471a0 100644 --- a/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java +++ b/maven-resolver-util/src/main/java/org/eclipse/aether/util/graph/transformer/ConflictResolver.java @@ -536,9 +536,9 @@ public final class ConflictResolver List<DependencyNode> previousParent = null; int previousDepth = 0; totalConflictItems += items.size(); - for ( int i = items.size() - 1; i >= 0; i-- ) + for ( ListIterator<ConflictItem> iterator = items.listIterator( items.size() ); iterator.hasPrevious(); ) { - ConflictItem item = items.get( i ); + ConflictItem item = iterator.previous(); if ( item.parent == previousParent ) { item.depth = previousDepth; @@ -619,18 +619,20 @@ public final class ConflictResolver { if ( ( changes & NodeInfo.CHANGE_SCOPE ) != 0 ) { - for ( int i = info.children.size() - 1; i >= 0; i-- ) + ListIterator<ConflictItem> itemIterator = info.children.listIterator( info.children.size() ); + while ( itemIterator.hasPrevious() ) { - ConflictItem item = info.children.get( i ); + ConflictItem item = itemIterator.previous(); String childScope = deriveScope( item.node, null ); item.addScope( childScope ); } } if ( ( changes & NodeInfo.CHANGE_OPTIONAL ) != 0 ) { - for ( int i = info.children.size() - 1; i >= 0; i-- ) + ListIterator<ConflictItem> itemIterator = info.children.listIterator( info.children.size() ); + while ( itemIterator.hasPrevious() ) { - ConflictItem item = info.children.get( i ); + ConflictItem item = itemIterator.previous(); boolean childOptional = deriveOptional( item.node, null ); item.addOptional( childOptional ); } diff --git a/maven-resolver-util/src/test/java/org/eclipse/aether/util/graph/transformer/ConflictResolverTest.java b/maven-resolver-util/src/test/java/org/eclipse/aether/util/graph/transformer/ConflictResolverTest.java new file mode 100644 index 0000000..40410a3 --- /dev/null +++ b/maven-resolver-util/src/test/java/org/eclipse/aether/util/graph/transformer/ConflictResolverTest.java @@ -0,0 +1,175 @@ +package org.eclipse.aether.util.graph.transformer; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.eclipse.aether.RepositoryException; +import org.eclipse.aether.artifact.DefaultArtifact; +import org.eclipse.aether.graph.DefaultDependencyNode; +import org.eclipse.aether.graph.Dependency; +import org.eclipse.aether.graph.DependencyNode; +import org.eclipse.aether.internal.test.util.TestUtils; +import org.eclipse.aether.internal.test.util.TestVersion; +import org.eclipse.aether.internal.test.util.TestVersionConstraint; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +public class ConflictResolverTest +{ + @Test + public void noTransformationRequired() throws RepositoryException + { + ConflictResolver resolver = makeDefaultResolver(); + + // Foo -> Bar + DependencyNode fooNode = makeDependencyNode( "group-id", "foo", "1.0" ); + DependencyNode barNode = makeDependencyNode( "group-id", "bar", "1.0" ); + fooNode.setChildren( mutableList( barNode ) ); + + DependencyNode transformedNode = resolver.transformGraph( + fooNode, TestUtils.newTransformationContext( TestUtils.newSession() ) + ); + + assertSame( fooNode, transformedNode ); + assertEquals( 1, transformedNode.getChildren().size() ); + assertSame( barNode, transformedNode.getChildren().get( 0 ) ); + } + + @Test + public void versionClash() throws RepositoryException + { + ConflictResolver resolver = makeDefaultResolver(); + + // Foo -> Bar -> Baz 2.0 + // |---> Baz 1.0 + DependencyNode fooNode = makeDependencyNode( "some-group", "foo", "1.0" ); + DependencyNode barNode = makeDependencyNode( "some-group", "bar", "1.0" ); + DependencyNode baz1Node = makeDependencyNode( "some-group", "baz", "1.0" ); + DependencyNode baz2Node = makeDependencyNode( "some-group", "baz", "2.0" ); + fooNode.setChildren( mutableList( barNode, baz1Node ) ); + barNode.setChildren( mutableList( baz2Node ) ); + + DependencyNode transformedNode = resolver.transformGraph( + fooNode, TestUtils.newTransformationContext( TestUtils.newSession() ) + ); + + assertSame( fooNode, transformedNode ); + assertEquals( 2, fooNode.getChildren().size() ); + assertSame( barNode, fooNode.getChildren().get( 0 ) ); + assertTrue( barNode.getChildren().isEmpty() ); + assertSame( baz1Node, fooNode.getChildren().get( 1 ) ); + } + + @Test + public void derivedScopeChange() throws RepositoryException + { + ConflictResolver resolver = makeDefaultResolver(); + + // Foo -> Bar (test) -> Jaz + // |---> Baz -> Jaz + DependencyNode fooNode = makeDependencyNode( "some-group", "foo", "1.0" ); + DependencyNode barNode = makeDependencyNode( "some-group", "bar", "1.0", "test" ); + DependencyNode bazNode = makeDependencyNode( "some-group", "baz", "1.0" ); + DependencyNode jazNode = makeDependencyNode( "some-group", "jaz", "1.0" ); + fooNode.setChildren( mutableList( barNode, bazNode ) ); + + List<DependencyNode> jazList = mutableList( jazNode ); + barNode.setChildren( jazList ); + bazNode.setChildren( jazList ); + + DependencyNode transformedNode = resolver.transformGraph( + fooNode, TestUtils.newTransformationContext( TestUtils.newSession() ) + ); + + assertSame( fooNode, transformedNode ); + assertEquals( 2, fooNode.getChildren().size() ); + assertSame( barNode, fooNode.getChildren().get( 0 ) ); + assertEquals( 1, barNode.getChildren().size() ); + assertSame( jazNode, barNode.getChildren().get( 0 ) ); + assertSame( bazNode, fooNode.getChildren().get( 1 ) ); + assertEquals( 1, barNode.getChildren().size() ); + assertSame( jazNode, barNode.getChildren().get( 0 ) ); + } + + @Test + public void derivedOptionalStatusChange() throws RepositoryException + { + ConflictResolver resolver = makeDefaultResolver(); + + // Foo -> Bar (optional) -> Jaz + // |---> Baz -> Jaz + DependencyNode fooNode = makeDependencyNode( "some-group", "foo", "1.0" ); + DependencyNode barNode = makeDependencyNode( "some-group", "bar", "1.0" ); + barNode.setOptional(true); + DependencyNode bazNode = makeDependencyNode( "some-group", "baz", "1.0" ); + DependencyNode jazNode = makeDependencyNode( "some-group", "jaz", "1.0" ); + fooNode.setChildren( mutableList( barNode, bazNode ) ); + + List<DependencyNode> jazList = mutableList( jazNode ); + barNode.setChildren( jazList ); + bazNode.setChildren( jazList ); + + DependencyNode transformedNode = resolver.transformGraph( + fooNode, TestUtils.newTransformationContext( TestUtils.newSession() ) + ); + + assertSame( fooNode, transformedNode ); + assertEquals( 2, fooNode.getChildren().size() ); + assertSame( barNode, fooNode.getChildren().get( 0 ) ); + assertEquals( 1, barNode.getChildren().size() ); + assertSame( jazNode, barNode.getChildren().get( 0 ) ); + assertSame( bazNode, fooNode.getChildren().get( 1 ) ); + assertEquals( 1, barNode.getChildren().size() ); + assertSame( jazNode, barNode.getChildren().get( 0 ) ); + } + + private static ConflictResolver makeDefaultResolver() + { + return new ConflictResolver( + new NearestVersionSelector(), new JavaScopeSelector(), new SimpleOptionalitySelector(), new JavaScopeDeriver() + ); + } + + private static DependencyNode makeDependencyNode( String groupId, String artifactId, String version ) + { + return makeDependencyNode( groupId, artifactId, version, "compile" ); + } + + private static DependencyNode makeDependencyNode( String groupId, String artifactId, String version, String scope ) + { + DefaultDependencyNode node = new DefaultDependencyNode( + new Dependency( new DefaultArtifact( groupId + ':' + artifactId + ':' + version ), scope ) + ); + node.setVersion( new TestVersion( version ) ); + node.setVersionConstraint( new TestVersionConstraint( node.getVersion() ) ); + return node; + } + + private static List<DependencyNode> mutableList(DependencyNode... nodes) + { + return new ArrayList<>( Arrays.asList( nodes ) ); + } +} \ No newline at end of file
