Java的@Repeatable注解使用詳細(xì)解析
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
暫時(shí)不添加@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類(lèi):
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(); } }
執(zhí)行結(jié)果如下:
水果id:1001,水果名稱:荔枝
水果id:1002,水果名稱:葡萄
但是問(wèn)題是,如果希望在字段上增加多個(gè)注解,那么會(huì)提示Duplicate annotation.錯(cuò)誤:
于是考慮新增一個(gè)RepeaDemos注解,用于存儲(chǔ)@RepeaDemo注解數(shù)組,就可以達(dá)到多個(gè)注解的使用了,如下:
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(); } }
執(zhí)行結(jié)果如下:
水果id:1001,水果名稱:荔枝
水果id:1003,水果名稱:沃柑
水果id:1002,水果名稱:葡萄
2.2 @Repeatable注解使用
對(duì)于上述注解使用,@Repeatable注解的作用就是使得@RepeaDemo注解可以多個(gè)添加在字段上,而最外層無(wú)須包裹@RepeaDemos注解,當(dāng)然,@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,參數(shù)為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類(lèi):
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(); } }
執(zhí)行效果如下:
水果id:1001,水果名稱:荔枝
水果id:1003,水果名稱:沃柑
水果id:1002,水果名稱:葡萄
可見(jiàn),如下兩種方式,獲取的結(jié)果是一致的,其實(shí)@Repeatable注解就是一種語(yǔ)法糖(類(lèi)似于python的裝飾器語(yǔ)法糖等等),本質(zhì)上在java編譯時(shí),使用如下的第2種注解方式,等同于使用第1種:
//1: @RepeaDemos(value = { @RepeaDemo(id = "1001",name = "荔枝"), @RepeaDemo(id = "1003",name = "沃柑") }) //2: @RepeaDemo(id = "1001",name = "荔枝") @RepeaDemo(id = "1003",name = "沃柑")
2.3 小結(jié)
1 @Repeatable注解使用前,需先增加一個(gè)注解的屬性值為子注解數(shù)組,且名稱為value()的父注解;
2 @Repeatable注解需要在子注解上標(biāo)注,且@Repeatable注解的值為父注解class;
3 @Repeatable注解本質(zhì)上是一種語(yǔ)法糖。
到此這篇關(guān)于Java的@Repeatable注解使用詳細(xì)解析的文章就介紹到這了,更多相關(guān)@Repeatable注解的使用內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java并發(fā)編程中的CyclicBarrier線程屏障詳解
這篇文章主要介紹了Java并發(fā)編程中的CyclicBarrier線程屏障詳解,2023-12-12Java使用@Retryable注解實(shí)現(xiàn)HTTP請(qǐng)求重試
HTTP調(diào)用是Java應(yīng)用與外部API進(jìn)行交互時(shí)重要的訪問(wèn)方式之一,為了確保在遇到臨時(shí)性問(wèn)題時(shí)能自動(dòng)重試,我們可以設(shè)計(jì)一個(gè)靈活的重試機(jī)制,在Java中,我們可以通過(guò)注解來(lái)實(shí)現(xiàn)這一功能,文將介紹如何使用注解@Retryable來(lái)實(shí)現(xiàn)HTTP調(diào)用的重試機(jī)制,需要的朋友可以參考下2024-10-10maven中no main manifest attribute的問(wèn)題解決
本文主要介紹了maven中no main manifest attribute的問(wèn)題解決,這個(gè)錯(cuò)誤通常意味著Spring Boot應(yīng)用在啟動(dòng)時(shí)遇到了問(wèn)題,下面就來(lái)具體介紹一下,感興趣的可以了解一下2024-08-08解決java.lang.ClassCastException的java類(lèi)型轉(zhuǎn)換異常的問(wèn)題
這篇文章主要介紹了解決java.lang.ClassCastException的java類(lèi)型轉(zhuǎn)換異常的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-09-09Calcite使用SQL實(shí)現(xiàn)查詢csv/json文件內(nèi)容
calcite可以支持文件系統(tǒng)的數(shù)據(jù)源適配, 其實(shí)官方已經(jīng)提供了相應(yīng)的能力, 其支持csv和json的查詢適配,下面我們就來(lái)看看Calcite如何使用SQL實(shí)現(xiàn)查詢csv/json文件內(nèi)容吧2025-01-01