【问题标题】:Why I can't detect annotations from a loaded java class?为什么我无法从已加载的 java 类中检测到注释?
【发布时间】:2017-08-17 02:48:02
【问题描述】:

我有一个插件,我想从我的 maven 项目中访问我的模型包的类列表。到目前为止,我只是将类加载到插件中:

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();
    }

直到在这里我才能看到我班级的全名。

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());

                }

            }

但我什么也没得到,这是输出:

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

我也尝试过使用refelctions

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

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

          System.out.println(annotated);

这给了我一个空列表。 这是我的注释:

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 "";
}

注释字段:

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

【问题讨论】:

  • 我已经更新了我的答案,希望对您有所帮助!

标签: java maven reflection annotations maven-plugin


【解决方案1】:

我修正了我的答案,当Thread.getContextClassLoader() 返回null 时,您的问题是在不同的 ClassLoader 中加载不同的类实例,因为当 parent 为 null 时 URLClassLoader(urls,parent)。你可以看到两种方式 java 返回的测试一个Proxy instance for Annotation Name instance. 出现这个问题,经常有人在某处调用Thread.currentThread().setContextClassLoader(null)。所以你可以通过检查contextLoader是否为null来解决问题。例如:

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

测试

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 注释

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();
}

存根类

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

【讨论】:

    【解决方案2】:

    您已经在检索带有注释的类,但您只需要添加一个循环来迭代您拥有的每个字段的所有注释。

    试试这个例子,当它可用于加载类的字段时,它将打印注释名称及其值。

      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());
                    }
    
    
                }
    

    您可以解析 toString 以检索该注释上的值。 等待您的反馈。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多