【问题标题】:Create custom method level annotation only available to specific return types [AOP]创建仅适用于特定返回类型的自定义方法级别注释 [AOP]
【发布时间】:2019-09-06 13:10:51
【问题描述】:

我想创建一个仅对特定类型的返回值可用的注释。

例如这是我的注释。

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface MyAnnotation {

}

我还有一个界面:

public interface MyInterface {
    String generateKey();
}

实现我的接口的示例类:

public class ExampleClass implements MyInterface {

@Override
public String generateKey() {
   return "Whatever";
    }
}

所以在这些之后,我想以一种方式配置我的注释,如果返回类型没有实现MyInterface,它甚至不会编译。

在这种情况下,我希望它编译得很好:

@MyAnnotation
public ExampleClass anExampleMethod() {
    return new ExampleClass();
}

这不能编译:

@MyAnnotation
public String anotherMethod() {
    return "Whatever";
}

我想知道这是否有可能。当然我可以检查参数是否在我的 Aspect 类中实现了这个接口,但最好在我的库中按顺序提供这种保护以防止滥用任何注释。

【问题讨论】:

    标签: java annotations aop pointcut retention


    【解决方案1】:

    辅助分类器:

    这些直接来自您的示例,只是带有包名和导入。

    package de.scrum_master.app;
    
    import static java.lang.annotation.ElementType.METHOD;
    import static java.lang.annotation.RetentionPolicy.RUNTIME;
    
    import java.lang.annotation.Retention;
    import java.lang.annotation.Target;
    
    @Retention(RUNTIME)
    @Target(METHOD)
    public @interface MyAnnotation {}
    
    package de.scrum_master.app;
    
    public interface MyInterface {
      String generateKey();
    }
    
    package de.scrum_master.app;
    
    public class ExampleClass implements MyInterface {
      @Override
      public String generateKey() {
        return "Whatever";
      }
    }
    

    不应编译的类:

    这个类有一些注解和一些非注解的方法。一个带注释的方法返回MyInterface 或其任何实现类。目标是编译失败。

    package de.scrum_master.app;
    
    public class Application {
      @MyAnnotation
      public MyInterface annotatedMethodReturningInterface(int number) {
        return new ExampleClass();
      }
    
      @MyAnnotation
      public ExampleClass annotatedMethodReturningImplementingClass() {
        return new ExampleClass();
      }
    
      @MyAnnotation
      public String annotatedMethodReturningSomethingElse() {
        // This one should not compile!
        return "Whatever";
      }
    
      public MyInterface nonAnnotatedMethodReturningInterface(int number) {
        return new ExampleClass();
      }
    
      public ExampleClass nonAnnotatedMethodReturningImplementingClass() {
        return new ExampleClass();
      }
    
      public String nonAnnotatedMethodReturningSomethingElse() {
        return "Whatever";
      }
    }
    

    约定检查方面(原生 AspectJ 语法):

    package de.scrum_master.aspect;
    
    import de.scrum_master.app.MyAnnotation;
    import de.scrum_master.app.MyInterface;
    
    public aspect AnnotationCheckerAspect {
      declare error :
        @annotation(MyAnnotation) && execution(* *(..)) && !execution(MyInterface+ *(..)) :
        "Method annotated with @MyAnnotation must return MyInterface type";
    }
    

    这方面检查

    • 所有方法执行
    • 方法有@MyAnnotation
    • 但返回类型不同于 MyInterface 或任何子类型或实现类。

    这是 Eclipse 中的结果:

    当然,如果您从命令行或通过 AspectJ Maven 插件或类似插件编译,编译错误是一样的。

    如果您不喜欢原生语法(我更喜欢它,但出于某种难以理解的原因,其他人似乎更喜欢 @AspectJ 风格):

    约定检查方面(基于注解的@AspectJ 语法):

    package de.scrum_master.aspect;
    
    import org.aspectj.lang.annotation.Aspect;
    import org.aspectj.lang.annotation.DeclareError;
    
    @Aspect
    public class AnnotationCheckerAspect {
      @DeclareError(
        "@annotation(de.scrum_master.app.MyAnnotation) && " +
        "execution(* *(..)) && " +
        "!execution(de.scrum_master.app.MyInterface+ *(..))"
      )
      static final String wrongSignatureError =
      "Method annotated with @MyAnnotation must return MyInterface type";
    }
    

    也可以在这里查看我的相关答案:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-31
      • 2019-01-24
      相关资源
      最近更新 更多