Skip to content

Commit 4e3cdf9

Browse files
mbhavephilwebb
andcommitted
Support flat jar layering with Maven
Update the Maven plugin so that layered jars now use the regular "flat" format. The layers.idx file now describes which layer each file should be placed. See gh-20813 Co-authored-by: Phillip Webb <[email protected]>
1 parent 3f806aa commit 4e3cdf9

File tree

15 files changed

+346
-201
lines changed

15 files changed

+346
-201
lines changed

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

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ final void writeEntries(JarFile jarFile, EntryTransformer entryTransformer, Unpa
8686
JarArchiveEntry entry = new JarArchiveEntry(entries.nextElement());
8787
setUpEntry(jarFile, entry);
8888
try (ZipHeaderPeekInputStream inputStream = new ZipHeaderPeekInputStream(jarFile.getInputStream(entry))) {
89-
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream);
89+
EntryWriter entryWriter = new InputStreamEntryWriter(inputStream, false);
9090
JarArchiveEntry transformedEntry = entryTransformer.transform(entry);
9191
if (transformedEntry != null) {
9292
writeEntry(transformedEntry, entryWriter, unpackHandler);
@@ -114,13 +114,18 @@ private void setUpEntry(JarFile jarFile, JarArchiveEntry entry) throws IOExcepti
114114
*/
115115
@Override
116116
public void writeEntry(String entryName, InputStream inputStream) throws IOException {
117+
writeEntry(entryName, new InputStreamEntryWriter(inputStream, true));
118+
}
119+
120+
/**
121+
* Writes an entry. The {@code inputStream} is closed once the entry has been written
122+
* @param entryName the name of the entry
123+
* @param entryWriter the entry writer
124+
* @throws IOException if the write fails
125+
*/
126+
public void writeEntry(String entryName, EntryWriter entryWriter) throws IOException {
117127
JarArchiveEntry entry = new JarArchiveEntry(entryName);
118-
try {
119-
writeEntry(entry, new InputStreamEntryWriter(inputStream));
120-
}
121-
finally {
122-
inputStream.close();
123-
}
128+
writeEntry(entry, entryWriter);
124129
}
125130

126131
/**
@@ -133,9 +138,7 @@ public void writeNestedLibrary(String location, Library library) throws IOExcept
133138
JarArchiveEntry entry = new JarArchiveEntry(location + library.getName());
134139
entry.setTime(getNestedLibraryTime(library));
135140
new CrcAndSize(library::openStream).setupStoredEntry(entry);
136-
try (InputStream inputStream = library.openStream()) {
137-
writeEntry(entry, new InputStreamEntryWriter(inputStream), new LibraryUnpackHandler(library));
138-
}
141+
writeEntry(entry, new InputStreamEntryWriter(library.openStream(), true), new LibraryUnpackHandler(library));
139142
}
140143

141144
/**
@@ -200,7 +203,7 @@ public void writeLoaderClasses(String loaderJarResourceName) throws IOException
200203
JarEntry entry;
201204
while ((entry = inputStream.getNextJarEntry()) != null) {
202205
if (entry.getName().endsWith(".class")) {
203-
writeEntry(new JarArchiveEntry(entry), new InputStreamEntryWriter(inputStream));
206+
writeEntry(new JarArchiveEntry(entry), new InputStreamEntryWriter(inputStream, false));
204207
}
205208
}
206209
}
@@ -254,7 +257,7 @@ private EntryWriter addUnpackCommentIfNecessary(JarArchiveEntry entry, EntryWrit
254257
ByteArrayOutputStream output = new ByteArrayOutputStream();
255258
entryWriter.write(output);
256259
entry.setComment("UNPACK:" + unpackHandler.sha1Hash(entry.getName()));
257-
return new InputStreamEntryWriter(new ByteArrayInputStream(output.toByteArray()));
260+
return new InputStreamEntryWriter(new ByteArrayInputStream(output.toByteArray()), true);
258261
}
259262

260263
/**
@@ -264,8 +267,11 @@ private static class InputStreamEntryWriter implements EntryWriter {
264267

265268
private final InputStream inputStream;
266269

267-
InputStreamEntryWriter(InputStream inputStream) {
270+
private final boolean close;
271+
272+
InputStreamEntryWriter(InputStream inputStream, boolean close) {
268273
this.inputStream = inputStream;
274+
this.close = close;
269275
}
270276

271277
@Override
@@ -276,6 +282,9 @@ public void write(OutputStream outputStream) throws IOException {
276282
outputStream.write(buffer, 0, bytesRead);
277283
}
278284
outputStream.flush();
285+
if (this.close) {
286+
this.inputStream.close();
287+
}
279288
}
280289

281290
}

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

Lines changed: 0 additions & 55 deletions
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
/*
2+
* Copyright 2012-2020 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.loader.tools;
18+
19+
import java.io.BufferedWriter;
20+
import java.io.IOException;
21+
import java.io.OutputStream;
22+
import java.io.OutputStreamWriter;
23+
import java.nio.charset.StandardCharsets;
24+
import java.util.List;
25+
26+
import org.springframework.util.LinkedMultiValueMap;
27+
import org.springframework.util.MultiValueMap;
28+
29+
/**
30+
* Index describing the layer to which each entry in a jar belongs.
31+
*
32+
* @author Madhura Bhave
33+
* @author Andy Wilkinson
34+
* @since 2.3.0
35+
*/
36+
public class LayersIndex {
37+
38+
private final Iterable<Layer> layers;
39+
40+
private final MultiValueMap<Layer, String> index = new LinkedMultiValueMap<>();
41+
42+
/**
43+
* Create a new {@link LayersIndex} backed by the given layers.
44+
* @param layers the layers in the index
45+
*/
46+
public LayersIndex(Iterable<Layer> layers) {
47+
this.layers = layers;
48+
}
49+
50+
/**
51+
* Add an item to the index.
52+
* @param layer the layer of the item
53+
* @param name the name of the item
54+
*/
55+
public void add(Layer layer, String name) {
56+
this.index.add(layer, name);
57+
}
58+
59+
/**
60+
* Write the layer index to an output stream.
61+
* @param out the destination stream
62+
* @throws IOException on IO error
63+
*/
64+
public void writeTo(OutputStream out) throws IOException {
65+
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, StandardCharsets.UTF_8));
66+
for (Layer layer : this.layers) {
67+
List<String> names = this.index.get(layer);
68+
if (names != null) {
69+
for (String name : names) {
70+
writer.write(layer.toString());
71+
writer.write(" ");
72+
writer.write(name);
73+
writer.write("\n");
74+
}
75+
}
76+
}
77+
writer.flush();
78+
79+
}
80+
81+
}

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

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -94,31 +94,14 @@ public String getClasspathIndexFileLocation() {
9494
return "BOOT-INF/classpath.idx";
9595
}
9696

97-
@Override
98-
public boolean isExecutable() {
99-
return true;
100-
}
101-
102-
}
103-
104-
/**
105-
* Executable JAR layout with support for layers.
106-
*/
107-
public static class LayeredJar extends Jar implements LayeredLayout {
108-
10997
@Override
11098
public String getLayersIndexFileLocation() {
11199
return "BOOT-INF/layers.idx";
112100
}
113101

114102
@Override
115-
public String getRepackagedClassesLocation(Layer layer) {
116-
return "BOOT-INF/layers/" + layer + "/classes/";
117-
}
118-
119-
@Override
120-
public String getLibraryLocation(String libraryName, LibraryScope scope, Layer layer) {
121-
return "BOOT-INF/layers/" + layer + "/lib/";
103+
public boolean isExecutable() {
104+
return true;
122105
}
123106

124107
}

0 commit comments

Comments
 (0)