001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.eclipse.aether.collection; 020 021import java.util.Collection; 022import java.util.Collections; 023import java.util.Iterator; 024import java.util.LinkedHashSet; 025import java.util.List; 026 027import org.eclipse.aether.RepositoryException; 028import org.eclipse.aether.artifact.Artifact; 029import org.eclipse.aether.graph.DependencyNode; 030import org.eclipse.aether.version.VersionConstraint; 031 032import static java.util.Objects.requireNonNull; 033 034/** 035 * Thrown in case of an unsolvable conflict between different version constraints for a dependency. 036 */ 037public class UnsolvableVersionConflictException extends RepositoryException { 038 039 private final transient Collection<String> versions; 040 041 private final transient Collection<? extends List<? extends DependencyNode>> paths; 042 043 /** 044 * Creates a new exception with the specified paths to conflicting nodes in the dependency graph. 045 * 046 * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}. 047 * @deprecated Use {@link #UnsolvableVersionConflictException(String, Collection)} instead. 048 */ 049 @Deprecated 050 public UnsolvableVersionConflictException(Collection<? extends List<? extends DependencyNode>> paths) { 051 this("Unsolvable hard constraint combination", paths); 052 } 053 054 /** 055 * Creates a new exception with the specified paths to conflicting nodes in the dependency graph. 056 * 057 * @param message The strategy that throw the bucket in, must not be {@code null}. Should provide concise message 058 * why this exception was thrown. 059 * @param paths The paths to the dependency nodes that participate in the version conflict, may be {@code null}. 060 * 061 * @since 2.0.0 062 */ 063 public UnsolvableVersionConflictException( 064 String message, Collection<? extends List<? extends DependencyNode>> paths) { 065 super(requireNonNull(message, "message") + "; Could not resolve version conflict among " + toPaths(paths)); 066 if (paths == null) { 067 this.paths = Collections.emptyList(); 068 this.versions = Collections.emptyList(); 069 } else { 070 this.paths = paths; 071 this.versions = new LinkedHashSet<>(); 072 for (List<? extends DependencyNode> path : paths) { 073 VersionConstraint constraint = path.get(path.size() - 1).getVersionConstraint(); 074 if (constraint != null && constraint.getRange() != null) { 075 versions.add(constraint.toString()); 076 } 077 } 078 } 079 } 080 081 private static String toPaths(Collection<? extends List<? extends DependencyNode>> paths) { 082 String result = ""; 083 084 if (paths != null) { 085 Collection<String> strings = new LinkedHashSet<>(); 086 087 for (List<? extends DependencyNode> path : paths) { 088 strings.add(toPath(path)); 089 } 090 091 result = strings.toString(); 092 } 093 094 return result; 095 } 096 097 private static String toPath(List<? extends DependencyNode> path) { 098 StringBuilder buffer = new StringBuilder(256); 099 100 for (Iterator<? extends DependencyNode> it = path.iterator(); it.hasNext(); ) { 101 DependencyNode node = it.next(); 102 if (node.getDependency() == null) { 103 continue; 104 } 105 106 Artifact artifact = node.getDependency().getArtifact(); 107 buffer.append(artifact.getGroupId()); 108 buffer.append(':').append(artifact.getArtifactId()); 109 buffer.append(':').append(artifact.getExtension()); 110 if (!artifact.getClassifier().isEmpty()) { 111 buffer.append(':').append(artifact.getClassifier()); 112 } 113 buffer.append(':').append(node.getVersionConstraint()); 114 115 if (it.hasNext()) { 116 buffer.append(" -> "); 117 } 118 } 119 120 return buffer.toString(); 121 } 122 123 /** 124 * Gets the paths leading to the conflicting dependencies. 125 * 126 * @return The (read-only) paths leading to the conflicting dependencies, never {@code null}. 127 */ 128 public Collection<? extends List<? extends DependencyNode>> getPaths() { 129 return paths; 130 } 131 132 /** 133 * Gets the conflicting version constraints of the dependency. 134 * 135 * @return The (read-only) conflicting version constraints, never {@code null}. 136 */ 137 public Collection<String> getVersions() { 138 return versions; 139 } 140}