This is an automated email from the ASF dual-hosted git repository.
cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-resolver.git
The following commit(s) were added to refs/heads/master by this push:
new 399e68fee Checksums: lack of information (#1917)
399e68fee is described below
commit 399e68fee60c7fd3ad21a3cb28a3615e720cfcec
Author: Tamas Cservenak <[email protected]>
AuthorDate: Sat Jun 13 21:43:35 2026 +0200
Checksums: lack of information (#1917)
Issue: `TrustedChecksumsArtifactResolverPostProcessor` uses wrong ctor of
`ChecksumFailureExxeption` and thus, created exceptions with lack of
information. This was easy mistake to do, as exception already had way too many
constructors.
Fix: This exception is quite special, as it covers many cases: real
mismatch, processing issues during checksum calculation and lack of checksums.
The Resolver intent is to always provide as much information as possible.
Hence, deprecated all constructors, not using them in production code, instead
using new provided helper methods for 3 cases (mismatch, lack of and processing
error), making sure that in each case we provide as much information as
possible.
---
.../aether/transfer/ChecksumFailureException.java | 106 +++++++++++++++++++--
.../aether/connector/basic/ChecksumValidator.java | 18 ++--
.../internal/impl/AbstractChecksumPolicy.java | 2 +-
...stedChecksumsArtifactResolverPostProcessor.java | 23 +++--
...ChecksumsArtifactResolverPostProcessorTest.java | 9 +-
5 files changed, 126 insertions(+), 32 deletions(-)
diff --git
a/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/ChecksumFailureException.java
b/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/ChecksumFailureException.java
index 38dae4341..100bb342b 100644
---
a/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/ChecksumFailureException.java
+++
b/maven-resolver-api/src/main/java/org/eclipse/aether/transfer/ChecksumFailureException.java
@@ -21,7 +21,14 @@ package org.eclipse.aether.transfer;
import org.eclipse.aether.RepositoryException;
/**
- * Thrown in case of a checksum failure during an artifact/metadata download.
+ * Thrown in case of a checksum failure during an artifact/metadata download.
This exception is usually thrown in
+ * following cases:
+ * <ul>
+ * <li>actual checksum <em>mismatch</em>, see {@link #mismatch(String,
String, String)}</li>
+ * <li>lack of required checksums, see {@link #noneAvailable(String,
String)}</li>
+ * <li>processing problem during checksum checks (ie IO problem), see
{@link #processingFailure(String, Throwable)}</li>
+ * </ul>
+ * It is resolver expectation to provide most available information to caller.
*/
public class ChecksumFailureException extends RepositoryException {
@@ -33,6 +40,65 @@ public class ChecksumFailureException extends
RepositoryException {
private final boolean retryWorthy;
+ /**
+ * Use in case of checksum mismatch. Creates a new exception with the
specified expected, expected kind and actual
+ * checksum. The resulting exception is {@link #isRetryWorthy()
retry-worthy}. The checksum match check should
+ * have already happened, this method does not check for any kind of
inequality.
+ *
+ * @param expected The expected checksum as declared by the hosting
repository, may be {@code null}.
+ * @param expectedKind The expected checksum kind, may be {@code null}.
+ * @param actual The actual checksum as computed from the local bytes, may
be {@code null}.
+ * @since 2.0.19
+ */
+ public static ChecksumFailureException mismatch(String expected, String
expectedKind, String actual) {
+ return mismatchDetail(null, expected, expectedKind, actual);
+ }
+
+ /**
+ * Use in case of checksum mismatch. Creates a new exception with the
specified expected, expected kind and actual
+ * checksum. The resulting exception is {@link #isRetryWorthy()
retry-worthy}. The checksum match check should
+ * have already happened, this method does not check for any kind of
inequality.
+ *
+ * @param detail The extra detail/information regarding mismatch.
+ * @param expected The expected checksum as declared by the hosting
repository, may be {@code null}.
+ * @param expectedKind The expected checksum kind, may be {@code null}.
+ * @param actual The actual checksum as computed from the local bytes, may
be {@code null}.
+ * @since 2.0.19
+ */
+ public static ChecksumFailureException mismatchDetail(
+ String detail, String expected, String expectedKind, String
actual) {
+ String message = "Checksum validation failed, expected '"
+ + expected + "'" + (expectedKind == null ? "" : " (" +
expectedKind + ")")
+ + " but is actually '" + actual + "'";
+ if (detail != null) {
+ message = message + " (" + detail + ")";
+ }
+ return new ChecksumFailureException(message, null, expected,
expectedKind, actual, true);
+ }
+
+ /**
+ * Use in case of checksum not available. Optionally, one can specify
which kind was not available.
+ *
+ * @param message The message.
+ * @param expectedKind The expected checksum kind, may be {@code null}.
+ * @since 2.0.19
+ */
+ public static ChecksumFailureException noneAvailable(String message,
String expectedKind) {
+ return new ChecksumFailureException(message, null, "", expectedKind ==
null ? "" : expectedKind, "", false);
+ }
+
+ /**
+ * Use in case of error, for example IO problem during checksum
processing, calculation and alike. Ideally, one
+ * should specify cause as well.
+ *
+ * @param message The message.
+ * @param cause The cause.
+ * @since 2.0.19
+ */
+ public static ChecksumFailureException processingFailure(String message,
Throwable cause) {
+ return new ChecksumFailureException(message, cause, "", "", "", false);
+ }
+
/**
* Creates a new exception with the specified expected, expected kind and
actual checksum. The resulting exception
* is {@link #isRetryWorthy() retry-worthy}.
@@ -41,7 +107,9 @@ public class ChecksumFailureException extends
RepositoryException {
* @param expectedKind The expected checksum kind, may be {@code null}.
* @param actual The actual checksum as computed from the local bytes, may
be {@code null}.
* @since 1.8.0
+ * @deprecated Use {@link #mismatch(String, String, String)} or other
suitable helper method instead.
*/
+ @Deprecated
public ChecksumFailureException(String expected, String expectedKind,
String actual) {
super("Checksum validation failed, expected '"
+ expected + "'" + (expectedKind == null ? "" : " (" +
expectedKind + ")")
@@ -54,33 +122,41 @@ public class ChecksumFailureException extends
RepositoryException {
/**
* Creates a new exception with the specified detail message. The
resulting exception is not
- * {@link #isRetryWorthy() retry-worthy}.
+ * {@link #isRetryWorthy() retry-worthy}. Use this constructor ONLY in
cases like "no data to work with",
+ * like missing checksums. In every other case use some other constructor.
*
* @param message The detail message, may be {@code null}.
+ * @deprecated Use {@link #noneAvailable(String, String)} or other
suitable helper method instead.
*/
+ @Deprecated
public ChecksumFailureException(String message) {
- this(false, message, null);
+ this(message, null, "", "", "", false);
}
/**
* Creates a new exception with the specified cause. The resulting
exception is not {@link #isRetryWorthy()
- * retry-worthy}.
+ * retry-worthy}. Use this constructor in case some other error (ie IO
problem) prevented checksum calculation.
*
* @param cause The exception that caused this one, may be {@code null}.
+ * @deprecated Use {@link #processingFailure(String, Throwable)} or other
helper method instead.
*/
+ @Deprecated
public ChecksumFailureException(Throwable cause) {
- this("Checksum validation failed" + getMessage(": ", cause), cause);
+ this("Checksum validation failed" + getMessage(": ", cause), cause,
"", "", "", false);
}
/**
* Creates a new exception with the specified detail message and cause.
The resulting exception is not
- * {@link #isRetryWorthy() retry-worthy}.
+ * {@link #isRetryWorthy() retry-worthy}. Use this constructor in case
some other error (ie IO problem)
+ * prevented checksum calculation.
*
* @param message The detail message, may be {@code null}.
* @param cause The exception that caused this one, may be {@code null}.
+ * @deprecated Use {@link #processingFailure(String, Throwable)} or other
helper method instead.
*/
+ @Deprecated
public ChecksumFailureException(String message, Throwable cause) {
- this(false, message, cause);
+ this(message, cause, "", "", "", false);
}
/**
@@ -89,12 +165,22 @@ public class ChecksumFailureException extends
RepositoryException {
* @param retryWorthy {@code true} if the exception is retry-worthy,
{@code false} otherwise.
* @param message The detail message, may be {@code null}.
* @param cause The exception that caused this one, may be {@code null}.
+ * @deprecated Do not use this constructor, it lacks information.
*/
+ @Deprecated
public ChecksumFailureException(boolean retryWorthy, String message,
Throwable cause) {
+ this(message, cause, "", "", "", retryWorthy);
+ }
+
+ /**
+ * Hidden constructor, use static helper methods instead, suitable for
your case.
+ */
+ private ChecksumFailureException(
+ String message, Throwable cause, String expected, String
expectedKind, String actual, boolean retryWorthy) {
super(message, cause);
- this.expected = "";
- this.expectedKind = "";
- this.actual = "";
+ this.expected = expected;
+ this.expectedKind = expectedKind;
+ this.actual = actual;
this.retryWorthy = retryWorthy;
}
diff --git
a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
index 850474f0a..39b0cc3ee 100644
---
a/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
+++
b/maven-resolver-connector-basic/src/main/java/org/eclipse/aether/connector/basic/ChecksumValidator.java
@@ -142,7 +142,7 @@ final class ChecksumValidator {
checksumPolicy.onChecksumMismatch(
checksumAlgorithmFactory.getName(),
kind,
- new ChecksumFailureException(expected, kind.name(),
actual));
+ ChecksumFailureException.mismatch(expected,
kind.name(), actual));
} else if
(checksumPolicy.onChecksumMatch(checksumAlgorithmFactory.getName(), kind)) {
return true;
}
@@ -156,8 +156,10 @@ final class ChecksumValidator {
Object calculated = actualChecksums.get(factory.getName());
if (calculated instanceof Exception) {
checksumPolicy.onChecksumError(
- factory.getName(), ChecksumKind.REMOTE_EXTERNAL, new
ChecksumFailureException((Exception)
- calculated));
+ factory.getName(),
+ ChecksumKind.REMOTE_EXTERNAL,
+ ChecksumFailureException.processingFailure(
+ "Checksum calculation problem", (Exception)
calculated));
continue;
}
Path checksumFile =
getChecksumPath(checksumLocation.getChecksumAlgorithmFactory());
@@ -169,7 +171,9 @@ final class ChecksumValidator {
}
} catch (Exception e) {
checksumPolicy.onChecksumError(
- factory.getName(), ChecksumKind.REMOTE_EXTERNAL,
new ChecksumFailureException(e));
+ factory.getName(),
+ ChecksumKind.REMOTE_EXTERNAL,
+
ChecksumFailureException.processingFailure("Checksum fetching problem", e));
continue;
}
@@ -181,13 +185,15 @@ final class ChecksumValidator {
checksumPolicy.onChecksumMismatch(
factory.getName(),
ChecksumKind.REMOTE_EXTERNAL,
- new ChecksumFailureException(expected,
ChecksumKind.REMOTE_EXTERNAL.name(), actual));
+ ChecksumFailureException.mismatch(expected,
ChecksumKind.REMOTE_EXTERNAL.name(), actual));
} else if (checksumPolicy.onChecksumMatch(factory.getName(),
ChecksumKind.REMOTE_EXTERNAL)) {
return true;
}
} catch (IOException e) {
checksumPolicy.onChecksumError(
- factory.getName(), ChecksumKind.REMOTE_EXTERNAL, new
ChecksumFailureException(e));
+ factory.getName(),
+ ChecksumKind.REMOTE_EXTERNAL,
+ ChecksumFailureException.processingFailure("Checksum
related IO problem", e));
}
}
return false;
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
index 153994f60..2007042fc 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/AbstractChecksumPolicy.java
@@ -60,7 +60,7 @@ abstract class AbstractChecksumPolicy implements
ChecksumPolicy {
@Override
public void onNoMoreChecksums() throws ChecksumFailureException {
- throw new ChecksumFailureException("Checksum validation failed, no
checksums available");
+ throw ChecksumFailureException.noneAvailable("Checksum validation
failed, no checksums available", null);
}
@Override
diff --git
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor.java
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor.java
index 50033b930..e6137de09 100644
---
a/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor.java
+++
b/maven-resolver-impl/src/main/java/org/eclipse/aether/internal/impl/resolution/TrustedChecksumsArtifactResolverPostProcessor.java
@@ -38,6 +38,7 @@ import
org.eclipse.aether.spi.checksums.TrustedChecksumsSource;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactory;
import
org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmFactorySelector;
import org.eclipse.aether.spi.connector.checksum.ChecksumAlgorithmHelper;
+import org.eclipse.aether.spi.connector.checksum.ChecksumPolicy;
import org.eclipse.aether.transfer.ChecksumFailureException;
import org.eclipse.aether.util.ConfigUtils;
import org.eclipse.aether.util.artifact.ArtifactIdUtils;
@@ -274,9 +275,11 @@ public final class
TrustedChecksumsArtifactResolverPostProcessor extends Artifac
if (!missingTrustedAlg.isEmpty() && failIfMissing) {
artifactResult.addException(
artifactRepository,
- new ChecksumFailureException("Missing from " +
trustedSourceName
- + " trusted checksum(s) " +
missingTrustedAlg + " for artifact "
- + ArtifactIdUtils.toId(artifact)));
+ ChecksumFailureException.noneAvailable(
+ "Missing from " + trustedSourceName
+ + " trusted checksum(s) " +
missingTrustedAlg + " for artifact "
+ +
ArtifactIdUtils.toId(artifact),
+
ChecksumPolicy.ChecksumKind.PROVIDED.name()));
valid = false;
}
@@ -288,10 +291,11 @@ public final class
TrustedChecksumsArtifactResolverPostProcessor extends Artifac
if (trustedChecksum != null &&
!Objects.equals(calculatedChecksum, trustedChecksum)) {
artifactResult.addException(
artifactRepository,
- new ChecksumFailureException("Artifact "
- + ArtifactIdUtils.toId(artifact) +
" trusted checksum mismatch: "
- + trustedSourceName + "=" +
trustedChecksum + "; calculated="
- + calculatedChecksum));
+ ChecksumFailureException.mismatchDetail(
+ "Trusted Checksums Source: " +
trustedSourceName,
+ trustedChecksum,
+
ChecksumPolicy.ChecksumKind.PROVIDED.name(),
+ calculatedChecksum));
valid = false;
}
}
@@ -301,8 +305,9 @@ public final class
TrustedChecksumsArtifactResolverPostProcessor extends Artifac
if (!validated && failIfMissing) {
artifactResult.addException(
artifactRepository,
- new ChecksumFailureException(
- "There are no enabled trusted checksums" + "
source(s) to validate against."));
+ ChecksumFailureException.noneAvailable(
+ "There are no enabled trusted checksums
source(s) to validate against.",
+ ChecksumPolicy.ChecksumKind.PROVIDED.name()));
valid = false;
}
} catch (IOException e) {
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 c82a8e0c0..3f6a5dbb5 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
@@ -206,12 +206,9 @@ public class
TrustedChecksumsArtifactResolverPostProcessorTest implements Truste
subject.postProcess(session,
Collections.singletonList(artifactResult));
assertFalse(artifactResult.isResolved());
assertFalse(artifactResult.getExceptions().isEmpty());
-
assertTrue(artifactResult.getExceptions().get(0).getMessage().contains("trusted
checksum mismatch"));
- assertTrue(artifactResult
- .getExceptions()
- .get(0)
- .getMessage()
- .contains(TRUSTED_SOURCE_NAME + "=" +
artifactTrustedChecksum));
+ assertEquals(
+ "Checksum validation failed, expected 'foobar' (PROVIDED) but
is actually 'da39a3ee5e6b4b0d3255bfef95601890afd80709' (Trusted Checksums
Source: test)",
+ artifactResult.getExceptions().get(0).getMessage());
}
@Test