Skip to content

Commit b790c82

Browse files
mbhavephilwebb
andcommitted
Apply exclusions to existing war entries
Update `RepackageMojo` and supporting classes so that `exclusions` on the repackage goal apply to both the contributed libraries and any existing jar entries already contained in the original war. Prior to this commit, exclusions would apply to contributed jars (for example, those in `WEB-INF/lib-provided`) but not jars that were packaged directly into `WEB-INF/lib` by the war plugin Fixes gh-15808 Co-authored-by: Phillip Webb <[email protected]>
1 parent 4d694dd commit b790c82

File tree

17 files changed

+346
-81
lines changed

17 files changed

+346
-81
lines changed

spring-boot-project/spring-boot-cli/src/main/java/org/springframework/boot/cli/command/archive/ArchiveCommand.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ private List<Library> createLibraries(List<URL> dependencies) throws URISyntaxEx
198198
List<Library> libraries = new ArrayList<>();
199199
for (URL dependency : dependencies) {
200200
File file = new File(dependency.toURI());
201-
libraries.add(new Library(file, getLibraryScope(file)));
201+
libraries.add(new Library(null, file, getLibraryScope(file), null, false, false, true));
202202
}
203203
return libraries;
204204
}
@@ -256,7 +256,7 @@ private List<Library> addClasspathEntries(JarWriter writer, List<MatchedResource
256256
List<Library> libraries = new ArrayList<>();
257257
for (MatchedResource entry : entries) {
258258
if (entry.isRoot()) {
259-
libraries.add(new Library(entry.getFile(), LibraryScope.COMPILE));
259+
libraries.add(new Library(null, entry.getFile(), LibraryScope.COMPILE, null, false, false, true));
260260
}
261261
else {
262262
writeClasspathEntry(writer, entry);

spring-boot-project/spring-boot-tools/spring-boot-gradle-plugin/src/main/java/org/springframework/boot/gradle/tasks/bundling/LayerResolver.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.boot.gradle.tasks.bundling.ResolvedDependencies.DependencyDescriptor;
2525
import org.springframework.boot.loader.tools.Layer;
2626
import org.springframework.boot.loader.tools.Library;
27+
import org.springframework.boot.loader.tools.LibraryCoordinates;
2728

2829
/**
2930
* Resolver backed by a {@link LayeredSpec} that provides the destination {@link Layer}
@@ -77,9 +78,12 @@ Iterable<Layer> getLayers() {
7778
private Library asLibrary(FileCopyDetails details) {
7879
File file = details.getFile();
7980
DependencyDescriptor dependency = this.resolvedDependencies.find(file);
80-
return (dependency != null)
81-
? new Library(null, file, null, dependency.getCoordinates(), false, dependency.isProjectDependency())
82-
: new Library(file, null);
81+
if (dependency == null) {
82+
return new Library(null, file, null, null, false, false, true);
83+
}
84+
LibraryCoordinates coordinates = dependency.getCoordinates();
85+
boolean projectDependency = dependency.isProjectDependency();
86+
return new Library(null, file, null, coordinates, false, projectDependency, true);
8387
}
8488

8589
}

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/AbstractJarWriter.java

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import java.util.Enumeration;
3131
import java.util.HashSet;
3232
import java.util.Set;
33+
import java.util.function.Predicate;
3334
import java.util.jar.JarEntry;
3435
import java.util.jar.JarFile;
3536
import java.util.jar.JarInputStream;
@@ -88,23 +89,42 @@ public void writeManifest(Manifest manifest) throws IOException {
8889
* Write all entries from the specified jar file.
8990
* @param jarFile the source jar file
9091
* @throws IOException if the entries cannot be written
92+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
93+
* {@link #writeEntries(JarFile, EntryTransformer, UnpackHandler, Predicate)}
9194
*/
95+
@Deprecated
9296
public void writeEntries(JarFile jarFile) throws IOException {
93-
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER);
97+
writeEntries(jarFile, EntryTransformer.NONE, UnpackHandler.NEVER, (entry) -> true);
9498
}
9599

96-
final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler)
97-
throws IOException {
100+
/**
101+
* Write required entries from the specified jar file.
102+
* @param jarFile the source jar file
103+
* @param entryTransformer the entity transformer used to change the entry
104+
* @param unpackHandler the unpack handler
105+
* @param entryFilter a predicate used to filter the written entries
106+
* @throws IOException if the entries cannot be written
107+
* @since 2.4.8
108+
*/
109+
public void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,
110+
Predicate<JarEntry> entryFilter) throws IOException {
98111
Enumeration<JarEntry> entries = jarFile.entries();
99112
while (entries.hasMoreElements()) {
100-
JarArchiveEntry entry = new JarArchiveEntry(entries.nextElement());
101-
setUpEntry(jarFile, entry);
102-
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {
103-
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
104-
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
105-
if (transformedEntry != null) {
106-
writeEntry(transformedEntry, entryWriter, unpackHandler, true);
107-
}
113+
JarEntry entry = entries.nextElement();
114+
if (entryFilter.test(entry)) {
115+
writeEntry(jarFile, entryTransformer, unpackHandler, new JarArchiveEntry(entry));
116+
}
117+
}
118+
}
119+
120+
private void writeEntry(JarFile jarFile, EntryTransformer entryTransformer, UnpackHandler unpackHandler,
121+
JarArchiveEntry entry) throws IOException {
122+
setUpEntry(jarFile, entry);
123+
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {
124+
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
125+
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
126+
if (transformedEntry != null) {
127+
writeEntry(transformedEntry, entryWriter, unpackHandler, true);
108128
}
109129
}
110130
}

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/JarModeLibrary.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ public class JarModeLibrary extends Library {
4242
}
4343

4444
public JarModeLibrary(LibraryCoordinates coordinates) {
45-
super(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false);
45+
super(getJarName(coordinates), null, LibraryScope.RUNTIME, coordinates, false, false, true);
4646
}
4747

4848
private static LibraryCoordinates createCoordinates(String artifactId) {

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Library.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,16 @@ public class Library {
4343

4444
private final boolean local;
4545

46+
private final boolean included;
47+
4648
/**
4749
* Create a new {@link Library}.
4850
* @param file the source file
4951
* @param scope the scope of the library
52+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
53+
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
5054
*/
55+
@Deprecated
5156
public Library(File file, LibraryScope scope) {
5257
this(file, scope, false);
5358
}
@@ -57,7 +62,10 @@ public Library(File file, LibraryScope scope) {
5762
* @param file the source file
5863
* @param scope the scope of the library
5964
* @param unpackRequired if the library needs to be unpacked before it can be used
65+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
66+
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
6067
*/
68+
@Deprecated
6169
public Library(File file, LibraryScope scope, boolean unpackRequired) {
6270
this(null, file, scope, unpackRequired);
6371
}
@@ -69,7 +77,10 @@ public Library(File file, LibraryScope scope, boolean unpackRequired) {
6977
* @param file the source file
7078
* @param scope the scope of the library
7179
* @param unpackRequired if the library needs to be unpacked before it can be used
80+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
81+
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
7282
*/
83+
@Deprecated
7384
public Library(String name, File file, LibraryScope scope, boolean unpackRequired) {
7485
this(name, file, scope, null, unpackRequired);
7586
}
@@ -82,7 +93,10 @@ public Library(String name, File file, LibraryScope scope, boolean unpackRequire
8293
* @param scope the scope of the library
8394
* @param coordinates the library coordinates or {@code null}
8495
* @param unpackRequired if the library needs to be unpacked before it can be used
96+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
97+
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
8598
*/
99+
@Deprecated
86100
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired) {
87101
this(name, file, scope, coordinates, unpackRequired, false);
88102
}
@@ -98,15 +112,37 @@ public Library(String name, File file, LibraryScope scope, LibraryCoordinates co
98112
* @param local if the library is local (part of the same build) to the application
99113
* that is being packaged
100114
* @since 2.4.0
115+
* @deprecated since 2.4.8 for removal in 2.6.0 in favor of
116+
* {@link #Library(String, File, LibraryScope, LibraryCoordinates, boolean, boolean, boolean)}
101117
*/
118+
@Deprecated
102119
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired,
103120
boolean local) {
121+
this(name, file, scope, coordinates, unpackRequired, local, true);
122+
}
123+
124+
/**
125+
* Create a new {@link Library}.
126+
* @param name the name of the library as it should be written or {@code null} to use
127+
* the file name
128+
* @param file the source file
129+
* @param scope the scope of the library
130+
* @param coordinates the library coordinates or {@code null}
131+
* @param unpackRequired if the library needs to be unpacked before it can be used
132+
* @param local if the library is local (part of the same build) to the application
133+
* that is being packaged
134+
* @param included if the library is included in the fat jar
135+
* @since 2.4.8
136+
*/
137+
public Library(String name, File file, LibraryScope scope, LibraryCoordinates coordinates, boolean unpackRequired,
138+
boolean local, boolean included) {
104139
this.name = (name != null) ? name : file.getName();
105140
this.file = file;
106141
this.scope = scope;
107142
this.coordinates = coordinates;
108143
this.unpackRequired = unpackRequired;
109144
this.local = local;
145+
this.included = included;
110146
}
111147

112148
/**
@@ -172,4 +208,12 @@ public boolean isLocal() {
172208
return this.local;
173209
}
174210

211+
/**
212+
* Return if the library is included in the fat jar.
213+
* @return if the library is included
214+
*/
215+
public boolean isIncluded() {
216+
return this.included;
217+
}
218+
175219
}

spring-boot-project/spring-boot-tools/spring-boot-loader-tools/src/main/java/org/springframework/boot/loader/tools/Packager.java

Lines changed: 54 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,9 @@
2525
import java.util.Map;
2626
import java.util.Map.Entry;
2727
import java.util.concurrent.TimeUnit;
28+
import java.util.function.Predicate;
2829
import java.util.jar.Attributes;
30+
import java.util.jar.JarEntry;
2931
import java.util.jar.JarFile;
3032
import java.util.jar.Manifest;
3133
import java.util.stream.Collectors;
@@ -191,14 +193,18 @@ protected final boolean isAlreadyPackaged(File file) {
191193

192194
protected final void write(JarFile sourceJar, Libraries libraries, AbstractJarWriter writer) throws IOException {
193195
Assert.notNull(libraries, "Libraries must not be null");
194-
WritableLibraries writeableLibraries = new WritableLibraries(libraries);
196+
write(sourceJar, writer, new PackagedLibraries(libraries));
197+
}
198+
199+
private void write(JarFile sourceJar, AbstractJarWriter writer, PackagedLibraries libraries) throws IOException {
195200
if (isLayered()) {
196201
writer.useLayers(this.layers, this.layersIndex);
197202
}
198203
writer.writeManifest(buildManifest(sourceJar));
199204
writeLoaderClasses(writer);
200-
writer.writeEntries(sourceJar, getEntityTransformer(), writeableLibraries);
201-
writeableLibraries.write(writer);
205+
writer.writeEntries(sourceJar, getEntityTransformer(), libraries.getUnpackHandler(),
206+
libraries.getEntryFilter());
207+
libraries.write(writer);
202208
if (isLayered()) {
203209
writeLayerIndex(writer);
204210
}
@@ -456,11 +462,15 @@ private boolean isTransformable(JarArchiveEntry entry) {
456462
* An {@link UnpackHandler} that determines that an entry needs to be unpacked if a
457463
* library that requires unpacking has a matching entry name.
458464
*/
459-
private final class WritableLibraries implements UnpackHandler {
465+
private final class PackagedLibraries {
460466

461467
private final Map<String, Library> libraries = new LinkedHashMap<>();
462468

463-
WritableLibraries(Libraries libraries) throws IOException {
469+
private final UnpackHandler unpackHandler;
470+
471+
private final Predicate<JarEntry> entryFilter;
472+
473+
PackagedLibraries(Libraries libraries) throws IOException {
464474
libraries.doWithLibraries((library) -> {
465475
if (isZip(library::openStream)) {
466476
addLibrary(library);
@@ -469,6 +479,8 @@ private final class WritableLibraries implements UnpackHandler {
469479
if (isLayered() && Packager.this.includeRelevantJarModeJars) {
470480
addLibrary(JarModeLibrary.LAYER_TOOLS);
471481
}
482+
this.unpackHandler = new PackagedLibrariesUnpackHandler();
483+
this.entryFilter = this::isIncluded;
472484
}
473485

474486
private void addLibrary(Library library) {
@@ -480,37 +492,58 @@ private void addLibrary(Library library) {
480492
}
481493
}
482494

483-
@Override
484-
public boolean requiresUnpack(String name) {
485-
Library library = this.libraries.get(name);
486-
return library != null && library.isUnpackRequired();
495+
private boolean isIncluded(JarEntry entry) {
496+
Library library = this.libraries.get(entry.getName());
497+
return library == null || library.isIncluded();
487498
}
488499

489-
@Override
490-
public String sha1Hash(String name) throws IOException {
491-
Library library = this.libraries.get(name);
492-
Assert.notNull(library, () -> "No library found for entry name '" + name + "'");
493-
return Digest.sha1(library::openStream);
500+
UnpackHandler getUnpackHandler() {
501+
return this.unpackHandler;
502+
}
503+
504+
Predicate<JarEntry> getEntryFilter() {
505+
return this.entryFilter;
494506
}
495507

496-
private void write(AbstractJarWriter writer) throws IOException {
508+
void write(AbstractJarWriter writer) throws IOException {
509+
List<String> writtenPaths = new ArrayList<>();
497510
for (Entry<String, Library> entry : this.libraries.entrySet()) {
498511
String path = entry.getKey();
499512
Library library = entry.getValue();
500-
String location = path.substring(0, path.lastIndexOf('/') + 1);
501-
writer.writeNestedLibrary(location, library);
513+
if (library.isIncluded()) {
514+
String location = path.substring(0, path.lastIndexOf('/') + 1);
515+
writer.writeNestedLibrary(location, library);
516+
writtenPaths.add(path);
517+
}
502518
}
503519
if (getLayout() instanceof RepackagingLayout) {
504-
writeClasspathIndex((RepackagingLayout) getLayout(), writer);
520+
writeClasspathIndex(writtenPaths, (RepackagingLayout) getLayout(), writer);
505521
}
506522
}
507523

508-
private void writeClasspathIndex(RepackagingLayout layout, AbstractJarWriter writer) throws IOException {
509-
List<String> names = this.libraries.keySet().stream().map((path) -> "- \"" + path + "\"")
510-
.collect(Collectors.toList());
524+
private void writeClasspathIndex(List<String> paths, RepackagingLayout layout, AbstractJarWriter writer)
525+
throws IOException {
526+
List<String> names = paths.stream().map((path) -> "- \"" + path + "\"").collect(Collectors.toList());
511527
writer.writeIndexFile(layout.getClasspathIndexFileLocation(), names);
512528
}
513529

530+
private class PackagedLibrariesUnpackHandler implements UnpackHandler {
531+
532+
@Override
533+
public boolean requiresUnpack(String name) {
534+
Library library = PackagedLibraries.this.libraries.get(name);
535+
return library != null && library.isUnpackRequired();
536+
}
537+
538+
@Override
539+
public String sha1Hash(String name) throws IOException {
540+
Library library = PackagedLibraries.this.libraries.get(name);
541+
Assert.notNull(library, () -> "No library found for entry name '" + name + "'");
542+
return Digest.sha1(library::openStream);
543+
}
544+
545+
}
546+
514547
}
515548

516549
}

0 commit comments

Comments
 (0)