Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassNotFound exception while executing Java AnnotationProcessor

I wrote a simple annotation and an AnnotationProcessor to process the annotation.

The annotation has a single value: it should be the name of an existing interface (with package).

The annotation processor should retrieve the value of the annotation, retrieve the Class object of the interface and finally should print all method declared in the interface.

Example: this is my annotation

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation{
    public String interfaceName();
}

and this is the annotated class:

@MyAnnotation(interfaceName = "java.lang.CharSequence")
public class Example{}

my processor looks like

[...]
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment env) {

    for (TypeElement te : annotations) {

        for(Element e : env.getElementsAnnotatedWith(te)) {

            MyAnnotation myAnnotation = e.getAnnotation(MyAnnotation.class);
            String iName = myAnnotation.interfaceName();
            Class<?> clazz = Class.forName(iName);
            // use reflection to cycle through methods and prints them
            [...]
        }
    }

now this works fine if I configure an interface like java.lang.CharSequence as the interfaceName of MyAnnotation;

however, if I configure as interfaceName an interface located in a .jar file (added in the buildpath of the project), I obtain a ClassNotFoundException when I try to do the Class.forName(...) statement.

Any thoughts?

Thank you, cheers

like image 754
user1561017 Avatar asked Mar 30 '26 00:03

user1561017


1 Answers

This is a typical ClassLoader issue. You're trying to find a class which was not loaded by the current class loader, so a ClassNotFoundException is thrown.

The Javadoc for java.lang.Class defines the method Class.forName(className) as:

Returns the Class object associated with the class or interface with the given string name. Invoking this method is equivalent to Class.forName(className, true, currentLoader) where currentLoader denotes the defining class loader of the current class.

So, this method call will try to look up the specified class in the current class loader context. The interface you are trying to find has not been loaded by this classloader, so a ClassNotFoundException is thrown.

If the .jar file is on the classpath of your application, you can simply use the system classloader instead, like so...

ClassLoader systemClassLoader = ClassLoader.getSystemClassloader();
Class<?> clazz = Class.forName(className, true, systemClassLoader)

...But if your .jar file is located elsewhere, and has not been loaded yet, you're going to need to load it accordingly:

ClassLoader urlClassLoader = new URLClassLoader(new URL[]{new URL("path/to/file.jar")});
Class<?> clazz = Class.forName(className, true, urlClassLoader)

Et voilà!

like image 200
Daniel Scarfe Avatar answered Apr 02 '26 03:04

Daniel Scarfe



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!