【问题标题】:Overriding method level @annotation at runtime with reflection, works for class level在运行时使用反射覆盖方法级别@annotation,适用于类级别
【发布时间】:2018-04-06 20:37:51
【问题描述】:

问题:我能够使用以下方法成功覆盖类级别注释:

public static void alterClassAnnotation(Class classToLookFor, Class<? extends Annotation> annotationToAlter,Annotation annotationValue) {
        if (isJDK7OrLower()) {
            try {
                Field annotations = Class.class.getDeclaredField(ANNOTATIONS);
                annotations.setAccessible(true);
                Map<Class<? extends Annotation>, Annotation> map =
                    (Map<Class<? extends Annotation>, Annotation>) annotations.get(classToLookFor);
                map.put(annotationToAlter, annotationValue);
            } catch (Exception  e) {
                e.printStackTrace();
            }
        } else {
            try {
                //In JDK8 Class has a private method called annotationData().
                //We first need to invoke it to obtain a reference to AnnotationData class which is a private class
                Method method = Class.class.getDeclaredMethod(ANNOTATION_DATA, null);
                method.setAccessible(true);
                //Since AnnotationData is a private class we cannot create a direct reference to it. We will have to
                //manage with just Object
                Object annotationData = method.invoke(classToLookFor);
                //We now look for the map called "annotations" within AnnotationData object.
                Field annotations = annotationData.getClass().getDeclaredField(ANNOTATIONS);
                annotations.setAccessible(true);
                Map<Class<? extends Annotation>, Annotation> map =
                    (Map<Class<? extends Annotation>, Annotation>) annotations.get(annotationData);
                map.put(annotationToAlter, annotationValue);
            } catch (Exception  e) {
                e.printStackTrace();
            }
        }
    }

我对反射 API 感到困惑,如何修改此代码以覆盖方法级别参数的值?我有 3 个注释,其中 2 个可以在类级别设置,所以我用这段代码成功地覆盖了它们,但是如果注释是针对方法本身的呢?

我的接口实现类:

import java.lang.annotation.Annotation;

import io.qameta.allure.junit4.DisplayName;
public class DynamicDisplayName implements DisplayName {

    private String value;

    public DynamicDisplayName(String value) {
        this.value = value;
    }

    @Override
    public Class<? extends Annotation> annotationType() {
        return null;
    }

    @Override
    public String value() {
        return value;
    }

}

我已经成功覆盖了 Issue 和 TmsLink,这是我的代码(这两个接口都在类级别正常运行)

Issue issue = SaveCourse.class.getAnnotation(Issue.class);
DynamicIssue altered = new DynamicIssue(issueId);
AnnotationHelper.alterClassAnnotation(SaveCourse.class, Issue.class, altered);
issue = SaveCourse.class.getAnnotation(Issue.class);                 


DisplayName dname = SaveCourse.class.getAnnotation(DisplayName.class);
DynamicDisplayName dna = new DynamicDisplayName(displayName);
AnnotationHelper.alterClassAnnotation(SaveCourse.class, DisplayName.class, dna);
dname = SaveCourse.class.getAnnotation(DisplayName.class);

TmsLink tmslink = SaveCourse.class.getAnnotation(TmsLink.class);
DynamicTmsLink tmsaltered = new DynamicTmsLink(testCaseId);
AnnotationHelper.alterClassAnnotation(SaveCourse.class, TmsLink.class, tmsaltered);
tmslink = SaveCourse.class.getAnnotation(TmsLink.class);

displayName 接口:

/**
 * Used to change display name for test in the report.
 */
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
public @interface DisplayName {

    String value();

}

【问题讨论】:

  • 依赖于 java.lang.Class 中私有字段或方法的存在保证会在 Java 的更高版本中中断。为什么要这样做?
  • 我正在使用带有 junit DataProvider 的 allure 报告作为测试数据,allure 有一些可以在方法级别应用的注释,但我很难将数据从 DataProvider 传递到注释中,所以报告每次迭代都包含准确的数据,您能否建议实现这一目标的更好方法? @VGR

标签: java reflection interface overriding


【解决方案1】:

对于 JUnit4 的 Allure,我使用以下方法在方法级别动态设置 DisplayName。

AllureLifecycle oLifecycle = Allure.getLifecycle();
oLifecycle.updateTestCase(testResult -> testResult.setName("My DisplayName");

【讨论】:

    【解决方案2】:

    这是我的code on github.。你可以使用

    addAnnotation(...)
    removeAnnotation(...)
    changeAnnotationValue(...)
    

    修改ClassFieldMethod上的注解。并使用createAnnotationFromMap 来创建任何类型的注解。

    【讨论】:

      猜你喜欢
      • 2012-06-29
      • 2010-09-28
      • 1970-01-01
      • 2016-08-04
      • 2011-11-29
      • 1970-01-01
      • 1970-01-01
      • 2016-02-07
      • 2014-08-14
      相关资源
      最近更新 更多