Why can't I detect annotations from the loaded Java class?

I have a plugin inside. I want to access the class list of my model package from my maven project. So far, I just did this to load the classes into the plugin:

try {
            runtimeClasspathElements = project.getRuntimeClasspathElements();

        } catch (DependencyResolutionRequiredException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        URL[] runtimeUrls = new URL[runtimeClasspathElements.size()];
        for (int i = 0; i < runtimeClasspathElements.size(); i++) {
          String element = (String) runtimeClasspathElements.get(i);
          try {
            runtimeUrls[i] = new File(element).toURI().toURL();
        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

newLoader = new URLClassLoader(runtimeUrls,
      Thread.currentThread().getContextClassLoader());
      try {          class=newLoader.loadClass("com.pkl.bc.personnaldata.model.Personne");

    if(class!=null)
        System.out.println(class.getCanonicalName());
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

      

So far, I can see the full name of my class.

System.out.println(class.getDeclaredFields());
System.out.println(class.isAnnotationPresent(EditColumn.class));
for (Field f : class.getDeclaredFields()) {

                EditColumn v = f.getAnnotation(EditColumn.class);
                if (v != null) {

                    System.out.println(v.tableName());
                    System.out.println(v.oldName());

                }

            }

      

but i get nothing, here is the output:

[Ljava.lang.reflect.Field;@398f573b
false

      

I have also tried using refelctions

Reflections reflections = new Reflections("com.pkl.bc.personnaldata.model.Personne");

          Set<Field> annotated = reflections.getFieldsAnnotatedWith(EditColumn.class);

          System.out.println(annotated);

      

this gives me an empty list. here is my annotation:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface EditColumn {

    String oldName() default "";

    String newName() default "";

    String tableName() default "";
}

      

annotated field:

@EditColumn(newName = "main_adress", oldName = "adress", tableName = "Personne")
    private String main_adress;

      

+3


source to share


2 answers


You already retrieve the class with its annotations, but you just need to add a loop to iterate over all the annotations for every field you have.

try this example, it will print annotation name and its values ​​when available for loaded class field.



  for (Field f : loadedClass.getDeclaredFields()) {
                System.out.println(f.getName());
                for (Annotation a : f.getAnnotations()) {
                    System.out.println("## SHOWING ANNOTATION FOR FIELD:" + f.getName());
                    System.out.println(a.toString());
                }


            }

      

You can parse toString to get the values ​​in this annotation. Waiting for feedback.

+1


source


I corrected my answer that your problem is loading an instance of another class into another class ClassLoader when it Thread.getContextClassLoader()

returns null

, because URLClassLoader (urls, parent) when the parent is null. You can see tests that both paths return java a Proxy

instance for Name

instance.occurs annotation this problem is often caused by Thread.currentThread().setContextClassLoader(null)

someone somewhere. You can solve the problem by checking the contextLoader if it is null.for example:

ClassLoader context=Thread.currentThread().getContextClassLoader();
if(context==null){
  context=getClass().getClassLoader();
}
URLClassLoader loader=new URLClassLoader(urls,context);

      

Test

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.lang.annotation.Annotation;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.function.Consumer;
import java.util.stream.Stream;

import static java.lang.String.format;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;

/**
 * Created by holi on 3/24/17.
 */
public class AnnotationsTest {
    private interface StubClass {
        Class<?> stubClass() throws ClassNotFoundException;

        default <T extends Annotation> T annotation(Class<T> type) throws Exception {
            return stubClass().getAnnotation(type);
        }

        default Annotation[] annotations() throws Exception {
            return stubClass().getAnnotations();
        }
    }

    private static final StubClass JAR_WITHIN_ANNOTATION_CLASS = jar("stubs-within-annotation-class.jar");
    private static final StubClass JAR_WITHOUT_ANNOTATION_CLASS = jar("stubs-without-annotation-class.jar");

    public static StubClass jar(String jar) {
        URL jarFile = Objects.requireNonNull(ClassLoader.getSystemResource(jar), format("Jar file not found:%s", jar));
        return () -> {
            ClassLoader context = Thread.currentThread().getContextClassLoader();
            return new URLClassLoader(new URL[]{jarFile}, context).loadClass("Stub");
        };
    }

    private ClassLoader original;

    @BeforeEach
    void setUp() throws Throwable {
        original = Thread.currentThread().getContextClassLoader();
    }

    @AfterEach
    void tearDown() throws Throwable {
        Thread.currentThread().setContextClassLoader(original);
    }

    @Test
    void getAnnotationFromJarClassesWillReturnsContextLoaderAnnotationSharedInstanceIfContextLoaderAssociatedWithRuntimeClassLoader() throws Throwable {
        Set<Object> annotationsCreated = new HashSet<>();
        Set<Object> stubClassCreated = new HashSet<>();
        Thread.currentThread().setContextClassLoader(getClass().getClassLoader());

        Stream.of(JAR_WITHIN_ANNOTATION_CLASS, JAR_WITHOUT_ANNOTATION_CLASS).forEach(asserts(stub -> {
            Name it = stub.annotation(Name.class);
            assertThat(it, is(instanceOf(Name.class)));
            assertThat(it.value(), equalTo("stub"));
            annotationsCreated.add(it);
            stubClassCreated.add(stub.stubClass());
        }));

        assertThat(annotationsCreated, hasSize(1));
        assertThat(stubClassCreated, hasSize(2));
    }

    @Test
    void getAnnotationFromJarClassesWillReturnsNullIfNoContextLoaderAssociated() throws Throwable {
        Thread.currentThread().setContextClassLoader(null);

        Stream.of(JAR_WITHIN_ANNOTATION_CLASS, JAR_WITHOUT_ANNOTATION_CLASS).forEach(asserts(it -> {
            //create different class instance in each class loader
            assertThat(it.stubClass().getName(), equalTo("Stub"));

            assertThat(it.annotation(Name.class), is(nullValue()));
        }));

        assertThat(JAR_WITHOUT_ANNOTATION_CLASS.annotations(), is(emptyArray()));
        assertThat(JAR_WITHIN_ANNOTATION_CLASS.annotations(), arrayWithSize(1));
        Annotation it = JAR_WITHIN_ANNOTATION_CLASS.annotations()[0];

        assertThat(it.annotationType(), is(not(instanceOf(Name.class))));
        assertThat(it.annotationType().getName(), equalTo(Name.class.getName()));
        assertThat(it.annotationType().getDeclaredMethod("value").invoke(it), equalTo("stub"));
    }


    private interface Assert<T> {
        void assertThat(T value) throws Exception;
    }

    private <T> Consumer<T> asserts(Assert<T> executor) {
        return (value) -> {
            try {
                executor.assertThat(value);
            } catch (RuntimeException e) {
                throw e;
            } catch (Exception e) {
                RuntimeException wrappedException = new RuntimeException(e);
                wrappedException.setStackTrace(e.getStackTrace());
                throw wrappedException;
            }
        };
    }
}

      



@Name Annotation

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Created by holi on 3/24/17.
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface Name {
    String value();
}

      

Stub class

@Name("stub")
public class Stub{
}

      

+3


source







All Articles