专栏首页后端Coderjava自定义注解的使用

java自定义注解的使用

在开始讲如何实现自定义注解之前,我们先唠唠嗑,其实我们刚开始学java的时候,如何创建一个对象,这本身就是一个难题,有的人或许会直接说直接new一个,或者通过反射机制直接创建一个类的实例对象进行对对象实例的操作。

不曾想,每个人都是这样经历过来的,不知你是否还记得在spring的xml配置文件里如何配置对象的场景?或许依然记忆犹新,或许早已抛开在脑后,等等吧。后面spring出现了通过注解的方式去注入一个实例,这或许解放了很多我这样的码农双手,坏笑。

通过上面的故事,我们一步一步走进了注解的视野里面,既然熟知注解的应用,接下来我们还是看下如何实现自己的注解吧。

在看示例程序之前,我们看下是如何自定义一个注解的,我们都知道定义一个类使用class标识符进行修饰,定义一个接口使用interface标识进行修饰,那么同样使用@interface标识进行修饰的就是自定义注解。

public @interface ValidatorString {
}

好了,我们既然知道了如何自定义一个自己的注解,接下来我们看下我们的示例程序吧。

package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorString {
    /**
     * 判断是否为空
     * @return  boolean值
     */
    boolean isEmpty();
}

上面我们实现了一个对字符串进行判空操作的自定义注解,在看下面的程序之前,我们还是看下上面的各个元注解的含义好了。

什么叫做元注解呢?其实这个词语可以不必深究,因为就算你懂了,对你来说也没什么意思,元注解就是修饰注解的注解,是不是有点绕?坏笑。

@Documented:这个注解的含义就是可以包含在javadoc中的。

@Inherited:这个注解的含义就是允许子类继承父类的注解的。

@Target:这个注解的含义就是说这个注解的作用范围,标识这个注解可以用在什么地方。比如说我们可以作用在类上,接口上,字段上,方法上等等等。

@Retention:这个注解的含义就是说注解的保存策略,比如说注解的生效范围,有的可能在编译器生效,有的可能只存在源码级别生效,但是大部分我们都是设置为运行期生效,毕竟我们就是在程序运行期间进行使用的嘛,不知道这段话,你懂了没有。

好了,下面我们需要定义一个类来验证我们的注解是否可行。

package com.wpw.springboot;

public class User {
    @ValidatorString(isEmpty = false)
    private String username;
    @ValidatorMax(max = 120)
    @ValidatorMin(min = 1)
    private int age;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public int getAge() {
        return age;
    }

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

在上面的示例程序中,我们使用了我们自己的自定义注解对字符串username进行了限定,同样我们使用了下面的注解进行对age属性进行了最大最小的限定。

package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public  @interface ValidatorMax {
    /**
     * 校验最大值
     * @return  最大值
     */
    int max();
}
package com.wpw.springboot;

import java.lang.annotation.*;

@Documented
@Inherited
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface ValidatorMin {
    /**
     * @return  返回最小值
     */
    int min();
}

其实上面的是可以放到一个自定义注解里面的。由于文章都有注释,详细解析就不再说明了,你应该都会明白的。

接下来我们就是要写一个自定义解析器,对我们的自定义注解的内容进行解析。

package com.wpw.springboot;

import java.lang.reflect.Field;
import java.util.Objects;

public class ValidatorResolver {
    public static <T> boolean validator(T t) throws IllegalAccessException {
        Field[] fields = t.getClass().getDeclaredFields();
        for (Field field : fields) {
            field.setAccessible(true);
            ValidatorString validatorString = field.getAnnotation(ValidatorString.class);
            ValidatorMax validatorMax = field.getAnnotation(ValidatorMax.class);
            ValidatorMin validatorMin = field.getAnnotation(ValidatorMin.class);
            //判断字符是否为空
            if (Objects.nonNull(validatorString) && field.getType().equals(String.class)) {
                if (Objects.isNull(field.get(t)) || ((String) field.get(t)).length() <= 0) {
                    System.out.println(field.getName() + "不可以为空");
                    return false;
                }
            }
            if ((Objects.nonNull(validatorMax) || Objects.nonNull(validatorMin)) && field.getType().equals(Integer.class) &&
                    Objects.isNull(field.get(t))) {
                System.out.println(field.getName() + "字段不可以为空");
                return false;
            }
            //判断该字段是否为Integer或者int类型
            if (field.getType().equals(Integer.class) || field.getType() == int.class) {
                if (Objects.nonNull(validatorMax) && ((int) field.get(t)) > validatorMax.max()) {
                    System.out.println(field.getName() + "字段大于了最大值");
                    return false;
                }
                if (Objects.nonNull(validatorMin) && ((int) field.get(t) < validatorMin.min())) {
                    System.out.println(field.getName() + "字段小于了最小值");
                    return false;
                }
            }
        }
        return true;
    }
}

好了,上面的自定义注解的解析器就写完了,下面我们开始做个测试了,看下我们的自定义注解是否生效。

 public static void main(String[] args) throws IllegalAccessException {
        User user=new User();
        user.setUsername("backCoder");
        user.setAge(90);
        System.out.println(ValidatorResolver.validator(user));//true
    }

上面我们都是对对象user进行了合理的设置,接下来我们故意写个错误的看下是否可以达到我们想要的效果。

public static void main(String[] args) throws IllegalAccessException {
        User user=new User();
        user.setAge(90);
        System.out.println(ValidatorResolver.validator(user));
    }

当我们不设置username值时,我们看下控制台的输出语句。

username不可以为空
false

这就是我们在解析器里面输出的内容和返回的结果。

本文分享自微信公众号 - WwpwW(gh_245290c1861a),作者:后端Coder

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-11-19

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • java之StopWatch源码分析

    计时这个词语在生活中被应用的很普遍,体育竞赛时频繁出现的秒表,发令信号一经发出,秒表就在滴答滴答流转开始计时了,秒表此时的作用就是计时的代名词,在我们编写代码的...

    码农王同学
  • java高级进阶|定时器的分析

    以前写文章的时候忘了标记原创,导致最近整理文章的时候会发现不是原创的文章不给自己权限合入对应目录了,这也是自己后面慢慢开始注重这方面的积累了,读过我的文章的读者...

    码农王同学
  • LeetCode27|最长公共前缀

    5,总结,这道题想着是上周有时间总结输出来的,但是还是延迟了一个周,才将这道题总结输出出来,这道题就是一个对比的题,本质上利用了缓存这一原理,之前自己在写类似键...

    码农王同学
  • hdu1087

    @坤的
  • 07 Spring框架 依赖注入(四)基于注解的依赖注入

    前面几节我们都在使用xml进行依赖的注入,但是在实际的开发中我们往往偏爱于使用注解进行依赖注入,因为这样更符合我们人的思维,并且更加快捷,本节就来讲述Sprin...

    MindMrWang
  • 技术分享 | 实战 MySQL 8.0.17 Clone Plugin

    很神奇,5.7.17 和 8.0.17,连续两个17小版本都让人眼前一亮。前者加入了组复制(Group Replication)功能,后者加入了克隆插件(Clo...

    田帅萌
  • 微信小程序自定义 tabBar 踩坑实践

    创建一个与 /pages 的同级目录,命名为 /custom-tab-bar,注意目录层级与目录命名问题,不可用其他名称命名。

    江不知
  • Python绘制直方图案例一则

    Python小屋屋主
  • Python使用matplotlib绘制龟兔赛跑中兔子和乌龟的行走轨迹

    Python小屋屋主
  • 数据库三大范式

    第一范式 第一范式(1NF)要求数据库表的每一列都是不可分割的基本数据项,同一列中不能有多个值。 若某一列有多个值,可以将该列单独拆分成一个实体,新实体和原实...

    大闲人柴毛毛

扫码关注云+社区

领取腾讯云代金券