java注解

介绍

java 1.5引入了注解(annotation),注解类似注释,不同的是注解除了提供代码说明,
还能实现程序的逻辑功能,在很多java框架中都得到了广发的应用。

元注解

元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。

  • @Target 修饰了注解使用范围 可以是类(TYPE),方法(METHOD),字段(FIELD),构造函数(CONSTRUCTOR),参数(PARAMETER),局部变量(LOCAL_VARIABLE),包(PACKAGE)
  • @Retention 修饰了注解存在的时间 SOURCE 只在源码中出现,CLASS 只在Class文件可以看见 RUNTIME 运行时也可以看见
  • @Documented 用来修饰注解是否出现在API中
  • @Inherited 是否会被子类继承 注解正常只出现在父类 子类不继承 加上这个标记 子类也能获得注解

示例代码

给类付上额外的信息

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ClassAnno {
    String value() default "类注解";
}

@ClassAnno("Test类")
public class Test {

}

public class Main {

    public static void main(String ...args){
        ClassAnno classAnno=Test.class.getAnnotation(ClassAnno.class);
        if(classAnno!=null){
            System.out.println(classAnno.value());
        }
    }
}

测试方法

  • 去掉Test类上的注解 查看结果
  • 去掉Test类上注解的值 查看结果

注解应用 验证类

一个验证接口

/**
 * 验证接口
 * @param <T> 值类型
 * @param <A> 注解类型
 */
public interface Validator<T,A> {

    /**
     * 验证方法
     * @param value 值
     * @param anno  注解
     * @return  错误信息 如果是null表示无错误
     */
    String validate(T value,A anno);
}

实现一个注解和验证接口实现类的绑定

/**
 * 绑定注解和验证类
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorBind {
    /**
     * 验证类
     * @return
     */
    Class validator();
}

实现一个接受验证结果的类

/**
 * 验证结果
 */
public class ValidatorResult {
    /**
     * 错误信息
     */
    private String message;
    /**
     * 字段名称
     */
    private String fieldName;
    /**
     * 字段路径
     */
    private String fieldPath;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getFieldName() {
        return fieldName;
    }

    public void setFieldName(String fieldName) {
        this.fieldName = fieldName;
    }

    public String getFieldPath() {
        return fieldPath;
    }

    public void setFieldPath(String fieldPath) {
        this.fieldPath = fieldPath;
    }
}

实现一个验证工具

public class ValidatorUtil {

    /**
     * 获取所有字段
     * @param clz
     */
    public static List<Field> getAllField(Class clz){
        Field[] declaredFields = clz.getDeclaredFields();
        Field[] fields=clz.getFields();
        List<Field> fieldList=new ArrayList<>(fields.length+declaredFields.length);
        for(int i=0;i<declaredFields.length;i++){
            declaredFields[i].setAccessible(true);
            fieldList.add(declaredFields[i]);
        }
        for(int i=0;i<fields.length;i++){
            fieldList.add(fields[i]);
        }
        return fieldList;
    }

    /**
     * 验证对象的某个字段是否符合规则
     * @param field 字段
     * @param object 对象
     * @param results 错误结果存储
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private static boolean validatorField(Field field, Object object,List<ValidatorResult> results) throws IllegalAccessException, InstantiationException {
        Annotation[] annos = field.getAnnotations();
        for(Annotation annotation:annos){
            ValidatorBind validatorBind=annotation.annotationType().getAnnotation(ValidatorBind.class);
            if(validatorBind!=null){
               Validator validator= (Validator) validatorBind.validator().newInstance();
               String msg=validator.validate(field.get(object),annotation);
               if(msg!=null){
                   ValidatorResult validatorResult=new ValidatorResult();
                   validatorResult.setFieldName(field.getName());
                   validatorResult.setMessage(msg);
                   results.add(validatorResult);
                   return false;
               };
            }
        }
        return true;
    }

    /**
     * 验证对象
     * @param object
     * @return 错误结果合集
     */
    public static List<ValidatorResult> validator(Object object){
        //返回结果
        List<ValidatorResult> results=new ArrayList<>();
        Class clz=object.getClass();
        List<Field> fields=getAllField(clz);
        for(Field field:fields){
            try {
                validatorField(field,object,results);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
        return results;
    }
}

上面一个验证框架就完成了
下面是增加验证功能
增加一个NotNull验证

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@ValidatorBind(validator = NotNullValidator.class)
@interface NotNull {
    String msg() default "不能为空";
}

实现类

/**
 * 验证Object不是NULL
 */
public class NotNullValidator implements Validator<Object,NotNull> {

    /**
     *  验证不能为NULL
     * @param value 值 Object类型
     * @param anno  注解 NotNull注解
     * @return
     */
    @Override
    public String validate(Object value, NotNull anno) {
        if(value==null){
            return anno.msg();
        }
        return null;
    }
}

增加正则验证

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@ValidatorBind(validator = PatternValidator.class)
public @interface Pattern {
    String regexp() default "";
    String msg() default "不符合正则规则";
}

实现正则验证规则

public class PatternValidator implements Validator<String,Pattern> {
    @Override
    public String validate(String value, Pattern anno) {
        String regexp=anno.regexp();
        if(!RegExp.test(regexp,value)){
            return anno.msg();
        }
        return null;
    }
}

测试类

class A {
    @NotNull
    @Pattern(regexp = "^\\d+$",msg = "必须是纯数字")
    String name;
}

public class Main {

    public static void main(String ...args){
        A a=new A();
        a.name="asd";
        List<ValidatorResult> list = ValidatorUtil.validator(a);
        if(list.isEmpty()){
            System.out.println("通过验证");
        }else{
            for(ValidatorResult result:list) {
                System.out.println(result.getFieldName()+' '+result.getMessage());
            }
        }
    }
}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容

  • 本文章涉及代码已放到github上annotation-study 1.Annotation为何而来 What:A...
    zlcook阅读 29,109评论 15 116
  • 内容概要 Annotation的概念 Annotation的作用 Annotation的分类 系统内置注解 元注解...
    DevinZhang阅读 4,142评论 0 28
  • 介绍 java 1.5引入了注解(annotation),注解类似注释,不同的是注解除了提供代码说明,还能实现程序...
    Charon_Pluto阅读 412评论 0 1
  • 介绍 java 1.5引入了注解(annotation),注解类似注释,不同的是注解除了提供代码说明,还能实现程序...
    代码界的扫地僧阅读 234评论 0 0
  • 有多久没哭过了,此时此刻,感觉自己受委屈了,眼泪就自己掉下来了,虽然不似以前汹涌,但是很难过,因为再也不会有那个在...
    d5ebe78a80c1阅读 220评论 0 0