Skip to content

Commit

Permalink
Final fixes for #673
Browse files Browse the repository at this point in the history
  • Loading branch information
lukehutch committed Apr 15, 2022
1 parent addb1d5 commit ca61ef4
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 65 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@

/** A directory classpath element, using the {@link File} API. */
class ClasspathElementFileDir extends ClasspathElement {
// TODO: this class is no longer used, in favor of ClasspathElementPathDir

/** The directory at the root of the classpath element. */
private final File classpathEltDir;

Expand Down
91 changes: 51 additions & 40 deletions src/main/java/io/github/classgraph/Scanner.java
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ public ClasspathEntryWorkUnit(final Object classpathEntryObj, final ClassLoader
classpathEntryObjToClasspathEntrySingletonMap = //
new SingletonMap<Object, ClasspathElement, IOException>() {
@Override
public ClasspathElement newInstance(final Object classpathEntryObj, final LogNode log)
public ClasspathElement newInstance(final Object key, final LogNode log)
throws IOException, InterruptedException {
// Each use of this map provides a NewInstanceFactory
throw new IOException("This method should not be called");
Expand All @@ -398,42 +398,58 @@ public ClasspathElement newInstance(final ClasspathEntryWorkUnit classpathEntryW
throw new IOException("Got null classpath entry object");
}

// Convert URL/URI into String, to handle some normalization.
// Paths.get fails with "IllegalArgumentException: URI is not hierarchical"
// for paths like "jar:file:myjar.jar!/" (#625) -- need to strip the "!/" off the end
// for paths like "jar:file:myjar.jar!/" (#625) -- need to strip the "!/" off the end.
// Also strip any "jar:file:" or "file:" off the beginning.
// This normalizes "file:x.jar" and "x.jar" to the same string, for example.
if (classpathEntObj instanceof URL || classpathEntObj instanceof URI) {
final String classpathEntryStr = classpathEntObj.toString();
if (classpathEntryStr.endsWith("!/")) {
classpathEntObj = classpathEntryStr.substring(0, classpathEntryStr.length() - 2);
} else if (classpathEntryStr.endsWith("!")) {
classpathEntObj = classpathEntryStr.substring(0, classpathEntryStr.length() - 1);
}
classpathEntObj = FastPathResolver.resolve(classpathEntObj.toString());
}

// If classpath entry object is a URL-formatted string, convert to a URL instance
// If classpath entry object is a URL-formatted string, convert to (or back to) a URL instance.
if (classpathEntObj instanceof String) {
final String classpathEntryStr = (String) classpathEntObj;
if (JarUtils.URL_SCHEME_PATTERN.matcher(classpathEntryStr).matches()) {
String classpathEntStr = (String) classpathEntObj;
final boolean isURL = JarUtils.URL_SCHEME_PATTERN.matcher(classpathEntStr).matches();
final boolean isMultiSection = classpathEntStr.contains("!");
if (isURL || isMultiSection) {
// Convert back to URL (or URI) if this has a URL scheme or if this is a multi-section
// path (which needs the "jar:file:" scheme)
if (!isURL) {
// Add "file:" scheme if there is no scheme
classpathEntStr = "file:" + classpathEntStr;
}
if (isMultiSection) {
// Multi-section URL strings that do not already have a URL scheme need to
// have the "jar:file:" scheme
classpathEntStr = "jar:" + classpathEntStr;
// Also "jar:" URLs need at least one instance of "!/" -- if only "!" is used
// without a subsequent "/", replace it
classpathEntStr = classpathEntStr.replaceAll("!([^/])", "!/$1");
}
try {
classpathEntObj = new URL(classpathEntryStr);
// Convert classpath entry to (or back to) a URL.
classpathEntObj = new URL(classpathEntStr);
} catch (final MalformedURLException e) {
// Try creating URI if URL creation fails, in case there is a URI-only scheme
try {
classpathEntObj = new URI(classpathEntryStr);
classpathEntObj = new URI(classpathEntStr);
} catch (final URISyntaxException e1) {
throw new IOException("Malformed URI: " + classpathEntryStr + " : " + e1);
throw new IOException("Malformed URI: " + classpathEntObj + " : " + e1);
}
}
} else if (classpathEntryStr.contains("!")) {
} else {
// If this is not a URL with a non-"file:" scheme and is not a multi-section URL,
// try parsing the path string as a Path
try {
classpathEntObj = new URL("jar:file:" + classpathEntryStr);
} catch (final MalformedURLException e) {
try {
classpathEntObj = new URI(classpathEntryStr);
} catch (final URISyntaxException e1) {
throw new IOException("Malformed URI: " + classpathEntryStr + " : " + e1);
}
classpathEntObj = Paths.get(classpathEntStr);
} catch (final InvalidPathException e) {
throw new IOException("Malformed path: " + classpathEntObj + " : " + e);
}
}
}
// At this point, String is dealt with and String, URL, and URI classpath elements are all
// normalized together. classpathEntObj is either a URL, URI, or Path.

// Check type of classpath entry object
Path classpathEntryPath = null;
Expand All @@ -448,10 +464,9 @@ public ClasspathElement newInstance(final ClasspathEntryWorkUnit classpathEntryW
// Use toString() for the key so that URLs and URIs that resolve to the
// same resource will point to the same entry in the singleton map
classpathEntryURL.toString(), log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key,
final LogNode log) {
public ClasspathElement newInstance() {
return new ClasspathElementZip(classpathEntryURL,
classpathEntryWorkUnit, nestedJarHandler, scanSpec);
}
Expand Down Expand Up @@ -486,10 +501,9 @@ public ClasspathElement newInstance(final Object key,
// Use toString() for the key so that URLs and URIs that resolve to the
// same resource will point to the same entry in the singleton map
classpathEntryURL.toString(), log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key,
final LogNode log) {
public ClasspathElement newInstance() {
return new ClasspathElementZip(classpathEntryURL,
classpathEntryWorkUnit, nestedJarHandler, scanSpec);
}
Expand Down Expand Up @@ -533,10 +547,9 @@ public ClasspathElement newInstance(final Object key,
// Use toString() for the key so that URLs and URIs that resolve to the
// same resource will point to the same entry in the singleton map
classpathEntryURI.toString(), log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key,
final LogNode log) {
public ClasspathElement newInstance() {
return new ClasspathElementZip(classpathEntryURI,
classpathEntryWorkUnit, nestedJarHandler, scanSpec);
}
Expand Down Expand Up @@ -565,10 +578,9 @@ public ClasspathElement newInstance(final Object key,
try {
final Path path = classpathEntryPath;
return classpathEntryObjToClasspathEntrySingletonMap.get(classpathEntryPath, log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key,
final LogNode log) {
public ClasspathElement newInstance() {
return new ClasspathElementZip(path, classpathEntryWorkUnit,
nestedJarHandler, scanSpec);
}
Expand All @@ -588,10 +600,9 @@ public ClasspathElement newInstance(final Object key,
try {
final Path path = classpathEntryPath;
return classpathEntryObjToClasspathEntrySingletonMap.get(classpathEntryPath, log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key,
final LogNode log) {
public ClasspathElement newInstance() {
return new ClasspathElementPathDir(path, classpathEntryWorkUnit,
nestedJarHandler, scanSpec);
}
Expand Down Expand Up @@ -644,15 +655,15 @@ public ClasspathElement newInstance(final Object key,
try {
final boolean jar = isJar;
return classpathEntryObjToClasspathEntrySingletonMap.get(pathCanonicalized, log,
new NewInstanceFactory<Object, ClasspathElement>() {
new NewInstanceFactory<ClasspathElement>() {
@Override
public ClasspathElement newInstance(final Object key, final LogNode log) {
public ClasspathElement newInstance() {
// Instantiate a ClasspathElementZip or ClasspathElementDir singleton
// for the classpath element path
return jar
? new ClasspathElementZip(pathCanonicalized, classpathEntryWorkUnit,
nestedJarHandler, scanSpec)
: new ClasspathElementFileDir(fileCanonicalized,
: new ClasspathElementPathDir(pathCanonicalized,
classpathEntryWorkUnit, nestedJarHandler, scanSpec);
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,23 +166,17 @@ V get() throws InterruptedException {
/**
* Create a new instance.
*
* @param <K>
* The key type.
* @param <V>
* The instance type.
*/
@FunctionalInterface
public interface NewInstanceFactory<K, V> {
public interface NewInstanceFactory<V> {
/**
* Create a new instance.
*
* @param key
* The key.
* @param log
* The log.
* @return The new instance.
*/
public V newInstance(K key, LogNode log);
public V newInstance();
}

/**
Expand Down Expand Up @@ -215,7 +209,7 @@ public interface NewInstanceFactory<K, V> {
* @throws NewInstanceException
* if {@link #newInstance(Object, LogNode)} threw an exception.
*/
public V get(final K key, final LogNode log, final NewInstanceFactory<K, V> newInstanceFactory)
public V get(final K key, final LogNode log, final NewInstanceFactory<V> newInstanceFactory)
throws E, InterruptedException, NullSingletonException, NewInstanceException {
final SingletonHolder<V> singletonHolder = map.get(key);
@SuppressWarnings("null")
Expand All @@ -237,7 +231,7 @@ public V get(final K key, final LogNode log, final NewInstanceFactory<K, V> newI
// Create a new instance
if (newInstanceFactory != null) {
// Call NewInstanceFactory
instance = newInstanceFactory.newInstance(key, log);
instance = newInstanceFactory.newInstance();
} else {
// Call overridden newInstance method
instance = newInstance(key, log);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,6 @@

import static org.assertj.core.api.Assertions.assertThat;

import java.net.MalformedURLException;
import java.net.URL;

import org.junit.jupiter.api.Test;

import io.github.classgraph.ClassGraph;
Expand All @@ -50,19 +47,8 @@ public void issue46Test() {
final String jarPath = "jar:file://"
+ Issue46Test.class.getClassLoader().getResource("nested-jars-level1.zip").getPath()
+ "!level2.jar!level3.jar!classpath1/classpath2";
try (ScanResult scanResult = new ClassGraph().overrideClasspath(jarPath).enableClassInfo().verbose()
.scan()) {
try (ScanResult scanResult = new ClassGraph().overrideClasspath(jarPath).enableClassInfo().scan()) {
assertThat(scanResult.getAllClasses().getNames()).containsOnly("com.test.Test");
}
}
//
// public static void main(String[] args) throws MalformedURLException {
// final String jarPath = "jar:file:" +
// Issue46Test.class.getClassLoader().getResource("nested-jars-level1.zip").getPath()
// + "!/level2.jar!/level3.jar!/classpath1/classpath2";
// System.out.println(jarPath);
// URL u = new URL(jarPath);
// System.out.println(u);
// System.out.println(u.getPath());
// }
}

0 comments on commit ca61ef4

Please sign in to comment.