【问题标题】:Can you get subclass Annotation in parent?你能在父类中获得子类注释吗?
【发布时间】:2021-09-29 12:10:16
【问题描述】:

这是有线的,但你能做到吗?

我想使用无参数构造函数(所以开发依赖于我的框架不需要扩展构造函数),但我想在字段中使用 final。所以:

Annotation.java

public @interface Annotation {
    String value();
}

父类.java

public abstract class Parent {

    public final String name;

    // this will cause you must extends constructor in any sub class
    public Parent(Annotation annotation){
        this.name = annotation.value();
    }
}

接口定义

public abstract class Define extends Parent {


    // You can't do that:
    // Cannot reference 'this' before supertype constructor has been called
    public Define (){
        this(this.getClass().getAnnotation(Annotation.class).value());
    }

    // You can do that, but not working 
    // Define is point at Define as is rather I hope the sub class MyModule
    public Define (){
        this(Define.class.getAnnotation(Annotation.class).value());
    }

    public Define (Annotation annotation){
        super(annotation); // You must extend this
    }

    public abstract void foo();

}

我希望开发者可以像这样使用我的框架:

public class MyModule extends Define {

    public void foo(){
        // foo bar 
    }

}

但是由于Cannot reference 'this' before supertype constructor has been called,你必须写:

@Annotation
public class MyModule extends Define {

    // my framework using scan an IoC auto invoke 
    public MyModule(Annotation annotation){
        super(annotation.value())
    }

    public void foo(){
        // foo bar 
    }

}

悖论是name是写在注解中,而this必须在newInstance之后。所以这个问题更像是:

子类如何getClass()

所以唯一的解决方案是放弃 final 字段并使用类似 init() 的东西?

【问题讨论】:

    标签: java annotations java-annotations


    【解决方案1】:

    您可以将读取注解移动到基类,而不是要求每个子类读取注解并将其传递给超类:

    @Retention(RetentionPolicy.RUNTIME)
    @interface MyAnnotation {
      String value() default "defaultValue";
    }
    
    abstract class Base {
      final String value;
      Base() {
        MyAnnotation myAnnotation= getClass().getAnnotation(MyAnnotation.class);
        if (myAnnotation == null) {
          throw new IllegalStateException("Class " + getClass().getName() + " does not have require annotation MyAnnotation");
        }
        this.value = myAnnotation.value();
      }
    }
    
    @MyAnnotation
    class DefaultValue extends Base {
    }
    
    @MyAnnotation("someValue")
    class ExplicitValue extends Base {
    }
    
    class NoAnnotation extends Base {
    }
    

    给定这些类这两行

    System.out.println(new DefaultValue().value);
    System.out.println(new ExplicitValue().value);
    

    将分别打印defaultValuesomeValue。但是,这一行会抛出一个IllegalStateException

    new NoAnnotation();
    

    不幸的是,Java 类型系统不允许在编译时对每个具体类执行注解的要求,所以这个运行时异常是你能得到的最好的(在其他静态分析工具或 ArchUnit 等架构测试软件之外) .

    【讨论】:

      【解决方案2】:

      你能接受使用反射来解决这个问题吗?

      public abstract class Parent {
      
          final String name;
      
          public Parent() {
              this.name = null;
          }
      
          void setAnnotation(Annotation annotation) throws NoSuchFieldException, IllegalAccessException {
              Field field = Parent.class.getDeclaredField("name");
              field.setAccessible(true);
              field.set(this, annotation.value());
              field.setAccessible(false);
          }
      }
      
      public abstract class Define extends Parent {
          public Define() {
              super();
              try {
                  this.setAnnotation();
              } catch (Exception e) {
      
              }
          }
      
          public abstract void foo();
      
          public void setAnnotation() throws NoSuchFieldException, IllegalAccessException {
              Annotation annotation = this.getClass().getAnnotation(Annotation.class);
              super.setAnnotation(annotation);
          }
      }
      
      @Annotation(value = "foo")
      public class MyModule extends Define {
      
          @Override
          public void foo() {
          }
      }
      

      别忘了在注释类上添加TargetRetention

      【讨论】:

      • 在运行时使用注解必然意味着使用注解。
      猜你喜欢
      • 2022-11-24
      • 2010-12-19
      • 2011-01-14
      • 1970-01-01
      • 2023-04-04
      • 2016-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多