文章目录
前言1 自定义注解 NotNull2 使用接口实现 NotNull注解的功能3 测试效果4 控制台的异常栈信息前言
关于参数校验,一直是个困扰人的事。这次使用注解+反射,实现自己的非空校验。
1 自定义注解 NotNull
package com.example;import java.lang.annotation.*;/*** 注解非空,用于校验实例变量不能为空。实现逻辑在 Check接口中。*/@Target({ElementType.FIELD})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface NotNull {/*** 错误信息描述*/String errorMsg();}
2 使用接口实现 NotNull注解的功能
package com.example;import java.lang.reflect.Field;/*** 所有要校验的类,实现这个接口*/public interface Check {/*** 校验参数*/default void doCheck() {final Field[] declaredFields = this.getClass().getDeclaredFields();for (Field declaredField : declaredFields) {// 当前变量是这个 Check 接口的实现类、或有NotNull注解if (Check.class.isAssignableFrom(declaredField.getType()) || declaredField.isAnnotationPresent(NotNull.class)) {declaredField.setAccessible(true);deepCheck(declaredField);}}}private void deepCheck(Field declaredField) {try {final Object declaredFieldValue = declaredField.get(this);if (declaredFieldValue instanceof Check) {((Check) declaredFieldValue).doCheck();return;}if (declaredFieldValue == null && declaredField.isAnnotationPresent(NotNull.class)) {final NotNull notNull = declaredField.getAnnotation(NotNull.class);final String errorMsg = notNull.errorMsg();throw new IllegalArgumentException(errorMsg);}} catch (IllegalAccessException e) {e.printStackTrace();}}}
3 测试效果
package com.example;public class MainClient implements Check {@NotNull(errorMsg = "check2不能为空")private Check2 check2;@NotNull(errorMsg = "aaa")private String aaa;public static void main(String[] args) {MainClient client = new MainClient();client.check2 = new Check2();client.doCheck();}}class Check2 implements Check {@NotNull(errorMsg = "aaa不能为空")private String aaa="";}
4 控制台的异常栈信息
Exception in thread "main" java.lang.IllegalArgumentException: aaaat com.example.Check.deepCheck(Check.java:31)at com.example.Check.doCheck(Check.java:16)at com.example.MainClient.main(MainClient.java:14)