【问题标题】:@Inherited annotation is not being inherited@Inherited 注解没有被继承
【发布时间】:2017-09-07 03:31:37
【问题描述】:

我有一个SubClass 和一个SuperClass,还有一个注解DocAnnotation。我需要调用SubClass.foo()SubClassSuperClass 获取所有类注释。这些类是这样定义的:

超类

package Code

import Annotations.DocAnnotation;
import java.util.Arrays;

@DocAnnotation("Super Annotation")
public class SuperClass {

    public void foo() {
        System.out.println(Arrays.toString(this.getClass().getAnnotations()));
        System.out.println(Arrays.toString(this.getClass().getDeclaredAnnotations()));
    }
}

子类

package Code;

import Annotations.DocAnnotation;

@DocAnnotation("Sub Annotation")
public class SubClass extends SuperClass{
}

文档注释

package Annotations;

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

@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(DocAnnotations.class)
public @interface DocAnnotation {
    String value();
}

Running SubClass.foo 我希望看到"Super Annotation""Sub Annotation",但我只看到[@Annotations.DocAnnotation(value=Sub Annotation)]。我误解了@inherited 的作用,还是我做错了什么?


编辑:

在将注释@DocAnnotation("Super Annotation") 添加到SubClass(与SuperClass 中的注释相同)之后,它实际上出现了两次,一次用于SubClass,一次用于SuperClass!现在我几乎可以肯定我误解了一些东西......

【问题讨论】:

    标签: java inheritance annotations


    【解决方案1】:

    这似乎是预期的行为,或者至少指定以这种方式工作 (doc):

    如果 [...] 用户在类声明上查询注解类型,并且类声明没有该类型的注解,则将自动查询该类的超类的注解类型.

    换句话说,由于SubClass 已经用@DocAnnotation 进行了注解,所以不会查询超类。

    经过进一步检查,这种行为似乎有点奇怪,尤其是在尝试存在包含注释类型之后。我想出了以下示例来说明这一点(link):

    import java.lang.annotation.*;
    import java.util.*;
    
    @Inherited
    @Repeatable(Container.class)
    @Retention(RetentionPolicy.RUNTIME)
    @interface Ann {
        String value();
    }
    
    @Inherited
    @Retention(RetentionPolicy.RUNTIME)
    @interface Container {
        Ann[] value();
    }
    
    // Basic case. Result is that
    // only @Ann("2") is present on
    // ExhibitASub.
    @Ann("1")
    class ExhibitASuper {
    }
    @Ann("2")
    class ExhibitASub extends ExhibitASuper {
    }
    
    // Because this case results in the
    // @Container being present on ExhibitBSuper,
    // rather than @Ann, all three annotations
    // end up appearing on ExhibitBSub.
    @Ann("1")
    @Ann("2")
    class ExhibitBSuper {
    }
    @Ann("3")
    class ExhibitBSub extends ExhibitBSuper {
    }
    
    // Similar to the preceding case, by
    // forcing the use of @Container, both
    // annotations are present on ExhibitCSub.
    @Container(@Ann("1"))
    class ExhibitCSuper {
    }
    @Ann("2")
    class ExhibitCSub extends ExhibitCSuper {
    }
    
    // Yet when we force both to use @Container,
    // only @Container(@Ann("2")) is present on
    // ExhibitDSub.
    @Container(@Ann("1"))
    class ExhibitDSuper {
    }
    @Container(@Ann("2"))
    class ExhibitDSub extends ExhibitDSuper {
    }
    
    class Main {
        public static void main(String[] args) {
            for (Class<?> cls : Arrays.asList(ExhibitASub.class,
                                              ExhibitBSub.class,
                                              ExhibitCSub.class,
                                              ExhibitDSub.class)) {
                System.out.printf("%s:%n", cls);
                for (Annotation ann : cls.getAnnotations()) {
                    System.out.printf("    %s%n", ann);
                }
    
                System.out.println();
            }
        }
    }
    

    其输出如下:

    class ExhibitASub:
        @Ann(value=2)
    
    class ExhibitBSub:
        @Container(value=[@Ann(value=1), @Ann(value=2)])
        @Ann(value=3)
    
    class ExhibitCSub:
        @Container(value=[@Ann(value=1)])
        @Ann(value=2)
    
    class ExhibitDSub:
        @Container(value=[@Ann(value=2)])
    

    请注意,对于 B 和 C,我们在超类和子类上都看到了注解。这大概是因为(在严格意义上)超类上的注解与子类上的注解属于不同的类型。请注意,对于 D,我们返回仅查看子类注释,因为两个类都使用容器类型。

    在某些情况下,显式使用包含注释类型可能是一种解决方法,但由于情况 D,这不是通用解决方案。

    我明天可能会为此提交一份错误报告,因为这似乎很不受欢迎。由于@Inherited 早于@Repeatable,因此这种行为可能来自以前不会发生这种情况的版本。

    【讨论】:

    • 我完全忘记了容器注释!这真的让我陷入了循环......你知道我描述的行为是否可能吗?我可以直接查询子类扩展的所有类,但这似乎是丑陋的代码。有更好的解决方案吗?
    • 我不这么认为。另一种解决方案可能是完全放弃注释并使用接口。我真的不能说这对你的情况是否更好,但它可以工作,因为你正在注释类。
    • 我想我将不得不坚持注释,但谢谢!如果您最终提交了错误报告,请在此处发布指向它的链接。我很想知道 Oracle 是否也期望这种行为。
    【解决方案2】:

    你得到这个注释是错误的。 javadoc 明确指出:

    表示一个注解类型是自动继承的。如果注解类型声明中存在 Inherited 元注解,并且用户在类声明中查询注解类型,并且类声明没有该类型的注解,则将自动查询该类的超类以获取注解类型。

    换句话说:如果你查询子类,那么你会发现超类被注释了。但这个东西是为了继承在“OO 意义上”。如果你想看到both注解,你必须编写代码手动检查类继承树中的每个类。

    【讨论】:

      猜你喜欢
      • 2017-06-04
      • 1970-01-01
      • 2012-06-23
      • 1970-01-01
      • 2011-11-02
      • 2015-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多