mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-09-03 04:26:12 +08:00
Reuse previously parsed entries for filtered JARs
Update JarFile to reuse the previously parsed entries when creating filtered jars. This saves needing to re-scan the underlying file to recreate a subset of entries. See gh-1119
This commit is contained in:
parent
e9aab1e90c
commit
88195292dd
@ -55,20 +55,26 @@ public final class JarEntryData {
|
||||
|
||||
public JarEntryData(JarFile source, byte[] header, InputStream inputStream)
|
||||
throws IOException {
|
||||
|
||||
this.source = source;
|
||||
this.header = header;
|
||||
long nameLength = Bytes.littleEndianValue(header, 28, 2);
|
||||
long extraLength = Bytes.littleEndianValue(header, 30, 2);
|
||||
long commentLength = Bytes.littleEndianValue(header, 32, 2);
|
||||
|
||||
this.name = new AsciiBytes(Bytes.get(inputStream, nameLength));
|
||||
this.extra = Bytes.get(inputStream, extraLength);
|
||||
this.comment = new AsciiBytes(Bytes.get(inputStream, commentLength));
|
||||
|
||||
this.localHeaderOffset = Bytes.littleEndianValue(header, 42, 4);
|
||||
}
|
||||
|
||||
private JarEntryData(JarEntryData master, JarFile source, AsciiBytes name) {
|
||||
this.header = master.header;
|
||||
this.extra = master.extra;
|
||||
this.comment = master.comment;
|
||||
this.localHeaderOffset = master.localHeaderOffset;
|
||||
this.source = source;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
void setName(AsciiBytes name) {
|
||||
this.name = name;
|
||||
}
|
||||
@ -154,6 +160,10 @@ public final class JarEntryData {
|
||||
return this.comment;
|
||||
}
|
||||
|
||||
JarEntryData createFilteredCopy(JarFile jarFile, AsciiBytes name) {
|
||||
return new JarEntryData(this, jarFile, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link JarEntryData} instance from the specified input stream.
|
||||
* @param source the source {@link JarFile}
|
||||
|
@ -68,18 +68,16 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
|
||||
private final RandomAccessDataFile rootFile;
|
||||
|
||||
private final RandomAccessData data;
|
||||
|
||||
private final String name;
|
||||
|
||||
private final long size;
|
||||
private final RandomAccessData data;
|
||||
|
||||
private boolean signed;
|
||||
|
||||
private List<JarEntryData> entries;
|
||||
private final List<JarEntryData> entries;
|
||||
|
||||
private SoftReference<Map<AsciiBytes, JarEntryData>> entriesByName;
|
||||
|
||||
private boolean signed;
|
||||
|
||||
private JarEntryData manifestEntry;
|
||||
|
||||
private SoftReference<Manifest> manifest;
|
||||
@ -108,18 +106,25 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
* @param rootFile the root jar file
|
||||
* @param name the name of this file
|
||||
* @param data the underlying data
|
||||
* @param filters an optional set of jar entry filters
|
||||
* @throws IOException
|
||||
*/
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data,
|
||||
JarEntryFilter... filters) throws IOException {
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data)
|
||||
throws IOException {
|
||||
super(rootFile.getFile());
|
||||
CentralDirectoryEndRecord endRecord = new CentralDirectoryEndRecord(data);
|
||||
this.data = getArchiveData(endRecord, data);
|
||||
this.rootFile = rootFile;
|
||||
this.name = name;
|
||||
this.size = data.getSize();
|
||||
loadJarEntries(endRecord, filters);
|
||||
this.data = getArchiveData(endRecord, data);
|
||||
this.entries = loadJarEntries(endRecord);
|
||||
}
|
||||
|
||||
private JarFile(RandomAccessDataFile rootFile, String name, RandomAccessData data,
|
||||
List<JarEntryData> entries, JarEntryFilter... filters) throws IOException {
|
||||
super(rootFile.getFile());
|
||||
this.rootFile = rootFile;
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
this.entries = filterEntries(entries, filters);
|
||||
}
|
||||
|
||||
private RandomAccessData getArchiveData(CentralDirectoryEndRecord endRecord,
|
||||
@ -131,35 +136,47 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
return data.getSubsection(offset, data.getSize() - offset);
|
||||
}
|
||||
|
||||
private void loadJarEntries(CentralDirectoryEndRecord endRecord,
|
||||
JarEntryFilter[] filters) throws IOException {
|
||||
private List<JarEntryData> loadJarEntries(CentralDirectoryEndRecord endRecord)
|
||||
throws IOException {
|
||||
RandomAccessData centralDirectory = endRecord.getCentralDirectory(this.data);
|
||||
int numberOfRecords = endRecord.getNumberOfRecords();
|
||||
this.entries = new ArrayList<JarEntryData>(numberOfRecords);
|
||||
List<JarEntryData> entries = new ArrayList<JarEntryData>(numberOfRecords);
|
||||
InputStream inputStream = centralDirectory.getInputStream(ResourceAccess.ONCE);
|
||||
try {
|
||||
JarEntryData entry = JarEntryData.fromInputStream(this, inputStream);
|
||||
while (entry != null) {
|
||||
addJarEntry(entry, filters);
|
||||
entries.add(entry);
|
||||
processEntry(entry);
|
||||
entry = JarEntryData.fromInputStream(this, inputStream);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
inputStream.close();
|
||||
}
|
||||
return entries;
|
||||
}
|
||||
|
||||
private void addJarEntry(JarEntryData entry, JarEntryFilter[] filters) {
|
||||
AsciiBytes name = entry.getName();
|
||||
for (JarEntryFilter filter : filters) {
|
||||
name = (filter == null || name == null ? name : filter.apply(name, entry));
|
||||
}
|
||||
if (name != null) {
|
||||
entry.setName(name);
|
||||
this.entries.add(entry);
|
||||
if (name.startsWith(META_INF)) {
|
||||
processMetaInfEntry(name, entry);
|
||||
private List<JarEntryData> filterEntries(List<JarEntryData> entries,
|
||||
JarEntryFilter[] filters) {
|
||||
List<JarEntryData> filteredEntries = new ArrayList<JarEntryData>(entries.size());
|
||||
for (JarEntryData entry : entries) {
|
||||
AsciiBytes name = entry.getName();
|
||||
for (JarEntryFilter filter : filters) {
|
||||
name = (filter == null || name == null ? name : filter.apply(name, entry));
|
||||
}
|
||||
if (name != null) {
|
||||
JarEntryData filteredCopy = entry.createFilteredCopy(this, name);
|
||||
filteredEntries.add(filteredCopy);
|
||||
processEntry(filteredCopy);
|
||||
}
|
||||
}
|
||||
return filteredEntries;
|
||||
}
|
||||
|
||||
private void processEntry(JarEntryData entry) {
|
||||
AsciiBytes name = entry.getName();
|
||||
if (name.startsWith(META_INF)) {
|
||||
processMetaInfEntry(name, entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -322,8 +339,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
private JarFile getNestedJarFileFromDirectoryEntry(JarEntryData sourceEntry)
|
||||
throws IOException {
|
||||
final AsciiBytes sourceName = sourceEntry.getName();
|
||||
JarEntryFilter[] filtersToUse = new JarEntryFilter[1];
|
||||
filtersToUse[0] = new JarEntryFilter() {
|
||||
JarEntryFilter filter = new JarEntryFilter() {
|
||||
@Override
|
||||
public AsciiBytes apply(AsciiBytes name, JarEntryData entryData) {
|
||||
if (name.startsWith(sourceName) && !name.equals(sourceName)) {
|
||||
@ -334,7 +350,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
};
|
||||
return new JarFile(this.rootFile, getName() + "!/"
|
||||
+ sourceEntry.getName().substring(0, sourceName.length() - 1), this.data,
|
||||
filtersToUse);
|
||||
this.entries, filter);
|
||||
}
|
||||
|
||||
private JarFile getNestedJarFileFromFileEntry(JarEntryData sourceEntry)
|
||||
@ -355,7 +371,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
*/
|
||||
public synchronized JarFile getFilteredJarFile(JarEntryFilter... filters)
|
||||
throws IOException {
|
||||
return new JarFile(this.rootFile, getName(), this.data, filters);
|
||||
return new JarFile(this.rootFile, getName(), this.data, this.entries, filters);
|
||||
}
|
||||
|
||||
private JarEntry getContainedEntry(ZipEntry zipEntry) throws IOException {
|
||||
@ -368,7 +384,7 @@ public class JarFile extends java.util.jar.JarFile implements Iterable<JarEntryD
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return (int) this.size;
|
||||
return (int) this.data.getSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
Loading…
Reference in New Issue
Block a user