自定义Java注释以跳过方法执行

时间:2017-02-28 12:47:06

标签: java aop aspectj spring-annotations java-annotations

我想创建一个自定义注释来跳过方法执行

这是我的注释代码,带有验证器类

@Target({ METHOD , FIELD , PARAMETER } )
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy={MyValidator .class})
public @interface MyAnnotation {

    String message() default "DEFAULT_FALSE";

    Class<?>[] groups() default{};

    Class<? extends Payload>[] payload() default{};

}

我用验证器试了一下。这就是我的验证器的样子

public class MyValidator implements ConstraintValidator<MyAnnotation, String >{

    @Override
    public void initialize(MyAnnotation arg0) {

    }

    @Override
    public boolean isValid(String arg0, ConstraintValidatorContext arg1) {

        if(str=="msg"){
            return true;
        }
        return false;
    }

}

这就是我想要使用的方法 - 我想在方法级别使用注释并跳过方法执行。

我不知道是否有可能..请帮忙。

public class Test {



    public static void main(String[] args) {
    Test t = new Test();
        boolean valid=false;

         valid=t.validate();
        System.out.println(valid);

    }

@MyAnnotation(message="msg")
    public boolean validate(){

     // some code to return true or false
    return true;


    }
}

2 个答案:

答案 0 :(得分:4)

你应该使用AOP。创建一个AspectJ项目,并尝试这样的事情:

MyAnnotation.java:

package moo.aspecttest;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(value = { ElementType.METHOD })
public @interface MyAnnotation
{
    public String value();
}

MyAspectClass.java:

package moo.aspecttest;

import java.lang.reflect.Method;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;

@Aspect
public class MyAspectClass
{

    @Around("execution(* *(..))")
    public Object aroundAdvice(ProceedingJoinPoint point) throws Throwable
    {
        Method method = MethodSignature.class.cast(point.getSignature()).getMethod();
        String name = method.getName();
        MyAnnotation puff = method.getAnnotation(MyAnnotation.class);
        if (puff != null) {
            System.out.println("Method " + name + " annotated with " + puff.value() + ": skipped");
            return null;
        } else {
            System.out.println("Method " + name + " non annotated: executing...");
            Object toret = point.proceed();
            System.out.println("Method " + name + " non annotated: executed");
            return toret;
        }
    }
}

MyTestClass.java:

package moo.aspecttest;

public class MyTestClass
{

    @MyAnnotation("doh")
    public boolean validate(String s) {
        System.out.println("Validating "+s);
        return true;
    }

    public boolean validate2(String s) {
        System.out.println("Validating2 "+s);
        return true;
    }

    public static void main(String[] args)
    {
        MyTestClass mc = new MyTestClass();

        mc.validate("hello");
        mc.validate2("cheers");

        }
    }
}

运行时生成的输出:

Method main non annotated: executing...
Method validate annotated with doh: skipped
Method validate2 non annotated: executing...
Validating2 cheers
Method validate2 non annotated: executed
Method main non annotated: executed

我使用了一个非常通用的aroundAdvice,但你可以使用beforeAdvice,如果你想要。实际上,我认为这一点很清楚。

答案 1 :(得分:2)

它实际上非常简单,可以写出最简单的方面。 ;-)

您的示例代码的丑陋之处在于它使用了几个您不显示源代码的类,因此我必须创建虚拟类/接口以便编译代码。你也没有展示如何应用验证器,所以我不得不推测。无论如何,这是一组完全自洽的样本类:

助手类:

这只是脚手架,以便编译所有内容。

package de.scrum_master.app;

public interface Payload {}
package de.scrum_master.app;

public class ConstraintValidatorContext {}
package de.scrum_master.app;

public @interface Constraint {
  Class<MyValidator>[] validatedBy();
}
package de.scrum_master.app;

import java.lang.annotation.Annotation;

public interface ConstraintValidator<T1 extends Annotation, T2> {
  void initialize(T1 annotation);
  boolean isValid(T2 value, ConstraintValidatorContext validatorContext);
}
package de.scrum_master.app;

public class MyValidator implements ConstraintValidator<MyAnnotation, String> {
  @Override
  public void initialize(MyAnnotation annotation) {}

  @Override
  public boolean isValid(String value, ConstraintValidatorContext validatorContext) {
    if ("msg".equals(value))
      return true;
    return false;
  }
}
package de.scrum_master.app;

import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.*;

import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.*;

@Target({ METHOD, FIELD, PARAMETER })
@Retention(RUNTIME)
@Constraint(validatedBy = { MyValidator.class })
public @interface MyAnnotation {
  String message() default "DEFAULT_FALSE";
  Class<?>[] groups() default {};
  Class<? extends Payload>[] payload() default {};
}

驱动程序应用程序:

如果你想测试一些东西,你不仅需要一个积极的测试用例,而且还需要一个负面的测试用例。因为你没有提供,用户Sampisa的回答并不是你想要的。顺便说一句,我认为你应该能够自己从中推断出解决方案。你甚至都没试过。你没有任何编程经验吗?

package de.scrum_master.app;

public class Application {
  public static void main(String[] args) {
    Application application = new Application();
    System.out.println(application.validate1());
    System.out.println(application.validate2());
  }

  @MyAnnotation(message = "execute me")
  public boolean validate1() {
    return true;
  }

  @MyAnnotation(message = "msg")
  public boolean validate2() {
    return true;
  }
}

<强>方面:

除了Sampisa之外,我添加另一个示例方面的唯一原因是他的解决方案在他的反射使用方面不是最理想的。它很丑,很慢。我认为我的解决方案更优雅一点。亲眼看看:

package de.scrum_master.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

@Aspect
public class SkipValidationAspect {
  @Around("execution(@de.scrum_master.app.MyAnnotation(message=\"msg\") boolean *(..))")
  public boolean skipValidation(ProceedingJoinPoint thisJoinPoint) throws Throwable {
    return false;
  }
}

很简单,不是吗?

控制台日志:

true
false

Etvoilà - 我认为这就是你要找的东西。