Support provided-scope libraries when extracting an executable war - #51372
Support provided-scope libraries when extracting an executable war#51372skdas20 wants to merge 1 commit into
Conversation
|
Note on the red build: the failure is MongoDB 5.9.2 has been published since #51339 bumped the BOM to 5.9.1, so the check flags the drift on any build until that's bumped again. This PR only touches Happy to rebase once that lands if you'd like a green run before reviewing. |
|
@philwebb What do you think about adding a new manifest attribite for the |
|
@mhalbritter that reads better to me than the constant, and I'm happy to redo it that way — it would let the jarmode stop knowing war layout at all, which is really the underlying smell here. One fact that may make the decision easier: the tools jarmode is packaged into the archive it operates on — Shape I'd propose unless you'd rather something else:
That's a wider change than this PR, touching |
|
I like the proposal. I agree with @mhalbritter that it's better than hardcoding the location. |
|
@skdas20 you can go ahead, please implement adding a new manifest attribute for the lib-provided dependencies, which the jartools can then read. |
Extracting an executable war with the tools jarmode failed with "Invalid library location WEB-INF/lib-provided/..." because IndexedJarStructure only knew about the single library location recorded in Spring-Boot-Lib, while the classpath index of a war also references the provided-scope directory that WarLauncher adds to the classpath. Record the provided-scope library location in a new Spring-Boot-Lib-Provided manifest attribute and have the jarmode read it, rather than hardcoding the war layout in the jarmode. The attribute is written only when the layout reports a different location for LibraryScope.PROVIDED than for COMPILE, so jars are unaffected, and it is added to the deny list so it is stripped from the generated launcher manifest like its siblings. Closes spring-projectsgh-51367 Signed-off-by: Sumit Kumar Das <151006536+skdas20@users.noreply.github.com>
5c14f66 to
40e4e83
Compare
|
Thanks @mhalbritter, @philwebb — pushed, and the hardcoded
String libraryLocation = getLayout().getLibraryLocation("", LibraryScope.COMPILE);
putIfHasLength(attributes, BOOT_LIB_ATTRIBUTE, libraryLocation);
String providedLibraryLocation = getLayout().getLibraryLocation("", LibraryScope.PROVIDED);
if (!ObjectUtils.nullSafeEquals(providedLibraryLocation, libraryLocation)) {
putIfHasLength(attributes, BOOT_LIB_PROVIDED_ATTRIBUTE, providedLibraryLocation);
}The comparison against the compile location is doing real work rather than being defensive:
Gradle plugin: As mentioned, no fallback for older archives is needed since Green locally: |
See gh-51367.
Problem
IndexedJarStructure.toStructureDependencyflattens every classpath index entry relative to the singleSpring-Boot-Liblocation:For an executable war
Spring-Boot-LibisWEB-INF/lib/, but provided-scope dependencies (the embedded container among them) are packaged underWEB-INF/lib-provided/byLayouts.Warand are listed inWEB-INF/classpath.idxalongside the rest. The first such entry trips the assertion, so-Djarmode=tools extractfails withInvalid library location WEB-INF/lib-provided/...on any war built from awebstarter.Only
Spring-Boot-Libis recorded in the manifest, so the second location can't be read from there.WarLauncherhas the same need and hardcodes both:Change
Accept entries from either location when flattening, mirroring
WarLauncher, and keep the failure for anything genuinely outside a library root (now an explicitIllegalStateException, since the two-location check no longer fitsAssert.state).Tests
Added to
IndexedJarStructureTests, using a war-shaped manifest and an index containing both aWEB-INF/lib/and aWEB-INF/lib-provided/entry:shouldResolveLibraryEntryFromWarProvidedLocation— the provided entry resolves as aLIBRARYflattened to its bare jar nameshouldCreateLauncherManifestForWarWithProvidedLibraries— both jars appear in the generatedClass-PathBoth fail on
main:With the change the module's tests and
checkFormatMain/checkFormatTestall pass.One thing worth your call: I hardcoded the location as a constant to match
WarLauncher. If you'd rather it be derived (or carried in the manifest as a new attribute so the tools jarmode doesn't need to know war layout at all), happy to redo it that way.