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

Reply via email to