Skip to content

Commit

Permalink
Improve in-memory support for multi-release jars.
Browse files Browse the repository at this point in the history
  • Loading branch information
raphw committed Sep 24, 2024
1 parent 2603c3d commit 717fa70
Showing 1 changed file with 107 additions and 65 deletions.
172 changes: 107 additions & 65 deletions byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java
Original file line number Diff line number Diff line change
Expand Up @@ -3324,6 +3324,104 @@ interface Sink extends Closeable {
*/
void retain(Source.Element element) throws IOException;

/**
* A sink that stores resulting classes in memory.
*/
class InMemory implements Sink {

/**
* The class file version to consider as the maximum version when accepting
* multi-release classes or {@code null} if multi-release versions should
* be discarded.
*/
@MaybeNull
private final ClassFileVersion classFileVersion;

/**
* The map for storing all elements being received.
*/
private final Map<String, byte[]> storage;

/**
* A map of type names to the latest observed version if a multi-release version was reported.
*/
private final Map<String, Integer> versions;

/**
* Creates an in-memory sink.
*
* @param classFileVersion The class file version to consider as the maximum version when accepting
* multi-release classes or {@code null} if multi-release versions should
* be discarded.
* @param storage The map for storing all elements being received.
*/
public InMemory(@MaybeNull ClassFileVersion classFileVersion, Map<String, byte[]> storage) {
this.classFileVersion = classFileVersion;
this.storage = storage;
versions = new HashMap<String, Integer>();
}

/**
* {@inheritDoc}
*/
public void store(Map<TypeDescription, byte[]> binaryRepresentations) {
for (Map.Entry<TypeDescription, byte[]> entry : binaryRepresentations.entrySet()) {
String name = entry.getKey().getInternalName() + CLASS_FILE_EXTENSION;
if (!storage.containsKey(name)) {
storage.put(name, entry.getValue());
}
}
}

/**
* {@inheritDoc}
*/
public void store(int version, Map<TypeDescription, byte[]> binaryRepresentations) throws IOException {
if (classFileVersion != null && version <= classFileVersion.getJavaVersion()) {
for (Map.Entry<TypeDescription, byte[]> entry : binaryRepresentations.entrySet()) {
String name = entry.getKey().getInternalName() + CLASS_FILE_EXTENSION;
Integer current = versions.get(name);
if (current == null || current < version) {
versions.put(name, version);
storage.put(name, entry.getValue());
}
}
}
}

/**
* {@inheritDoc}
*/
public void retain(Source.Element element) throws IOException {
String name = element.getName();
if (!name.endsWith("/")) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
InputStream inputStream = element.getInputStream();
try {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
} finally {
inputStream.close();
}
} finally {
outputStream.close();
}
storage.put(element.getName(), outputStream.toByteArray());
}
}

/**
* {@inheritDoc}
*/
public void close() {
/* do nothing */
}
}

/**
* Implements a sink for a jar file.
*/
Expand Down Expand Up @@ -3444,18 +3542,23 @@ public void close() {
/**
* A sink that stores all elements in a memory map.
*/
class InMemory implements Target, Sink {
@HashCodeAndEqualsPlugin.Enhance
class InMemory implements Target {

/**
* The class file version to consider as the maximum version when accepting
* multi-release classes or {@code null} if multi-release versions should
* be discarded.
*/
@MaybeNull
@HashCodeAndEqualsPlugin.ValueHandling(HashCodeAndEqualsPlugin.ValueHandling.Sort.REVERSE_NULLABILITY)
private final ClassFileVersion classFileVersion;

/**
* The map for storing all elements being received.
*/
private final Map<String, byte[]> storage;

private final Map<String, Integer> versions;

/**
* Creates a new in-memory storage.
*/
Expand Down Expand Up @@ -3494,7 +3597,6 @@ public InMemory(Map<String, byte[]> storage) {
public InMemory(@MaybeNull ClassFileVersion classFileVersion, Map<String, byte[]> storage) {
this.classFileVersion = classFileVersion;
this.storage = storage;
versions = new HashMap<String, Integer>();
}

/**
Expand All @@ -3510,67 +3612,7 @@ public Sink write(@MaybeNull Manifest manifest) throws IOException {
}
storage.put(JarFile.MANIFEST_NAME, outputStream.toByteArray());
}
return this;
}

/**
* {@inheritDoc}
*/
public void store(Map<TypeDescription, byte[]> binaryRepresentations) {
for (Map.Entry<TypeDescription, byte[]> entry : binaryRepresentations.entrySet()) {
String name = entry.getKey().getInternalName() + CLASS_FILE_EXTENSION;
if (!storage.containsKey(name)) {
storage.put(name, entry.getValue());
}
}
}

/**
* {@inheritDoc}
*/
public void store(int version, Map<TypeDescription, byte[]> binaryRepresentations) throws IOException {
if (classFileVersion != null && version <= classFileVersion.getJavaVersion()) {
for (Map.Entry<TypeDescription, byte[]> entry : binaryRepresentations.entrySet()) {
String name = entry.getKey().getInternalName() + CLASS_FILE_EXTENSION;
Integer current = versions.get(name);
if (current == null || current < version) {
versions.put(name, version);
storage.put(name, entry.getValue());
}
}
}
}

/**
* {@inheritDoc}
*/
public void retain(Source.Element element) throws IOException {
String name = element.getName();
if (!name.endsWith("/")) {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
InputStream inputStream = element.getInputStream();
try {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, length);
}
} finally {
inputStream.close();
}
} finally {
outputStream.close();
}
storage.put(element.getName(), outputStream.toByteArray());
}
}

/**
* {@inheritDoc}
*/
public void close() {
/* do nothing */
return new Sink.InMemory(classFileVersion, storage);
}

/**
Expand Down

0 comments on commit 717fa70

Please sign in to comment.