Skip to content

Instantly share code, notes, and snippets.

@rmannibucau
Created December 12, 2022 08:34
Show Gist options
  • Save rmannibucau/ced8a809672a12a6f026e5ccac58a679 to your computer and use it in GitHub Desktop.
Save rmannibucau/ced8a809672a12a6f026e5ccac58a679 to your computer and use it in GitHub Desktop.
diff --git a/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java b/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java
index 7651ac3b..33a7b840 100644
--- a/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java
+++ b/xbean-finder/src/main/java/org/apache/xbean/finder/archive/JarArchive.java
@@ -16,6 +16,7 @@
*/
package org.apache.xbean.finder.archive;
+import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@@ -42,20 +43,52 @@ public class JarArchive implements Archive, AutoCloseable {
private final MJarSupport mjar = new MJarSupport();
public JarArchive(ClassLoader loader, URL url) {
-// if (!"jar".equals(url.getProtocol())) throw new IllegalArgumentException("not a jar url: " + url);
-
try {
this.loader = loader;
this.url = url;
- URL u = url;
- String jarPath = url.getFile();
- if (jarPath.contains("!")) {
- jarPath = jarPath.substring(0, jarPath.indexOf("!"));
- u = new URL(jarPath);
+ String filePath = null;
+ switch (url.getProtocol()) {
+ case "jar": // if there is the resource marker, extract actual path
+ String jarPath = url.getFile();
+ if (jarPath.startsWith("file:")) {
+ jarPath = jarPath.substring("file:".length());
+ }
+ jarPath = FileArchive.decode(jarPath);
+
+ int resourceSep = jarPath.indexOf("!/");
+ if (resourceSep > 0) {
+ String substring = jarPath;
+ while (resourceSep > 0) {
+ substring = jarPath.substring(0, resourceSep);
+ if (new File(substring).exists()) {
+ break;
+ }
+ resourceSep = jarPath.indexOf("!/", resourceSep + 2);
+ }
+ if (!new File(substring).exists()) {
+ // unlikely but full path can be right, tested after cause unlikely
+ filePath = FileArchive.decode(FileArchive.decode(jarPath));
+ if (!new File(filePath).exists()) {
+ throw new IllegalStateException("Can't find a file in '" + url + "' URL.");
+ }
+ } else {
+ filePath = substring;
+ }
+ } else {
+ filePath = jarPath;
+ }
+ break;
+ case "file":
+ filePath = FileArchive.decode(url.getFile());
+ break;
+ default:
+ throw new IllegalStateException(
+ "Not a supported protocol: '" + url.getProtocol() + "' in '" + url + "'");
}
- jar = new JarFile(FileArchive.decode(u.getFile())); // no more an url
- } catch (IOException e) {
+
+ jar = new JarFile(filePath);
+ } catch (final IOException e) {
throw new IllegalStateException(e);
}
}
diff --git a/xbean-finder/src/test/java/org/apache/xbean/finder/archive/Archives.java b/xbean-finder/src/test/java/org/apache/xbean/finder/archive/Archives.java
index 470db26c..affa3ca9 100644
--- a/xbean-finder/src/test/java/org/apache/xbean/finder/archive/Archives.java
+++ b/xbean-finder/src/test/java/org/apache/xbean/finder/archive/Archives.java
@@ -115,6 +115,22 @@ public class Archives {
// Create the ZIP file
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(classpath)));
+ putClasses(loader, out, classes);
+
+ for (Map.Entry<String, String> entry : entries.entrySet()) {
+
+ out.putNextEntry(new ZipEntry(entry.getKey()));
+
+ out.write(entry.getValue().getBytes());
+ }
+
+ // Complete the ZIP file
+ out.close();
+ return classpath;
+ }
+
+ public static void putClasses(final ClassLoader loader, final ZipOutputStream out,
+ final Class<?>[] classes) throws IOException {
for (Class clazz : classes) {
String name = clazz.getName().replace('.', '/') + ".class";
@@ -134,16 +150,5 @@ public class Archives {
// Complete the entry
out.closeEntry();
}
-
- for (Map.Entry<String, String> entry : entries.entrySet()) {
-
- out.putNextEntry(new ZipEntry(entry.getKey()));
-
- out.write(entry.getValue().getBytes());
- }
-
- // Complete the ZIP file
- out.close();
- return classpath;
}
}
diff --git a/xbean-finder/src/test/java/org/apache/xbean/finder/archive/JarArchiveTest.java b/xbean-finder/src/test/java/org/apache/xbean/finder/archive/JarArchiveTest.java
index a4ae0918..8f497fb3 100644
--- a/xbean-finder/src/test/java/org/apache/xbean/finder/archive/JarArchiveTest.java
+++ b/xbean-finder/src/test/java/org/apache/xbean/finder/archive/JarArchiveTest.java
@@ -21,19 +21,27 @@ import org.acme.foo.Green;
import org.acme.foo.Red;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
import java.io.File;
import java.net.URL;
import java.net.URLClassLoader;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Files;
import java.util.ArrayList;
import java.util.List;
+import java.util.jar.JarEntry;
+import java.util.jar.JarOutputStream;
+import static java.util.Collections.singletonList;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertNotNull;
import static junit.framework.Assert.assertTrue;
import static junit.framework.Assert.fail;
+import static org.apache.xbean.finder.archive.Archives.putClasses;
/**
* @version $Rev$ $Date$
@@ -44,6 +52,9 @@ public class JarArchiveTest {
private static File classpath;
private JarArchive archive;
+ @Rule
+ public final TemporaryFolder tmp = new TemporaryFolder();
+
@BeforeClass
public static void classSetUp() throws Exception {
@@ -90,10 +101,7 @@ public class JarArchiveTest {
@Test
public void testIterator() throws Exception {
- List<String> actual = new ArrayList<String>();
- for (Archive.Entry entry : archive) {
- actual.add(entry.getName());
- }
+ List<String> actual = list(archive);
assertFalse(0 == actual.size());
@@ -104,5 +112,74 @@ public class JarArchiveTest {
assertEquals(classes.length, actual.size());
}
+ private List<String> list(final JarArchive archive) {
+ final List<String> actual = new ArrayList<>();
+ for (final Archive.Entry entry : archive) {
+ actual.add(entry.getName());
+ }
+ return actual;
+ }
+
+ @Test
+ public void exclamationMarkInFilename() throws Exception {
+ createAndAssertBlueArchive(tmp.newFile("foo!bar.jar"));
+ }
+
+ @Test
+ public void exclamationMarkAsResourceSep() throws Exception {
+ createAndAssertBlueArchive(new File(tmp.newFolder("foo!"), "the-file.jar"));
+ }
+
+ @Test
+ public void exclamationMarkInFilePath() throws Exception {
+ createAndAssertBlueArchive(new File(tmp.newFolder("foo!bar"), "the-file.jar"));
+ }
+ @Test
+ public void exclamationMarkInResource() throws Exception {
+ final File file = tmp.newFile("file.jar");
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ try (final JarOutputStream out = new JarOutputStream(Files.newOutputStream(file.toPath()))) {
+ putClasses(loader, out, new Class<?>[]{Blue.class});
+ out.putNextEntry(new JarEntry("foo!/bar.marker"));
+ out.write("Just a marker to find the file for ex".getBytes(StandardCharsets.UTF_8));
+ out.closeEntry();
+ }
+
+ try (
+ final URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{file.toURI().toURL()});
+ final JarArchive jar = new JarArchive(
+ loader, urlClassLoader.getResource("foo!/bar.marker"))) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ }
+
+ private void createAndAssertBlueArchive(final File file) throws Exception {
+ final ClassLoader loader = Thread.currentThread().getContextClassLoader();
+ try (final JarOutputStream out = new JarOutputStream(Files.newOutputStream(file.toPath()))) {
+ putClasses(loader, out, new Class<?>[]{Blue.class});
+ }
+
+ final URL url = file.toURI().toURL();
+ // file:...
+ try (final JarArchive jar = new JarArchive(loader, url)) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ // file:... with marker with exclamation mark - this one is highly unlikely
+ try (final JarArchive jar = new JarArchive(loader, url)) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ // no resource
+ try (final JarArchive jar = new JarArchive(loader, new URL("jar", null, -1, url.toExternalForm()))) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ // resource
+ try (final JarArchive jar = new JarArchive(loader, new URL("jar", null, -1, url.toExternalForm() + "!/whatever"))) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ // resource with exclamation mark
+ try (final JarArchive jar = new JarArchive(loader, new URL("jar", null, -1, url.toExternalForm() + "!/whatever/is!/the!/marker"))) {
+ assertEquals(singletonList("org.acme.foo.Blue"), list(jar));
+ }
+ }
}
\ No newline at end of file
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment