@CompileStatic
class StrictCachedGrapesResolver
extends FileSystemResolver
org.apache.ivy.plugins.resolver.FileSystemResolver subclass that hardens Grape's cachedGrapes
resolver against stub-shaped synthetic descriptors.
Grape's default cachedGrapes (a plain <filesystem>) synthesises
a minimal ivy descriptor when it finds a JAR but no ivy file alongside —
<publications> only, no <dependencies>. The synthetic descriptor
is then written back to disk for next time, so the first artifact-only state
perpetuates itself. Any module hit via the chain after that returns only the
JAR (no transitive deps), causing runtime classloading failures — e.g. when
log4j-core's JAR is present but log4j-api is missing, calls into the log4j API
raise NoClassDefFoundError / MissingPropertyException.
This resolver guards three failure modes:
descriptor=required in the constructor — prevents new
stub synthesis. If the JAR exists but no ivy descriptor, the resolver
returns null and the chain falls through to localm2/ibiblio where the
real POM gets parsed.ivy-<rev>.xml.original (the
original POM) does not, treats the descriptor as if not present. The
.original file is Ivy's record that the descriptor was downloaded
from a real repo; its absence is the load-bearing signal that we're
looking at a synthesised stub rather than a real cached descriptor. This
silently self-heals existing stub corruption..original
and returns null. The chain falls through to localm2/ibiblio and Ivy
re-downloads a fresh copy in the same @Grab call — no second
grab needed. Catching corruption here, rather than at classloading time,
keeps corrupt JARs off the classpath entirely.Strict behaviour is unconditional — if this resolver is in use, both checks
run. Operators who don't want them can simply not declare this resolver in
their ~/.groovy/grapeConfig.xml, dropping back to the stock Ivy
<filesystem> resolver. Stub-rejection skips snapshot revisions
automatically (Maven snapshot caches use timestamped filenames); integrity
validation does not — corruption is corruption.
| Constructor and description |
|---|
StrictCachedGrapesResolver() |
| Type Params | Return Type | Name and description |
|---|---|---|
|
ResolvedResource |
findIvyFileRef(DependencyDescriptor dd, ResolveData data) |
|
static File |
locatePrimaryJar(File ivyFile, ModuleRevisionId mrid)Visible for testing: locate the primary JAR for a module revision in the cachedGrapes layout ( <module-dir>/jars/<name>-<rev>.jar), given the
ivy descriptor file. |
|
static File |
resolvedRefAsFile(ResolvedResource ref)Visible for testing: extract the on-disk File for a resolved ivy resource, or null if the resource is not file-backed. |
|
boolean |
shouldRejectAsCorruptArtifact(ModuleRevisionId mrid, File ivyFile)Visible for testing: decide whether to treat a cached module as having a corrupt primary JAR (truncated, zero bytes, garbage). |
|
boolean |
shouldRejectAsStub(ModuleRevisionId mrid, File ivyFile)Visible for testing: decide whether to treat a cached ivy descriptor as a stub and reject it. |
Visible for testing: locate the primary JAR for a module revision in the
cachedGrapes layout (<module-dir>/jars/<name>-<rev>.jar), given the
ivy descriptor file. Returns null if any layout assumption fails.
Visible for testing: extract the on-disk File for a resolved ivy resource, or null if the resource is not file-backed.
Visible for testing: decide whether to treat a cached module as having a corrupt primary JAR (truncated, zero bytes, garbage). Returns true iff the JAR is locatable on disk in the cachedGrapes layout and opening it as a JarFile raises ZipException. Unrelated I/O errors (e.g. permissions) return false — we only reject on clear zip-format corruption.
Visible for testing: decide whether to treat a cached ivy descriptor as a
stub and reject it. Returns true iff the revision is not a snapshot, the
ivy file's location is known, and no companion ivy-<rev>.xml.original
file exists alongside it.
Copyright © 2003-2026 The Apache Software Foundation. All rights reserved.