Git Product home page Git Product logo

classgraph's Introduction

ClassGraph

ClassGraph Logo       Duke Award logo     Google Open Source Peer Bonus logo

ClassGraph is an uber-fast parallelized classpath scanner and module scanner for Java, Scala, Kotlin and other JVM languages.

ClassGraph won a Duke's Choice Award (a recognition of the most useful and/or innovative software in the Java ecosystem) at Oracle Code One 2018, and a Google Open Source Peer Bonus award in 2022. Thanks to all the users who have reported bugs, requested features, offered suggestions, and submitted pull requests to help get ClassGraph to where it is today.

Platforms: Windows, Mac OS X, Linux, Android (build-time) Languages: Java, Scala, Kotlin, etc. JDK compatibility: 7, 8, 9+ (JPMS)
Build Status GitHub issues lgtm alerts lgtm code quality Codacy Badge
Dependencies: none Dependents GitHub stars chart
Maven Central Javadocs
Gitter chat
License: MIT

ClassGraph is stable and mature, and has a low bug report rate, despite being used by hundreds of projects.

ClassGraph vs. Java Introspection

ClassGraph has the ability to "invert" the Java class and/or reflection API, or has the ability to index classes and resources. For example, the Java class and reflection API can tell you the superclass of a given class, or the interfaces implemented by a given class, or can give you the list of annotations on a class; ClassGraph can find all classes that extend a given class (all subclasses of a given class), or all classes that implement a given interface, or all classes that are annotated with a given annotation. The Java API can load the content of a resource file with a specific path in a specific ClassLoader, but ClassGraph can find and load all resources in all classloaders with paths matching a given pattern.

Examples

The following code prints the name of all classes in the package com.xyz or its subpackages, anywhere on the classpath or module path, that are annotated with an annotation of the form @com.xyz.Route("/pages/home.html"), along with the annotation parameter value. This is accomplished without loading or initializing any of the scanned classes.

String pkg = "com.xyz";
String routeAnnotation = pkg + ".Route";
try (ScanResult scanResult =
        new ClassGraph()
            .verbose()               // Log to stderr
            .enableAllInfo()         // Scan classes, methods, fields, annotations
            .acceptPackages(pkg)     // Scan com.xyz and subpackages (omit to scan all packages)
            .scan()) {               // Start the scan
    for (ClassInfo routeClassInfo : scanResult.getClassesWithAnnotation(routeAnnotation)) {
        AnnotationInfo routeAnnotationInfo = routeClassInfo.getAnnotationInfo(routeAnnotation);
        List<AnnotationParameterValue> routeParamVals = routeAnnotationInfo.getParameterValues();
        // @com.xyz.Route has one required parameter
        String route = (String) routeParamVals.get(0).getValue();
        System.out.println(routeClassInfo.getName() + " is annotated with route " + route);
    }
}

The following code finds all JSON files in META-INF/config in all ClassLoaders or modules, and calls the method readJson(String path, String content) with the path and content of each file.

try (ScanResult scanResult = new ClassGraph().acceptPathsNonRecursive("META-INF/config").scan()) {
    scanResult.getResourcesWithExtension("json")
              .forEachByteArray((Resource res, byte[] content) -> {
                  readJson(res.getPath(), new String(content, StandardCharsets.UTF_8));
              });
}

See the code examples page for more examples of how to use the ClassGraph API.

Capabilities

ClassGraph provides a number of important capabilities to the JVM ecosystem:

  • ClassGraph has the ability to build a model in memory of the entire relatedness graph of all classes, annotations, interfaces, methods and fields that are visible to the JVM, and can even read type annotations. This graph of class metadata can be queried in a wide range of ways, enabling some degree of metaprogramming in JVM languages -- the ability to write code that analyzes or responds to the properties of other code.
  • ClassGraph reads the classfile bytecode format directly, so it can read all information about classes without loading or initializing them.
  • ClassGraph is fully compatible with the new JPMS module system (Project Jigsaw / JDK 9+), i.e. it can scan both the traditional classpath and the module path. However, the code is also fully backwards compatible with JDK 7 and JDK 8 (i.e. the code is compiled in Java 7 compatibility mode, and all interaction with the module system is implemented via reflection for backwards compatibility).
  • ClassGraph scans the classpath or module path using carefully optimized multithreaded code for the shortest possible scan times, and it runs as close as possible to I/O bandwidth limits, even on a fast SSD.
  • ClassGraph handles more classpath specification mechanisms found in the wild than any other classpath scanner, making code that depends upon ClassGraph maximally portable.
  • ClassGraph can scan the classpath and module path either at runtime or at build time (e.g. to implement annotation processing for Android).
  • ClassGraph can find classes that are duplicated or defined more than once in the classpath or module path, which can help find the cause of strange class resolution behaviors.
  • ClassGraph can create GraphViz visualizations of the class graph structure, which can help with code understanding: (click to enlarge; see graph legend here)

Class graph visualization

Downloading

Maven dependency

Replace X.Y.Z below with the latest release number. (Alternatively, you could use LATEST in place of X.Y.Z instead if you just want to grab the latest version -- although be aware that that may lead to non-reproducible builds, since the ClassGraph version number could increase at any time. You could use dependency locking to address this.)

<dependency>
    <groupId>io.github.classgraph</groupId>
    <artifactId>classgraph</artifactId>
    <version>X.Y.Z</version>
</dependency>

See instructions for use as a module.

Running on JDK 16+

The JDK team decided to start enforcing strong encapsulation in JDK 16+. That will means that by default, ClassGraph will not be able to find the classpath of your project, if all of the following are true:

  • You are running on JDK 16+
  • You are using a legacy classloader (rather than the module system)
  • Your classloader does not expose its classpath via a public field or method (i.e. the full classpath can only be determined by reflection of private fields or methods).

If your ClassGraph code works in JDK versions less than 16 but breaks in JDK 16+ (meaning that ClassGraph can no longer find your classes), you have probably run into this problem.

ClassGraph can use either of the following libraries to silently circumvent all of Java's security mechanisms (visibility/access checks, security manager restrictions, and strong encapsulation), in order to read the classpath from private fields and methods of classloaders.

  • Narcissus by Luke Hutchison (@lukehutch), author of ClassGraph
  • JVM-Driver by Roberto Gentili (@burningwave), author of Burningwave Core.

To clarify, you do only need to use Narcissus or JVM-driver if ClassGraph cannot find the classpath elements from your classloader, due to the enforcement of strong encapsulation, or if it is problematic that you are getting reflection access warnings on the console.

To use one of these libraries:

  • Upgrade ClassGraph to the latest version
  • Either:
    1. Add the Narcissus library to your project as an extra dependency (this includes a native library, and only Linux x86/x64, Windows x86/x64, and Mac OS X x64 are currently supported -- feel free to contribute native code builds for other platforms or architectures).
    2. Set ClassGraph.CIRCUMVENT_ENCAPSULATION = CircumventEncapsulationMethod.NARCISSUS; before interacting with ClassGraph in any other way (this will load the Narcissus library as ClassGraph's reflection driver).
  • Or:
    1. Add the JVM-Driver library to your project as an extra dependency (this uses only Java code and works to bypass encapsulation without native code for all JDK versions between 8 and 18).
    2. Set ClassGraph.CIRCUMVENT_ENCAPSULATION = CircumventEncapsulationMethod.JVM_DRIVER; before interacting with ClassGraph in any other way (this will load the JVM-Driver library as ClassGraph's reflection driver).

JDK 16's strong encapsulation is just the first step of trying to lock down Java's internals, so further restrictions are possible (e.g. it is likely that setAccessible(true) will fail in future JDK releases, even within a module, and probably the JNI API will be locked down soon, making Narcissus require a commandline flag to work). Therefore, please convince your upstream runtime environment maintainers to expose the full classpath from their classloader using a public method or field, otherwise ClassGraph may stop working for your runtime environment in the future.

Pre-built JARs

You can get pre-built JARs (usable on JRE 7 or newer) from Sonatype.

Building from source

ClassGraph must be built on JDK 8 or newer (due to the presence of @FunctionalInterface annotations on some interfaces), but is built using -target 1.7 for backwards compatibility with JRE 7.

The following commands will build the most recent version of ClassGraph from git master. The compiled package will then be in the "classgraph/target" directory.

git clone https://github.com/classgraph/classgraph.git
cd classgraph
export JAVA_HOME=/usr/java/default   # Or similar -- Maven needs JAVA_HOME
./mvnw -Dmaven.test.skip=true package

This will allow you to build a local SNAPSHOT jar in target/. Alternatively, use ./mvnw -Dmaven.test.skip=true install to build a SNAPSHOT jar and then copy it into your local repository, so that you can use it in your Maven projects. Note that may need to do ./mvnw dependency:resolve in your project if you overwrite an older snapshot with a newer one.

./mvnw -U updates from remote repositories an may overwrite your local artifact. But you can always change the artifactId or the groupId of your local ClassGraph build to place your local build artifact in another location within your local repository.

Documentation

See the wiki for complete documentation and usage information.

ClassGraph was known as FastClasspathScanner prior to version 4. See the porting notes for information on porting from the older FastClasspathScanner API.

Mailing List

  • Feel free to subscribe to the ClassGraph-Users email list for updates, or to ask questions.
  • There is also a Gitter room for discussion of ClassGraph.

Sponsorship

ClassGraph was written by Luke Hutchison (@LH on Twitter).

If ClassGraph is critical to your work, you can help fund further development through the GitHub Sponsors Program.

Acknowledgments

ClassGraph would not be possible without contributions from numerous users, including in the form of bug reports, feature requests, code contributions, and assistance with testing.

Alternatives

Some other classpath scanning mechanisms include:

License

The MIT License (MIT)

Copyright (c) 2022 Luke Hutchison

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

classgraph's People

Contributors

apxeolog-df avatar chrisr3 avatar dependabot[bot] avatar eduwei01 avatar fluxroot avatar freya022 avatar isopov avatar itmrat01 avatar jknack avatar jkschneider avatar johnou avatar larsgrefer avatar lukehutch avatar michael-simons avatar mmusenbr avatar pascalschumacher avatar pkesseli avatar raimondkempees avatar rbkcapdm avatar roxspring avatar seanf avatar sebthom avatar shamsasari avatar skahmann avatar stickycode avatar sullis avatar t101n avatar tagakov avatar twisterrob avatar vxmn avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

classgraph's Issues

Provide a way to pass blacklisted packages

I'm creating a framework that will need to scan through the users classes, which means that I cannot limit the scan to a specific package as it can be anything. This means that the library will also scan all my classes and dependencies which in my case is completely unnecessary and will only slow down startup time.

A simple solution would be to provide a list of packages to ignore the same way you can provide a list of packages to scan.

NullPointerException when scan reaches java.lang.object

Hi!

I'm trying to scan every class in the class path (empty constructor - I'm building a framework so I can't know package names to scan). However since I'm using IntelliJ IDEA for development and the it includes the JRE jars in the class path when running, I get a NullPointerException when the scan reaches java.lang.Object and tries to retrieve its parent class (as Object is the only one that does not have one).

Heres the exception:

Caused by: java.lang.NullPointerException
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.readClassInfoFromClassfileHeader(FastClasspathScanner.java:828)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.scanZipfile(FastClasspathScanner.java:1078)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.scan(FastClasspathScanner.java:1145)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.scan(FastClasspathScanner.java:1188)

I placed a breakpoint at the line the exception happened and read the className variable defined in line 818 of FastClasspathScanner.java which was java.lang.Object.

Of course when I package the app and run it from the terminal it works normally as the JRE jars are not explicitly included in the classpath. However it's still a problem since it makes development a bit problematic.

Ability to obtain class files as byte[]

I want to be able to access the class file byte arrays of certain classes on my classpath so that I can load them using sun.invoke.anon.AnonymousClassLoader. I really like the utility this classpath scanner provides and I can override the loadClass method, but there is no easy mechanism for obtaining the byte [] of my class. Is it possible to make scanZipfile a protected method so that I can override it's implementation to convert the input stream into a byte array before reading the contents?

path scanner fails on windows

root cause is nio.path issue on windows. Here is the Fix ClasspathFinder.java (line 75)

  •    pathElementStr = System.getProperty( "os.name" ).contains( "indow" ) ? pathElementStr.substring(1) : pathElementStr;
    

`getNamesOfClassesImplementing` fails if the interface is in different package.

Using 1.9.7

Assuming:

package a;
interface A {}


package b;
public class C extends A {}

And calling it with:

 new FastClasspathScanner("b").scan().getNamesOfClassesImplementing("a.A")

I would expect "b.C" to still be returned but it is not. A workaround is new FastClasspathScanner("b", "a"), but that feels clunky.

Basically I feel like the interface itself should not have to be in the list of packages scanned. I haven't looked at implementation details, so there may be a good reason for it.

ClassLoaderHandlers are not found when gradle + ant is used together

We have a gradle build which is using old ant tasks from our old build system (gradle has support for ant).

The next code snippet is problematic. No handler is found.

private static ServiceLoader<ClassLoaderHandler> classLoaderHandlerLoader = ServiceLoader
            .load(ClassLoaderHandler.class);

The root cause seems to be different class loader. ServiceLoader uses Thread.currentThread().getContextClassLoader()

It would be very useful to pass classloader as an parameter of FastClasspathScanner or get the classloader from caller.

Only plot class->interface link to highest implementing superclass

If B is a subclass of A, and A inherits some interface, the class graph will show both A and B implementing the interface. Should only show an arrow from A to the interface.

Also update the text below the example graph that says that a class and its subclass both implementing an interface indicates an issue. (Explicitly declaring a class and subclass extend the same interface is totally valid, but it's not useful to graph this, and once this is no longer shown, these explicit cases will no longer be shown anyway.)

Pass filesize into FileMatchProcessor

In case the entire file needs to be loaded into a byte[] array, FileMatchProcessor should add a fileSize argument (this breaks API). ZipEntry.getSize() and RandomAccessFile.getSize() can be used to get the file size.

Need to test whether Java method polymorphism can handle multiple different FunctionalInterfaces with Lambda expressions (maybe by arity matching?) -- if so, can keep API the same, and just add a new type of MatchProcessor that also takes a size argument.

doesn't find classes in jar file manifest's classpath

I've been using fast-classpath-scanner to locate classes in my classpath supporting a particular interface (allowing users to add functionality to my project). The classes would be found when the application was invoked like so:
java -cp base-application.jar:base-extension.jar:user-extension.jar MainClass

I've recently added a Class-Path line to base-application's manifest (adding base-extension.jar), meaning I should be able to execute the application like so:
java -cp user-extension.jar -jar base-application.jar

However, fast-classpath-scanner appears to no longer locate classes contained in the Class-Path attribute. The classes don't appear to be loaded at all. I've tested the old and the new version with verbose classloading enabled (both have the same classpath): http://pastebin.com/KS5kRqqr

FastClasspathScanner not finding classes under JBoss

Hi!

First, I'd like to thank you for your effort at making FastClasspathScanner. It's just great and just what I needed!

However, when I deploy my application under JBoss 4.2.3.GA, it doesn't seem to be able to find any of my classes. The execution of getNamesOfAllClasses returns:

[GetoptDemo, gnu.getopt.Getopt, gnu.getopt.LongOpt, javax.management.MBeanServer, javax.management.MBeanServerBuilder, org.jboss.Main, org.jboss.Main$1, org.jboss.Main$JarFilter, org.jboss.Version, org.jboss.system.JBossRMIClassLoader, org.jboss.system.ORBSingleton, org.jboss.system.server.NoAnnotationURLClassLoader, org.jboss.system.server.Server, org.jboss.system.server.ServerConfig, org.jboss.system.server.ServerConfigUtil, org.jboss.system.server.ServerLoader, org.jboss.system.server.jmx.LazyMBeanServer, org.jboss.system.server.jmx.MBeanServerBuilderImpl, org.omg.CORBA_2_3.ORB]

Using the verbose method, the classpath elements are these:

Classpath elements: [F:\jboss-4.2.3.GA\client\getopt.jar, F:\jboss-4.2.3.GA\bin\run.jar]

It doesn't use the jars inside my EAR.

I've read the documentation and tried some different constructors, but still no luck. It would be great if you could help me with this.

Best regards and thanks again!

Faliorn

Dalvik bytecode support

It is more an enhancement request, if possible to add Dalvik bytecode support. Perhaps it is already supported out of the box, otherwise it can be very useful.

Can't get black list to work

Version 1.9.1:

Using the following code I get no classes reported (even though there are plenty of candidates on the classpath):

 FastClasspathScanner scanner = new FastClasspathScanner("-java");
 scanner.scan();
 System.out.println(scanner.getNamesOfAllClasses());

I am trying to prevent the java runtime from being scanned as this seems to take a long time and I don't need it.

In fact any kind of blacklist seems to result in no results.

dir scanning fails on windoze

solution

    private void scanDir(File dir, int ignorePrefixLen, boolean scanTimestampsOnly) throws IOException {
        String absolutePath = dir.getPath();
        String relativePath = ignorePrefixLen > absolutePath.length() ? "" : absolutePath.substring(ignorePrefixLen);
        relativePath = relativePath.replace(File.separatorChar,'/'); // <=== INSERTED

It seems that the API cannot work well in Eclipse PDE

Thank you for the API. When I used it in a main method, it worked well, but I cannot use it to access my Eclipse plug-in's packages when the plug-in running in an Eclipse PDE. May you tell me how to solve this problem, please?
The code is shown below
List classNames = new FastClasspathScanner(this.pakageName).verbose().scan().getNamesOfAllClasses();

List classNames = new FastClasspathScanner(this.pakageName).scan().getNamesOfAllClasses();

Disable Jar filters during development

What do you recommend as the best way to apply a jar: filter so that the same code also works in the IDE (where no jar exists). I'm sure you are aware of the current behaviour; the existence of jar:completely disables normal classpath scanning. This is understandable but do you see a non-DIY solution to complex cases where some internal modules are loaded as IDE projects (no jars) and some left to dependency resolution to download

new FastClasspathScanner("com.company.product","jar:com-company-module1.jar","jar:com-company-module2.jar"....)

Classpath Scanning in Spring Boot Jar Not Working

I have a custom annotation:

@Target(value=ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Pipeline  {
  String id ();
  String name ();
  boolean visible () default true;
  String role () default "USER";
}

Which I use on interfaces within a Spring Boot App with nested jars:

@Pipeline(id="my-pipeline", name="My Pipeline")
public interface Echo {
  ...
}

My project structure:

parent-boot-project
   |
   --- plugin1.jar 
   --- plugin2.jar <--- interfaces are here
   --- ...

Next, I use lukehutch's fast-classpath-scanner to scan for them:

new FastClasspathScanner(BASE_PACKAGE)
    .matchClassesWithAnnotation(PIPELINE_ANNOTATION, aProcessor)
    .verbose()
    .scan();

Works great on my IDE (eclipse) but not when I build the jar. Tried messing around with the classpath but to no avail. Anyone ran into something like that?

matchClassesWithAnnotation() does not match anything (1.9.11)

In 1.9.11, FastClasspathScanner.matchClassesWithAnnotation(Class<?>, ClassAnnotationMatchProcessor) does not seem to match anything anymore. This is probably caused by #30.

I have different usages of this method and all are fine in 1.9.9 but they fail to find anything with 1.9.11+:

  • finding interfaces annotated with javax.jws.WebService
  • finding concrete classes annotated with javax.persistence.Entity
  • finding concrete classes annotated with javax.xml.bind.annotation.XmlType
  • finding concrete classes annotated with org.apache.deltaspike.core.api.jmx.MBean

Because of #38 I cannot check whether this problem has been fixed already in 1.9.12+.

Handle split lines in manifest files

From (https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html)[https://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html]:

"No line may be longer than 72 bytes (not characters), in its UTF8-encoded form. If a value would make the initial line longer than this, it should be continued on extra lines (each starting with a single SPACE)."

e.g.:

Manifest-Version: 1.0
Implementation-Vendor: Bytedeco
Implementation-Title: JavaCPP Presets for ARToolKitPlus
Implementation-Version: 2.3.1-1.1
Built-By: root
Build-Jdk: 1.7.0_85
Class-Path: ./ javacpp.jar artoolkitplus-linux-arm.jar artoolkitplus-l
 inux-x86.jar artoolkitplus-linux-x86_64.jar artoolkitplus-macosx-x86.
 jar artoolkitplus-macosx-x86_64.jar artoolkitplus-windows-x86.jar art
 oolkitplus-windows-x86_64.jar javacpp-1.1.jar
Specification-Vendor: Bytedeco
Name: org/bytedeco/javacpp/presets/
Specification-Title: JavaCPP Presets for ARToolKitPlus
Created-By: Apache Maven 3.0.5
Specification-Version: 2.3.1-1.1
Archiver-Version: Plexus Archiver

Fix ScanSpec for whitelisted classes

Need an enum value for ScanSpecPathMatch that will continue recursing into the path of a whitelisted class that is not itself in a whitelisted package (so that whitelisted classes get scanned, even if their packages are not scanned). Need to also fix dir and zipfile scanning to work with this.

Reverse the direction of "has field of type" arrow

Arrow should point from classes of type X to other classes that have fields of type X, not from classes that have fields of type X to X. (Or at least the arrow direction needs to flip, so that the arrow points downwards, not upwards, i.e. the arrow direction should reverse and the arrowhead should be on the beginning of the line, not the end.)

If no annotations found scan throws NullPointerException

When using FastClasspathScanner.matchClassesWithAnnotation, if there are no annotations found then a NullPointerException is thrown inside the ClassMatcher class added, since classGraphBuilder.getClassesWithAnnotation() returns null rather than an empty list.

The fix is either to check if null returned, or to modify getClassesWithAnnotation to return an empty list by default.

getClassesImplementing has the same issue.

Version 1.90.7 is not compatible with Java 7

First off, thank you for a wonderful Java library. I have a project that was using Reflections, however it plus the size of the libraries it relies on was over 4 times the size of my project. Your library works and its tiny, and its fast. However, although the description of it says the released to Maven works with Java 7, the current version doesn't.
The issue is primarily the use of a couple of methods that were newly added to classes for Java 8. The use of putIfAbsent on the HashMap in ClassInfo,java is a problem. As is the use of String.join in ClassInfo.java. and the java.time classes in Log.java
The first issue can be handled by passing in a ConcurrentHashMap instead of a plain HashMap.
The java.time issue is more of a problem to fix, since the new Java 8 classes are Thread-safe whereas the java.text.SimpleDateFormat they replaced are very much not.

Possible InputStream leak

https://github.com/lukehutch/fast-classpath-scanner/blob/master/src/main/java/io/github/lukehutch/fastclasspathscanner/FastClasspathScanner.java#L1032
This method returns ArrayList, however I would prefer it returns just List or even Collection, to make it more portable when it is overridden.
I found opened input stream leak in my forked version and tried to switch to master branch to see if it is fixed, but I can't since certain methods signature was updated. If you fixed any open stream leak, please let me know..

publish to maven center

currently when I am writing a kryo serializer for akka-remote,I found that I really need something like this.
I want to auto register classes to the kryo.
I currently using something like this:
It not good but works.

 def subTypeof[T](clazz:Class[T],filter:String => Boolean):Set[Class[_]] = {
    val classPath = ClassPath.from(this.getClass.getClassLoader)
    val allClasses = classPath.getAllClasses
    implicit def imutableSet2ScalaSet[V](input:ImmutableSet[V]):Set[V] = {
      val itr = input.iterator()
      var set = Set.empty[V]
      while (itr.hasNext){
        set += itr.next()
      }
      set
    }
    allClasses.filter(classInfo => filter(classInfo.getName)).map(_.load()).filter(clazz.isAssignableFrom)
  }

I think your way or the classindex way will be nice https://github.com/atteo/classindex I will not going to use Reflections,so many addition dependencies.
so how about publish to the maven center?

java.lang.ClassCastException in Wildfly 10

environment: wildfly 10.0.0.CR2
Java 8
exception:

java.lang.ClassCastException: org.jboss.modules.ModuleClassLoader cannot be cast to java.net.URLClassLoader
    at io.github.lukehutch.fastclasspathscanner.scanner.ClasspathFinder.parseSystemClasspath(ClasspathFinder.java:282)
    at io.github.lukehutch.fastclasspathscanner.scanner.ClasspathFinder.getUniqueClasspathElements(ClasspathFinder.java:318)
    at io.github.lukehutch.fastclasspathscanner.scanner.RecursiveScanner.scan(RecursiveScanner.java:398)
    at io.github.lukehutch.fastclasspathscanner.scanner.RecursiveScanner.scan(RecursiveScanner.java:447)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.scan(FastClasspathScanner.java:1064)

my code

        new FastClasspathScanner()  
            .matchClassesWithAnnotation(Entity.class, new ClassAnnotationMatchProcessor() {
                @Override
                public void processMatch(Class<?> matchingClass) {
                    System.out.println("Annotation Entity: " + matchingClass);
                }
            })
            .verbose()
            .scan();        

Is there a way to disable all blacklisted packages and classes?

https://github.com/benas/random-beans allows you scan the classpath for concrete types if you like to generate random instances of beans with abstract field types. Sadly we are unable to upgrade to the latest version, because:

Caused by: java.lang.IllegalArgumentException: Can't scan for java.lang.Comparable, it is in a >blacklisted package. You can explicitly override this by naming the class in the scan spec when you call the FastClasspathScanner constructor.
at >io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.checkClassNameIsNotBlacklisted(FastClasspathScanner.java:278)

Is there a way to disable all blacklists?

Unable to find classes implementing chosen interface if implementing super class is not in a scanned package

The title might be slightly confusing, but this is how you can reproduce the issue:

  • Create interface Searched.
  • Add abstract class AbstractSearched implementing Searched.
  • Add class ConcreteSearched extending AbstractSearched.
  • Scan for classes implementing Searched. Class ConcreteSearched will be found.
  • Now move interface and abstract class to a different package, which is not included for the scanning.
  • Scan for classes implementing Searched in ConcreteSearched package. ConcreteSearched will not be found.
  • Make ConcreteSearched additionally implement Searched.
  • Scan for classes implementing Searched in ConcreteSearched package.ConcreteSearched will be found.

It would be nice if this worked for complex class hierarchies even if some base classes are in another package (think about third-party libraries), for example. Currently you have to "duplicate" the interface implementation, which - while not causing any errors - usually leads to compilation warnings.

No such method error in 1.9.20

I'm getting a NoSuchMethodError after updating to 1.9.20 on Java "1.8.0_91".

java.lang.NoSuchMethodError: io.github.lukehutch.fastclasspathscanner.classpath.ClasspathFinder.getUniqueClasspathElements()Ljava/util/ArrayList;

Fast path is a dependency of JBrowserDriver where i'm getting this issue. See: MachinePublishers/jBrowserDriver#137

Feature discussion: Provide current search context to matcher

Hi Luke,

we recently tried to migrate homegrown code for our component container to your tool - thank you for providing it!

The only issue we're encountering so far is the fact that we need the context from where the match is encountered, because this "plugin" serves as another container for a new private classpath context. From here the plugin may lookup local content.

Currently this is not possible as we do not have the context in the match processor.

Do you think this might be a useful extension that could make it to the public API?

Greetings, Michael

Wildcard support in jar filters

Since I know my annotations exist only our in-house jars, I could benefit from saying:

new FastClasspathScanner("org.company.product", "jar:org-company-product-*").scan()

Whitelist doesn't work as expected

List<String> found = new FastClasspathScanner("factories").scan().getNamesOfClassesImplementing("factoryduke.Factory")

i'm getting

java.lang.IllegalArgumentException: Can't scan for factoryduke.Factory, it is in a package that is either blacklisted or not whitelisted
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.checkClassNameIsInWhitelistedPackage(FastClasspathScanner.java:216)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.annotationName(FastClasspathScanner.java:227)
    at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.getNamesOfClassesWithAnnotation(FastClasspathScanner.java:823)

without the package everything is working

List<String> found = new FastClasspathScanner().scan().getNamesOfClassesImplementing("factoryduke.Factory")

It seems the detection of the whitelist doesnt work well

private static boolean isWhitelisted(final String str, final ArrayList<String> whitelist,
            final ArrayList<String> blacklist) {
        boolean isWhitelisted = false;
        for (final String whitelistPrefix : whitelist) {
            if (str.startsWith(whitelistPrefix)) {
                isWhitelisted = true;
                break;
            }
        }
        boolean isBlacklisted = false;
        for (final String blacklistPrefix : blacklist) {
            if (str.startsWith(blacklistPrefix)) {
                isBlacklisted = true;
                break;
            }
        }
        return isWhitelisted && !isBlacklisted;
    }

cloud not using in scala

I am trying to using it in scala.but it could not found any subclass

scanner.matchSubclassesOf(classOf[AbstractEngine],new SubclassMatchProcessor[AbstractEngine] {
  override def processMatch(matchingClass: Class[_ <: AbstractEngine]): Unit = {
    println(matchingClass)
  }
}).scan()

I have wrote a java class with static method to invoke the scanner

public class ClassScanner {
    public static void findSubClass () {
        FastClasspathScanner scanner = new FastClasspathScanner(new String[]{"qgame"})
                .matchSubclassesOf(AbstractEngine.class, System.out::println);
        scanner.scan();
    }
}

still nothing ,anything wrong?

add override method which don't try to load the class in the FastClasspathScanner

like this

    public FastClasspathScanner matchClassesWithAnnotation(final Class<?> annotation,
            final ClassAnnotationMatchProcessor classAnnotationMatchProcessor) {
        if (!annotation.isAnnotation()) {
            throw new IllegalArgumentException("Class " + annotation.getName() + " is not an annotation");
        }
        classMatchers.add(new ClassMatcher() {
            @Override
            public void lookForMatches() {
                // For all classes with the given annotation
                for (String classWithAnnotation : classGraphBuilder.getClassesWithAnnotation(annotation.getName())) {
                    try {
                        // Load class
                        Class<?> klass = Class.forName(classWithAnnotation);

                        // Process match
                        classAnnotationMatchProcessor.processMatch(klass);

                    } catch (ClassNotFoundException | NoClassDefFoundError e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        });
        return this;
    }

for the line here

                        // Load class
                        Class<?> klass = Class.forName(classWithAnnotation);

we may provide a new type of processor with just accept string.

with this,we may don't need to provide method which allow us to specify the classloader.

Support for running under mvn jetty:run

Hi Luke,

Sadly I've reverted our (Apache Isis') dependency on your library, because if I run our webapp using mvn jetty:run then the classpath system property will not be populated. Since that's a use case we need to support, it's a bit of a showstopper.

I did a bit of playing around to see if there was another way to determine the directories/JARs to search through (eg ClassLoader.getSystemClassLoader()) but without success. In any case, getting into the whole classloader thing w.r.t. servlet containers is not something I want to get into without a bit of care.

So this ticket is a request to see if FCS can be made to run under mvn jetty:run (and also mvn antrun:run that we use to run our app via a standalone main() bootstrap method).

Thx
Dan

Alternative to services based class loader discovery

Hi,

Great project, thanks for the hard work!

@johnou and I were trying to integrate with the Orbit project (https://github.com/orbit/orbit) to replace our usage of Guava.

Unfortunately, the services based discovery of the class loaders in ClasspathFinder doesn't play nicely when the project is shaded as the package names are then incorrect. This is particularly a problem during a maven build.

It would be really nice if there was a way to specify the loaders manually for situations where the services based discovery doesn't work. If we could do this when creating the FastClasspathScanner the shading would take effect correctly and everything would work.

I'm happy to look into making the change myself, but wanted to run it by you before I started.

Thanks,
Joe

Cannot just gather all interfaces in a package

Imagine you have a package with only interfaces.

Now try to find all these interfaces with FastClasspathScanner:

  • .getNamesOfAllClasses() after just .scan() without any Processors returns only classes, not interfaces
  • .matchSubclassesOf(Object.class, ...) + .scan() does not match anything
  • .matchSubinterfacesOf(Object.class, ...) / .matchClassesImplementing() + .scan() both yield an exception

.matchClassesWithAnnotation() does match the interfaces but my interfaces don't have an annotation.

Expectations:
As there is no .getNamesOfAllInterfaces(), I expect .getNamesOfAllClasses() to return the interface names (besides "regular" class names).
In the end I need the class objects of all interfaces, not the just the names. So for me the best would be if matchSubclassesOf(Object.class, ...) also matched interfaces. This would be consistent with Object.class.isAssignableFrom(MyInterface.class).

Include ivy dependencies in a sbt/scala project?

At the moment I'm using a copy/paste approach to get the classpath entries. Swapping to your library would ease development, but I miss some dependencies from a sbt/scala project in the classpath.

Example:

object ClassPathTest extends App {

  def urlses(cl: ClassLoader): Array[java.net.URL] = cl match {
    case null => Array()
    case u: java.net.URLClassLoader => u.getURLs() ++ urlses(cl.getParent)
    case _ => urlses(cl.getParent)
  }

  val  urls = urlses(getClass.getClassLoader)
  println(urls.mkString("\n"))

  println("")
  println("----------------------------------------")
  println("")

  val items = new ClasspathFinder().getUniqueClasspathElements();

  println(items)

prints

file:/Users/oliver/Projects/personal/fast-classpath/target/scala-2.11/classes/
file:/Users/oliver/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.8.jar
file:/Users/oliver/.ivy2/cache/com.google.code.gson/gson/jars/gson-2.4.jar
file:/Users/oliver/.ivy2/cache/io.github.lukehutch/fast-classpath-scanner/jars/fast-classpath-scanner-1.9.18.jar
file:/Users/oliver/.ivy2/cache/org.scala-lang/scala-library/jars/scala-library-2.11.8.jar
file:/Users/oliver/.ivy2/cache/org.scala-lang/scala-compiler/jars/scala-compiler-2.11.8.jar
file:/Users/oliver/.ivy2/cache/org.scala-lang/scala-reflect/jars/scala-reflect-2.11.8.jar
file:/Users/oliver/.ivy2/cache/org.scala-lang.modules/scala-xml_2.11/bundles/scala-xml_2.11-1.0.4.jar
file:/Users/oliver/.ivy2/cache/org.scala-lang.modules/scala-parser-combinators_2.11/bundles/scala-parser-combinators_2.11-1.0.4.jar
file:/Users/oliver/.ivy2/cache/jline/jline/jars/jline-2.12.1.jar
file:/usr/local/Cellar/sbt/0.13.11/libexec/sbt-launch.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/cldrdata.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/dnsns.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/jfxrt.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/localedata.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/nashorn.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/sunec.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/sunjce_provider.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/sunpkcs11.jar
file:/Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/ext/zipfs.jar
file:/System/Library/Java/Extensions/MRJToolkit.jar

----------------------------------------

[/usr/local/Cellar/sbt/0.13.11/libexec/sbt-launch.jar]

Is there a way to also print the ivy dependencies?

Add .matchFilePath and .matchFileLeafname

.matchFilenamePattern() requires a regular expression. Add .matchFilenamePath() that performs a (non-regexp) string match against a complete relative path, and .matchFilenameLeaf() that matches just the leaf of the path.

Expose nonblocking API that returns a Future from scan()

This will require some sort of ScanResult class so that Future can be returned. Then all the getClasses...() methods will defer to ScanResult.

Also, the work currently done on the main thread should be moved to a worker thread.

ClassCastException: AnnotationDAGNode cannot be cast to InterfaceDAGNode

This is a regression since 1.9.12, probably caused by #30:

java.lang.ClassCastException: io.github.lukehutch.fastclasspathscanner.classgraph.AnnotationDAGNode cannot be cast to io.github.lukehutch.fastclasspathscanner.classgraph.InterfaceDAGNode
        at io.github.lukehutch.fastclasspathscanner.classgraph.StandardClassDAGNode.connect(StandardClassDAGNode.java:66)
        at io.github.lukehutch.fastclasspathscanner.classgraph.ClassGraphBuilder.<init>(ClassGraphBuilder.java:72)
        at io.github.lukehutch.fastclasspathscanner.FastClasspathScanner.scan(FastClasspathScanner.java:1284)

I suppose this happens when an annotation class is encountered (or "matched"?).

Possible hint: Class.isInterface() also returns true for annotations not just for regular interfaces!

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.