Java使用自定义注解并处理注解
目录
- 元注解
- 自定义注解
- 使用注解
- 处理注解的方法
- 测试使用
元注解
负责注解其他注解, Java定义了4个标准的meta-annotation类型, 他们被用来对其他annotation类型作说明
在 java.lang.annotation中可以找到
- @Target: 用于描述注解的范围(可以用在什么地方)
@Retention: 表示需要在什么级别保存该注解, 用于描述注解生命周期
- SOURCE < CLASS < RUNTIME
- @Document: 说明该注解是否包含在javadoc中
- @Inherited: 说明子类可以继承父类中该注解
@Target
最常用的元注解是@Target。使用@Target可以定义Annotation能够被应用于源码的哪些位置:
- 类或接口:
ElementType.TYPE
; - 字段:
ElementType.FIELD
; - 方法:
ElementType.METHOD
; - 构造方法:
ElementType.CONSTRUCTOR
; - 方法参数:
ElementType.PARAMETER
。
例如,定义注解 @MyAnnotation
可用在方法上,我们必须添加一个 @Target(ElementType.METHOD)
@Retention
另一个重要的元注解@Retention定义了Annotation的生命周期:
- 仅编译期:
RetentionPolicy.SOURCE
; - 仅class文件:
RetentionPolicy.CLASS
; - 运行期:
RetentionPolicy.RUNTIME
。
如果 @Retention
不存在,则该 Annotation
默认为 CLASS
。因为通常我们自定义的 Annotation
都是RUNTIME
,所以,务必要加上 @Retention(RetentionPolicy.RUNTIME)
这个元注解
/** * 定义一个注解 * Target: 表示我们的注解可以用在那些地方 * Retention: 表示注解在什么时候有效, 源码,class, 运行时 * Documented: 表示是否将我们的注解生成在JavaDoc中 * Inherited: 表示子类可以继承父类的注解 */
@Target(value = { ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@Documented
@Inherited
@interface MyAnnotation { }
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Range {
int min = 1;
int max = 7;
String msg = "长度不能小于" + Range.min + "或者大于" + Range.max;
String message() default msg;
int min() default min;
int max() default max;
}
使用注解
public class Person {
@Range
public String name;
@Range(min = 22, max = 50, message = "年龄不能小于22或者大于50")
public Integer age;
@Range(min = 3, max = 20, message = "长度不能小于3或者大于20")
public String city;
public Person() { }
public Person(String name, Integer age, String city) {
this.name = name;
this.age = age;
this.city = city;
}
// 此处省略 get/set ...
}
处理注解的方法
import java.lang.reflect.Field;
public class RangeCheck {
public static void check(Person person) throws IllegalAccessException, NullPointerException, IllegalArgumentException {
// 使用反射获取所有字段并遍历
for (Field field : person.getClass().getFields()) {
// 获取字段上的注解
Range range = field.getAnnotation(Range.class);
// 判断该字段是否使用了注解
if (range != null) {
// 获取字段的值, 这里可能会抛出 IllegalAccessException 访问权限异常
Object value = field.get(person);
System.out.println(field.getName() + " value--> " + value);
// 判断参数是否为空
if (value == null) {
throw new NullPointerException(field.getName() + "不能为空");
}
// String类型校验
else if (value instanceof String) {
// 如果是String类型就强转
String s = (String) value;
// 判断该值是否满足 @Range的min/max
if (s.length() < range.min() || s.length() > range.max()) {
throw new IllegalArgumentException("参数异常: " + field.getName() + range.message());
}
}
// Integer 类型校验
else if (value instanceof Integer) {
Integer i = (Integer) value;
if (i < range.min() || i > range.max()) {
throw new IllegalArgumentException("参数异常: " + field.getName() + range.message());
}
}
}
}
}
}
测试使用
class DemoApplicationTests {
public static void main(String[] args) {
Person person = new Person("Hello", 18, "深圳");
try {
RangeCheck.check(person);
}
// catch (IllegalAccessException e) {
// e.printStackTrace();
// }
// catch (IllegalArgumentException e) {
// e.printStackTrace();
// String message = e.getMessage();
// System.out.println("非法参数异常: --> " + message);
// }
// catch (NullPointerException e) {
// e.printStackTrace();
// String message = e.getMessage();
// System.out.println("空指针异常: --> " + message);
// }
catch (Exception e) {
e.printStackTrace();
if (e instanceof IllegalArgumentException) {
System.out.println("非法参数异常");
}
String message = e.getMessage();
System.out.println("所有异常: --> " + message);
}
}
}
/*******************某个字段不符合要求就会抛出异常********************/
java.lang.IllegalArgumentException: 参数异常: age年龄不能小于22或者大于50
at com.pro.pojo.RangeCheck.check(RangeCheck.java:35)
非法参数异常
所有异常: --> 参数异常: age年龄不能小于22或者大于50
2021-04-19 15:23:27.599 INFO 5604 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
还没有评论,来说两句吧...