Skip to main content

Find Java classes implementing an interface



Some time ago, I came across a piece of code, that used some piece of standard Java functionality to locate the classes that implemented a given interface. I know the functions were hidden in some non-logical place, but they could be used for other classes as the package name implied. Back then I did not need it, so I forgot about it, but now I do, and I can't seem to find the functions again. Where can these functions be found?





Edit: I'm not looking for any IDE functions or anything, but rather something that can be executed within the Java application.


Comments

  1. Awhile ago, I put together a package for doing what you want, and more. (I needed it for a utility I was writing). It uses the ASM library. You can use reflection, but ASM turned out to perform better.

    I put my package in an open source library I have on my web site. The library is here: http://software.clapper.org/javautil/. You want to start with the with ClassFinder class.

    The utility I wrote it for is an RSS reader that I still use every day, so the code does tend to get exercised. I use ClassFinder to support a plug-in API in the RSS reader; on startup, it looks in a couple directory trees for jars and class files containing classes that implement a certain interface. It's a lot faster than you might expect.

    The library is BSD-licensed, so you can safely bundle it with your code. Source is available.

    If that's useful to you, help yourself.

    Update: If you're using Scala, you might find this library to be more Scala-friendly.

    ReplyDelete
  2. The code you are talking about sounds like ServiceLoader, which was introduced in Java 6 to support a feature that has been defined since Java 1.3 or earlier. For performance reasons, this is the recommended approach to find interface implementations at runtime; if you need support for this in an older version of Java, I hope that you'll find my implementation helpful.

    There are a couple of implementations of this in earlier versions of Java, but in the Sun packages, not in the core API (I think there are some classes internal to ImageIO that do this). As the code is simple, I'd recommend providing your own implementation rather than relying on non-standard Sun code which is subject to change.

    ReplyDelete
  3. Obviously, Class.isAssignableFrom() tells you whether an individual class implements the given interface. So then the problem is getting the list of classes to test.

    As far as I'm aware, there's no direct way from Java to ask the class loader for "the list of classes that you could potentially load". So you'll have to do this yourself by iterating through the visible jars, calling Class.forName() to load the class, then testing it.

    However, it's a little easier if you just want to know classes implementing the given interface from those that have actually been loaded:


    via the Java Instrumentation framework, you can call Instrumentation.getAllLoadedClasses()
    via reflection, you can query the ClassLoader.classes field of a given ClassLoader.


    If you use the instrumentation technique, then (as explained in the link) what happens is that your "agent" class is called essentially when the JVM starts up, and passed an Instrumentation object. At that point, you probably want to "save it for later" in a static field, and then have your main application code call it later on to get the list of loaded classes.

    ReplyDelete
  4. Spring can do this for you...

    BeanDefinitionRegistry bdr = new SimpleBeanDefinitionRegistry();
    ClassPathBeanDefinitionScanner s = new ClassPathBeanDefinitionScanner(bdr);

    TypeFilter tf = new AssignableTypeFilter(CLASS_YOU_WANT.class);
    s.addIncludeFilter(tf);
    s.scan("package.you.want1", "package.you.want2");
    String[] beans = bdr.getBeanDefinitionNames();


    N.B. The TypeFilter is important if you want the correct results!
    You can also use exclusion filters here instead.

    The Scanner can be found in the spring-context jar, the registry in spring-beans, the type filter is in spring-core.

    ReplyDelete
  5. I know this question has already been answered a long time ago but another solution to this problem is to use Package Level Annotations.

    While its pretty hard to go find all the classes in the JVM its actually pretty easy to browse the package hierarchy.

    Package[] ps = Package.getPackages();
    for (Package p : ps) {
    MyAno a = p.getAnnotation(MyAno.class)
    // Recursively descend
    }


    Then just make your annotation have an argument of an array of Class.
    Then in your package-info.java for a particular package put the MyAno.

    I'll add more details (code) if people are interested but most probably get the idea.

    ReplyDelete
  6. In full generality, this functionality is impossible. The Java ClassLoader mechanism guarantees only the ability to ask for a class with a specific name (including pacakge), and the ClassLoader can supply a class, or it can state that it does not know that class.

    Classes can be (and frequently are) loaded from remote servers, and they can even be constructed on the fly; it is not difficult at all to write a ClassLoader that returns a valid class that implements a given interface for any name you ask from it; a List of the classes that implement that interface would then be infinite in length.

    In practice, the most common case is an URLClassLoader that looks for classes in a list of filesystem directories and JAR files. So what you need is to get the URLClassLoader, then iterate through those directories and archives, and for each class file you find in them, request the corresponding Class object and look through the return of its getInterfaces() method.

    ReplyDelete
  7. If you were asking from the perspective of working this out with a running program then you need to look to the java.lang.* package. If you get a Class object, you can use the isAssignableFrom method to check if it is an interface of another Class.

    There isn't a simple built in way of searching for these, tools like Eclipse build an index of this information.

    If you don't have a specific list of Class objects to test you can look to the ClassLoader object, use the getPackages() method and build your own package hierarchy iterator.

    Just a warning though that these methods and classes can be quite slow.

    ReplyDelete
  8. Any good IDE such as IntelliJ Idea or Eclipse can show you all of the implementing classes for an interface, or (even better) the entire class hierarchy for an interface/class.

    ReplyDelete

Post a Comment

Popular posts from this blog

[韓日関係] 首相含む大幅な内閣改造の可能性…早ければ来月10日ごろ=韓国

div not scrolling properly with slimScroll plugin

I am using the slimScroll plugin for jQuery by Piotr Rochala Which is a great plugin for nice scrollbars on most browsers but I am stuck because I am using it for a chat box and whenever the user appends new text to the boxit does scroll using the .scrollTop() method however the plugin's scrollbar doesnt scroll with it and when the user wants to look though the chat history it will start scrolling from near the top. I have made a quick demo of my situation http://jsfiddle.net/DY9CT/2/ Does anyone know how to solve this problem?

Why does this javascript based printing cause Safari to refresh the page?

The page I am working on has a javascript function executed to print parts of the page. For some reason, printing in Safari, causes the window to somehow update. I say somehow, because it does not really refresh as in reload the page, but rather it starts the "rendering" of the page from start, i.e. scroll to top, flash animations start from 0, and so forth. The effect is reproduced by this fiddle: http://jsfiddle.net/fYmnB/ Clicking the print button and finishing or cancelling a print in Safari causes the screen to "go white" for a sec, which in my real website manifests itself as something "like" a reload. While running print button with, let's say, Firefox, just opens and closes the print dialogue without affecting the fiddle page in any way. Is there something with my way of calling the browsers print method that causes this, or how can it be explained - and preferably, avoided? P.S.: On my real site the same occurs with Chrome. In the ex