java:@Repeatable注解使用

1 前言

java8新增了注解@Repeatable,在hibernate-validator的源码注解如@MAX、@NotNull等中,有@Repeatable注解的使用,源码示例如下:

/** Jakarta Bean Validation API** License: Apache License, Version 2.0* See the license.txt file in the root directory or <http://www.apache.org/licenses/LICENSE-2.0>.*/
package javax.validation.constraints;import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotNull.List;/*** The annotated element must not be {@code null}.* Accepts any type.** @author Emmanuel Bernard*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(List.class)
@Documented
@Constraint(validatedBy = { })
public @interface NotNull {String message() default "{javax.validation.constraints.NotNull.message}";Class<?>[] groups() default { };Class<? extends Payload>[] payload() default { };/*** Defines several {@link NotNull} annotations on the same element.** @see javax.validation.constraints.NotNull*/@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })@Retention(RUNTIME)@Documented@interface List {NotNull[] value();}
}

2 使用

参考hibernate-validator注解,使用@Repeatable:

2.1 新建注解RepeaDemo,暂时不添加@Repeatable:

package com.xiaoxu.tool.demo;import java.lang.annotation.*;@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeaDemo {String id();String name();
}

新建demo类:

package com.xiaoxu.tool.demo;import java.lang.reflect.Field;
import java.util.Arrays;/*** @author xiaoxu* @date 2022-05-17* spring_boot:com.xiaoxu.tool.demo.TestRepeatable*/
public class TestRepeatable {@RepeaDemo(id = "1001",name = "荔枝")private String fruit1;@RepeaDemo(id = "1002",name = "葡萄")private String fruit2;public static void demo1(){Class<?> a = TestRepeatable.class;Field[] fruits = a.getDeclaredFields();Arrays.stream(fruits).forEach(f->{if(f.isAnnotationPresent(RepeaDemo.class)){RepeaDemo anno = f.getAnnotation(RepeaDemo.class);String id = anno.id();String name = anno.name();System.out.printf("水果id:%s,水果名称:%s%n",id,name);}});}public static void main(String[] args) {demo1();}
}

执行结果如下:

水果id:1001,水果名称:荔枝
水果id:1002,水果名称:葡萄

但是问题是,如果希望在字段上增加多个注解,那么会提示Duplicate annotation.错误:

于是考虑新增一个RepeaDemos注解,用于存储@RepeaDemo注解数组,就可以达到多个注解的使用了,如下:

package com.xiaoxu.tool.demo;import java.lang.annotation.*;@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeaDemos {RepeaDemo[] repeaDemos();
}

修改TestRepeatable代码:

package com.xiaoxu.tool.demo;import java.lang.reflect.Field;
import java.util.Arrays;/*** @author xiaoxu* @date 2022-05-17* spring_boot:com.xiaoxu.tool.demo.TestRepeatable*/
public class TestRepeatable {@RepeaDemos(repeaDemos = {@RepeaDemo(id = "1001",name = "荔枝"),@RepeaDemo(id = "1003",name = "沃柑")})private String fruit1;@RepeaDemo(id = "1002",name = "葡萄")private String fruit2;public static void demo1(){Class<?> a = TestRepeatable.class;Field[] fruits = a.getDeclaredFields();Arrays.stream(fruits).forEach(f->{if(f.isAnnotationPresent(RepeaDemo.class)){RepeaDemo anno = f.getAnnotation(RepeaDemo.class);String id = anno.id();String name = anno.name();System.out.printf("水果id:%s,水果名称:%s%n",id,name);}});}public static void demo2(){Class<?> a = TestRepeatable.class;Field[] fruits = a.getDeclaredFields();Arrays.stream(fruits).forEach(f->{if(f.isAnnotationPresent(RepeaDemos.class)){RepeaDemos anno = f.getAnnotation(RepeaDemos.class);RepeaDemo[] res= anno.repeaDemos();Arrays.stream(res).forEach(r-> System.out.printf("水果id:%s,水果名称:%s%n",r.id(),r.name()));}if(f.isAnnotationPresent(RepeaDemo.class)){RepeaDemo anno = f.getAnnotation(RepeaDemo.class);String id = anno.id();String name = anno.name();System.out.printf("水果id:%s,水果名称:%s%n",id,name);}});}public static void main(String[] args) {demo2();}
}

执行结果如下:

水果id:1001,水果名称:荔枝
水果id:1003,水果名称:沃柑
水果id:1002,水果名称:葡萄

2.2 @Repeatable注解使用:

对于上述注解使用,@Repeatable注解的作用就是使得@RepeaDemo注解可以多个添加在字段上,而最外层无须包裹@RepeaDemos注解,当然,@RepeaDemos注解任然需要保留,修改如下:

修改@RepeaDemos注解(注意@RepeaDemos注解,必须改为value()才可以):

package com.xiaoxu.tool.demo;import java.lang.annotation.*;@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RepeaDemos {RepeaDemo[] value();
}

修改@RepeaDemo注解,增加@Repeatable,参数为RepeaDemos.class:

package com.xiaoxu.tool.demo;import java.lang.annotation.*;@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(RepeaDemos.class)
@Documented
public @interface RepeaDemo {String id();String name();
}

修改demo类:

package com.xiaoxu.tool.demo;import java.lang.reflect.Field;
import java.util.Arrays;/*** @author xiaoxu* @date 2022-05-17* spring_boot:com.xiaoxu.tool.demo.TestRepeatable*/
public class TestRepeatable {//    @RepeaDemos(value = {//        @RepeaDemo(id = "1001",name = "荔枝"),
//        @RepeaDemo(id = "1003",name = "沃柑")
//    })@RepeaDemo(id = "1001",name = "荔枝")@RepeaDemo(id = "1003",name = "沃柑")private String fruit1;@RepeaDemo(id = "1002",name = "葡萄")private String fruit2;public static void demo1(){Class<?> a = TestRepeatable.class;Field[] fruits = a.getDeclaredFields();Arrays.stream(fruits).forEach(f->{if(f.isAnnotationPresent(RepeaDemo.class)){RepeaDemo anno = f.getAnnotation(RepeaDemo.class);String id = anno.id();String name = anno.name();System.out.printf("水果id:%s,水果名称:%s%n",id,name);}});}public static void demo2(){Class<?> a = TestRepeatable.class;Field[] fruits = a.getDeclaredFields();Arrays.stream(fruits).forEach(f->{if(f.isAnnotationPresent(RepeaDemos.class)){RepeaDemos anno = f.getAnnotation(RepeaDemos.class);RepeaDemo[] res= anno.value();Arrays.stream(res).forEach(r-> System.out.printf("水果id:%s,水果名称:%s%n",r.id(),r.name()));}if(f.isAnnotationPresent(RepeaDemo.class)){RepeaDemo anno = f.getAnnotation(RepeaDemo.class);String id = anno.id();String name = anno.name();System.out.printf("水果id:%s,水果名称:%s%n",id,name);}});}public static void main(String[] args) {demo2();}
}

执行效果如下:

水果id:1001,水果名称:荔枝
水果id:1003,水果名称:沃柑
水果id:1002,水果名称:葡萄

可见,如下两种方式,获取的结果是一致的,其实@Repeatable注解就是一种语法糖(类似于python的装饰器语法糖等等),本质上在java编译时,使用如下的第2种注解方式,等同于使用第1种:

 //1:@RepeaDemos(value = {@RepeaDemo(id = "1001",name = "荔枝"),@RepeaDemo(id = "1003",name = "沃柑")})//2:@RepeaDemo(id = "1001",name = "荔枝")@RepeaDemo(id = "1003",name = "沃柑")

2.3 小结

1 @Repeatable注解使用前,需先增加一个注解的属性值为子注解数组,且名称为value()的父注解;
2 @Repeatable注解需要在子注解上标注,且@Repeatable注解的值为父注解class;
3 @Repeatable注解本质上是一种语法糖。

java:@Repeatable注解使用相关推荐

  1. java repeatable_java8 新增的@Repeatable注解

    * java8 新增的@Repeatable注解,其实只是语法糖而已. * java8 注解的 {@linkRepeatAnn} 类与 {@linkAnnotations}是等价的. * 新注解讲语法 ...

  2. 通俗易懂地讲解 Java 的注解

    作者 l 会点代码的大叔(CodeDaShu) 今天,我们来聊聊 Java 的注解. 01 注解的概念 Annotation(注解):先看看官方给出的概念,注解是 Java 提供的一种对元程序中元素关 ...

  3. 玩转java(Android)注解

    2019独角兽企业重金招聘Python工程师标准>>> 玩转java(Android)注解 1. java标准(原生)注解概览 Java API 中,在java.lang.java. ...

  4. JAVA元注解@interface详解(@Target,@Documented,@Retention,@Inherited)。

    jdk1.5起开始提供了4个元注解,用来定义自定义注解的注解,它们分别是: @Target 指定注解使用的目标范围(类.方法.字段等),其参考值见类的定义:java.lang.annotation.E ...

  5. c JAVA 注解,Java元注解作用及使用

    元注解是负责对其它注解进行说明的注解,自定义注解时可以使用元注解.Java 5 定义了 4 个注解,分别是 @Documented.@Target.@Retention 和 @Inherited.Ja ...

  6. java threadsafe 注解_Java 注解详解

    什么是注解 Annotation 中文译过来就是注解.标释的意思,在 Java 中注解是一个很重要的知识点,但经常还是有点让新手不容易理解.而新手很难理解的主要原因是一些技术文档里的专业术语和名词不太 ...

  7. JAVA元注解@interface详解(@Target,@Documented,@Retention,@Inherited)

    转载自 JAVA元注解@interface详解(@Target,@Documented,@Retention,@Inherited) jdk1.5起开始提供了4个元注解,用来定义自定义注解的注解,它们 ...

  8. Java元注解作用及使用

    元注解是负责对其它注解进行说明的注解,自定义注解时可以使用元注解.Java 5 定义了 4 个注解,分别是 @Documented.@Target.@Retention 和 @Inherited.Ja ...

  9. Java之注解的定义及使用

    Java的注解在实际项目中使用得非常的多,特别是在使用了Spring之后. 本文会介绍Java注解的语法,以及在Spring中使用注解的例子. 注解的语法 注解的例子 以Junit中的@Test注解为 ...

最新文章

  1. dell笔记本耳机怎么设置_win10笔记本怎么设置合上盖子不休眠
  2. linux应用日志类型,linux日志分析
  3. 使用canvas实现擦玻璃效果
  4. java方法能不能继承方法_关于java:方法链接+继承不能很好地一起玩吗?
  5. Windows配置tomcat环境
  6. python保存csv_在python中修改和保存csv文件
  7. 看完豁然开朗!mysql集群搭建linux
  8. 忘记准考证号获取四六级成绩的方法
  9. IEEE Transactions on Intelligent Transportation Systems投稿记录
  10. 解决使用shutil.rmtree无法删除文件夹的方案
  11. 软件开发工具——理论篇
  12. 什么是云服务举例说明_什么叫云服务举例说明(云服务器实例是什么)
  13. AndroidStudio 设置全局查找快捷键
  14. 文本语音阅读器——Python简单实现
  15. IDEA超实用方法类注释模板大全
  16. html随机显示图片,DUX主题实现缩略图随机显示
  17. mac上linux系统字符界面,MAC中Linux常用操作命令
  18. zan-admin响应式简单布局
  19. 全自研客户端技术方案:优酷跨端动态模板引擎优酷跨端动态模板引擎
  20. 原来可以这样中文转码

热门文章

  1. Vikki与您共享系列一:软件提供的是服务
  2. 【情感打分+情感判定+词云图】python情感分析李子柒频道视频热门英文评论
  3. 阿蒙:程序员创业如何寻找优秀的合作伙伴?
  4. 利用js的数组制作二级联动
  5. pnp计算机,PNP 文件扩展名: 它是什么以及如何打开它?
  6. 基于卷积神经网络的多目标图像检测研究(一)
  7. 浮动路由(CISCO)
  8. 基于live555的流媒体代理转发服务器
  9. 「春招系列」30张图理解HTTP在面试中所有会出现的题
  10. 记第一次C++面试与经验分享