-
Notifications
You must be signed in to change notification settings - Fork 291
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix dependency resolution for nested JARs (with fix for Spring Boot) #6720
Changes from all commits
cd45726
64bfa8e
cf34c8b
6c58278
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package datadog.telemetry.dependency; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.InputStream; | ||
import java.nio.file.NoSuchFileException; | ||
import java.util.Enumeration; | ||
import java.util.HashMap; | ||
import java.util.Map; | ||
import java.util.Properties; | ||
import java.util.jar.Attributes; | ||
import java.util.jar.JarFile; | ||
import java.util.jar.JarInputStream; | ||
import java.util.jar.Manifest; | ||
import java.util.zip.ZipEntry; | ||
|
||
class JarReader { | ||
static class Extracted { | ||
final String jarName; | ||
final Map<String, Properties> pomProperties; | ||
final Attributes manifest; | ||
|
||
public Extracted( | ||
final String jarName, | ||
final Map<String, Properties> pomProperties, | ||
final Attributes manifest) { | ||
this.jarName = jarName; | ||
this.pomProperties = pomProperties; | ||
this.manifest = manifest; | ||
} | ||
} | ||
|
||
public static Extracted readJarFile(String jarPath) throws IOException { | ||
try (final JarFile jar = new JarFile(jarPath, false /* no verify */)) { | ||
final Map<String, Properties> pomProperties = new HashMap<>(); | ||
final Enumeration<? extends ZipEntry> entries = jar.entries(); | ||
while (entries.hasMoreElements()) { | ||
final ZipEntry entry = entries.nextElement(); | ||
if (entry.getName().endsWith("pom.properties")) { | ||
try (final InputStream is = jar.getInputStream(entry)) { | ||
final Properties properties = new Properties(); | ||
properties.load(is); | ||
pomProperties.put(entry.getName(), properties); | ||
} | ||
} | ||
} | ||
final Manifest manifest = jar.getManifest(); | ||
final Attributes attributes = | ||
(manifest == null) ? new Attributes() : manifest.getMainAttributes(); | ||
return new Extracted(new File(jar.getName()).getName(), pomProperties, attributes); | ||
} | ||
} | ||
|
||
public static Extracted readNestedJarFile(final String jarPath) throws IOException { | ||
final int sepIdx = jarPath.indexOf("!/"); | ||
if (sepIdx == -1) { | ||
throw new IllegalArgumentException("Invalid nested jar path: " + jarPath); | ||
} | ||
final String outerJarPath = jarPath.substring(0, sepIdx); | ||
String innerJarPath = jarPath.substring(sepIdx + 2); | ||
if (innerJarPath.endsWith("!/")) { | ||
innerJarPath = innerJarPath.substring(0, innerJarPath.length() - 2); | ||
} | ||
try (final JarFile outerJar = new JarFile(outerJarPath, false /* no verify */)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Out of curiosity, but is it a thing to have more levels of nested jars? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I have seen at least 1 user report at Spring Boot asking about a third level of nesting, but Spring Boot does not support that. It would definitely be possible to do it with a custom Also note that, while it should be relatively easy to add support for an arbitrary nesting depth, we would always set a limit to nesting for performance reasons since each additional level of nesting needs to decompress a stream. |
||
final ZipEntry entry = outerJar.getEntry(innerJarPath); | ||
if (entry == null) { | ||
throw new NoSuchFileException("Nested jar not found: " + jarPath); | ||
} | ||
try (final InputStream is = outerJar.getInputStream(entry); | ||
final JarInputStream innerJar = new JarInputStream(is, false /* no verify */)) { | ||
final Map<String, Properties> pomProperties = new HashMap<>(); | ||
ZipEntry innerEntry; | ||
while ((innerEntry = innerJar.getNextEntry()) != null) { | ||
if (innerEntry.getName().endsWith("pom.properties")) { | ||
final Properties properties = new Properties(); | ||
properties.load(innerJar); | ||
pomProperties.put(innerEntry.getName(), properties); | ||
} | ||
} | ||
final Manifest manifest = innerJar.getManifest(); | ||
final Attributes attributes = | ||
(manifest == null) ? new Attributes() : manifest.getMainAttributes(); | ||
return new Extracted(new File(innerJarPath).getName(), pomProperties, attributes); | ||
} | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the reason of doing it like this instead of:
I think this part is not covered by any test 😢
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The background story here is tricky, so I'm not touching this logic until I can test it properly. We'll probably require Windows tests for it. See #4820