Java 注解

277 阅读2分钟

如题:使用 @Range 注解来检查 Java Bean的字段,如果字段类型是 String,就检查 String 的长度,如果字段是 int,就检查 int 的范围。

1、定义注解Range

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

// 下面定义注解,必须设置@Target 和 @Retetion
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD) // 可以把注解参数变为数组 @Target({ElementType.FIELD,ElementType.METHOD})
public @interface Range {
    int min() default Integer.MIN_VALUE;  // 最小值,默认为最小整数值
    int max() default Integer.MAX_VALUE;  // 最大值,默认为最大整数值
}

# 元注解,一些可以修饰其他注解的注解,称为元注解(meta annotation)。
常用的元注解有
    - @Target 可以定义 Annotation 能够被应用于源码的哪些位置
        -   类或接口:ElementType.TYPE;
        -   字段:ElementType.FIELD;
        -   方法:ElementType.METHOD;
        -   构造方法:ElementType.CONSTRUCTOR;
        -   方法参数:ElementType.PARAMETER。
     
    - @Retention 定义了 Annotation 的声明周期
        -   仅编译期:RetentionPolicy.SOURCE;
        -   仅class文件:RetentionPolicy.CLASS;
        -   运行期:RetentionPolicy.RUNTIME。
        如果@Retention 不存在,则该注解默认为Class,但是通常我们定义的注意都是RUNTIME,所以请务必加上这个注解。
    
    - @Repeatable 可以定义 Annotation 是否可重复
        定义多个注解之后,我们可以这样使用
        @Report(type=1, level="debug")
        @Report(type=2, level="warning")
        public class Hello {}
        
    - @Inherited 定义子类是否可继承父类定义的 Annotation,@Inherited 仅针对@Target(ElementType.TYPE)类型的 annotation 有效,并且仅针对 class 的继承,对 interface 的继承无效。
    

2、定义Java Bean

public class MyBen {
    public static void main(String[] args) throws IllegalAccessException {
        MyBen my = new MyBen();
        my.setName("chennan");
        System.out.println(my.getName());
        my.setAge(3);
        RangeValidator.validate(my);
        /*
        * RangeValidator.validate(my); 这个就是我们生成的拦截器或者校验工具,将实例对象my传入拦截器中
        * 拦截器会获取实例对象my的字段方法,如果字段方法有@Range注解,则触发校验
        * */
    }

    @Range(min = 5,max = 10)
    public int age;

    @Range(min=5,max = 20)
    public String name;

    public String getName(){
        return this.name;
    }
    public void setName(String name){
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

3、定义拦截器RangeValidator

import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Stack;

public class RangeValidator {
    // 拦截器,用于校验长度。
    public static void validate(Object obj) throws IllegalAccessException {
        Class<?> cls = obj.getClass();
        Field[] fields = cls.getDeclaredFields(); // 获取要检查类的字段
        System.out.println(Arrays.toString(fields));
        for (Field field:fields){ // 遍历每一个字段,获取注解,再判断类型,然后再对比
            if (field.isAnnotationPresent(Range.class)){
                field.setAccessible(true);

                Range rangeAnnotation = field.getAnnotation(Range.class);
                /*
                * getAnnotation 方法获取指定注解类型的注解。
                * 通过这个方法,可以在运行时检查类、方法或字段上是否存在特定类型的注解,并获取注解的属性值。
                * 这对于实现反射和元数据处理非常有用。
                * */

                Object value = field.get(obj);
                /*
                * 1、先获取了class,然后利用反射获取class的所有字段信息。
                * 2、循环拿到每一个字段,然后用get方法,传入实例对象,来获取实例对象对应字段的值
                * */

                if (value != null){
                    if (value instanceof Integer){
                        int intValue = (int) value;
                        if (intValue < rangeAnnotation.min() || intValue > rangeAnnotation.max()){
                            throw new IllegalArgumentException("Field "+ field.getName() + " is out of range. 哈哈int"+ rangeAnnotation.min() + " " + rangeAnnotation.max());
                        }else if (value instanceof String){
                            String strValue = (String) value;
                            if(strValue.length() < rangeAnnotation.min() || strValue.length() > rangeAnnotation.max()){
                                throw new IllegalArgumentException("Field "+ field.getName() + " is out of range. 哈哈str"+ rangeAnnotation.min() + " " + rangeAnnotation.max());
                            }
                        }
                    }
                }
            }
        }

    }
}