From 717fa70c890bf85c2291bec25c8fc9585d618363 Mon Sep 17 00:00:00 2001 From: Rafael Winterhalter Date: Wed, 25 Sep 2024 00:17:32 +0200 Subject: [PATCH] Improve in-memory support for multi-release jars. --- .../main/java/net/bytebuddy/build/Plugin.java | 172 +++++++++++------- 1 file changed, 107 insertions(+), 65 deletions(-) diff --git a/byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java b/byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java index 9554984ebe..f32fb4fe9f 100644 --- a/byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java +++ b/byte-buddy-dep/src/main/java/net/bytebuddy/build/Plugin.java @@ -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 storage; + + /** + * A map of type names to the latest observed version if a multi-release version was reported. + */ + private final Map 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 storage) { + this.classFileVersion = classFileVersion; + this.storage = storage; + versions = new HashMap(); + } + + /** + * {@inheritDoc} + */ + public void store(Map binaryRepresentations) { + for (Map.Entry 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 binaryRepresentations) throws IOException { + if (classFileVersion != null && version <= classFileVersion.getJavaVersion()) { + for (Map.Entry 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. */ @@ -3444,9 +3542,16 @@ 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; /** @@ -3454,8 +3559,6 @@ class InMemory implements Target, Sink { */ private final Map storage; - private final Map versions; - /** * Creates a new in-memory storage. */ @@ -3494,7 +3597,6 @@ public InMemory(Map storage) { public InMemory(@MaybeNull ClassFileVersion classFileVersion, Map storage) { this.classFileVersion = classFileVersion; this.storage = storage; - versions = new HashMap(); } /** @@ -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 binaryRepresentations) { - for (Map.Entry 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 binaryRepresentations) throws IOException { - if (classFileVersion != null && version <= classFileVersion.getJavaVersion()) { - for (Map.Entry 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); } /**