(原创)JAVA注解应用——实现属性的自动检测

本文介绍如何利用Java注解实现对JavaBean属性的自动检测,包括必填项、长度限制及取值范围等验证规则。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、什么是注解

Annotation(注解)是JDK5.0及以后版本引入的新特性。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的,根据注解参数的个数,我们可以将注解分为:标记注解、单值注解、完整注解三类。它们都不会直接影响到程序的语义,只是作为注解(标识)存在,我们可以通过反射机制编程实现对这些元数据(用来描述数据的数据)的访问。

二、注解能做什么

Annotation提供了一种安全的类似注释的机制,为我们在代码中添加信息提供了一种形式化得方法,使我们可以在稍后某个时刻方便的使用这些数据(通过解析注解来使用这些数据),用来将任何的信息或者元数据与程序元素(类、方法、成员变量等)进行关联。其实就是更加直观更加明了的说明,这些说明信息与程序业务逻辑没有关系,并且是供指定的工具或框架使用的。Annotation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的申明语句中。

Annotation其实是一种接口。通过java的反射机制相关的API来访问Annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。Java语言解释器在工作时会忽略这些Annotation,因此在JVM中这些Annotation是“不起作用”的,只能通过配套的工具才能对这些Annotation类型的信息进行访问和处理。

三、使用注解实现JAVABEAN中属性的自动检测

我们要接下来实现的功能很简单,假设有这么一个场景:外部需要调用某系统接口实现某一功能,其中接口参数是用JavaBean进行传递,JavaBean中定义了几个属性,系统中对这几个属性有着严格的限制,比如:非空、长度限制、参数取值限制等等。

按照传统的方法,我们可能需要针对每个javabean中的每个属性都要写对应的逻辑的判断,设想一下,如果这个系统的接口有1000个,是不是我们应该事先1000个逻辑?NONONO,不需要,java注解功能可以很好的事先这个问题。

1.要实现上面的三个监测,我们需要定义三个不同的注解,代码如下:

 1 package com.maomq.testannotation.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * 必填项注解
11  * @author maomq
12  * @since 2013-08-29
13  */
14 @Retention(RetentionPolicy.RUNTIME)
15 @Target({ElementType.FIELD})
16 @Documented
17 public @interface Required {
18 
19 }
非空注解
 1 package com.maomq.testannotation.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * 元素长度范围注解
11  * @author maomq
12  * @since 2013-08-29
13  */
14 @Retention(RetentionPolicy.RUNTIME)
15 @Target({ElementType.FIELD})
16 @Documented
17 public @interface LengthLimitRange {
18 
19     static final int MIN_VALUE = 0;
20     
21     static final int MAX_VALUE = 255;
22     
23     public int minValue() default MIN_VALUE;
24     
25     public int maxValue() default MAX_VALUE;    
26 }
长度限制注解
 1 package com.maomq.testannotation.annotation;
 2 
 3 import java.lang.annotation.Documented;
 4 import java.lang.annotation.ElementType;
 5 import java.lang.annotation.Retention;
 6 import java.lang.annotation.RetentionPolicy;
 7 import java.lang.annotation.Target;
 8 
 9 /**
10  * 字符串范围注解
11  * @author maomq
12  * @since 2013-08-29
13  */
14 @Retention(RetentionPolicy.RUNTIME)
15 @Target({ElementType.FIELD})
16 @Documented
17 public @interface ArrayStringRange {
18     public String[] valueArray();
19 }
字符串取值范围注解

2.注解定义好了,下一步应该定义注解的判断逻辑,这里我们引入一个接口,它将定义所有的监测规则

 1 package com.maomq.testannotation.checker;
 2 
 3 import java.lang.reflect.Field;
 4 
 5 /**
 6  * 注解检测实现接口类
 7  * 
 8  * @author maomq
 9  * @since 2013-08-29
10  */
11 public interface FieldAnnotationChecker {
12 
13     /**
14      * 返回check结果
15      * 
16      * @param value
17      * @param field
18      * @return boolean
19      */
20     public boolean check(Object value, Field field);
21 }
 1 package com.maomq.testannotation.checker;
 2 
 3 import java.lang.reflect.Field;
 4 import java.util.Collection;
 5 import java.util.Map;
 6 
 7 /**
 8  * 注解检测实现类
 9  * @author maomq
10  * @since 2013-08-29
11  */
12 public class RequiredAnnotationChecker implements FieldAnnotationChecker {
13 
14     @Override
15     public boolean check(Object value, Field field) {
16         if (null == value)
17         {
18             System.out.println("The required value is null!");
19             return false;
20         }
21         
22         if (value instanceof String)
23         {
24             String strValue = (String) value;
25             if(strValue.isEmpty())
26             {
27                 System.out.println("The required value is null!");
28                 return false;
29             }
30         }
31         else if (value instanceof Collection<?>)
32         {
33             Collection<?> collValue = (Collection<?>) value;
34             if(collValue.isEmpty())
35             {
36                 System.out.println("The required value is null!");
37                 return false;
38             }
39         }
40         else if (value instanceof Map<?, ?>)
41         {
42              Map<?, ?> mapValue = ( Map<?, ?>) value;
43             if(mapValue.isEmpty())
44             {
45                 System.out.println("The required value is null!");
46                 return false;
47             }
48         }
49         return true;
50     }
51 
52 }
必填项监测实现类
 1 package com.maomq.testannotation.checker;
 2 
 3 import java.lang.reflect.Field;
 4 import java.util.Collection;
 5 import java.util.Map;
 6 
 7 import com.maomq.testannotation.annotation.LengthLimitRange;
 8 
 9 /**
10  * 注解检测实现类
11  * 
12  * @author maomq
13  * @since 2013-08-29
14  */
15 public class LengthLimitRangeAnnotationChecker implements
16         FieldAnnotationChecker {
17 
18     @Override
19     public boolean check(Object value, Field field) {
20         if (null == value) {
21             System.out.println("The value is null or empty!");
22             return true;
23         }
24 
25         LengthLimitRange lengthRange = field
26                 .getAnnotation(LengthLimitRange.class);
27 
28         int maxValue = lengthRange.maxValue();
29 
30         int minValue = lengthRange.minValue();
31 
32         if (value instanceof String) {
33             String strValue = (String) value;
34             if (strValue.length() > maxValue || strValue.length() < minValue) {
35                 System.out
36                         .println("The input value is out of the value limit range!");
37                 return false;
38             }
39         } else if (value instanceof Collection<?>) {
40             Collection<?> collValue = (Collection<?>) value;
41             if (collValue.size() > maxValue || collValue.size() < minValue) {
42                 System.out
43                         .println("The input value is out of the value limit range!");
44                 return false;
45             }
46         } else if (value instanceof Map<?, ?>) {
47             Map<?, ?> mapValue = (Map<?, ?>) value;
48             if (mapValue.values().size() > maxValue
49                     || mapValue.values().size() < minValue) {
50                 System.out
51                         .println("The input value is out of the value limit range!");
52                 return false;
53             }
54         }
55         return true;
56     }
57 
58 }
长度限制检测实现类
 1 package com.maomq.testannotation.checker;
 2 
 3 import java.lang.reflect.Field;
 4 
 5 import com.maomq.testannotation.annotation.ArrayStringRange;
 6 
 7 /**
 8  * 注解检测实现类
 9  * 
10  * @author maomq
11  * @since 2013-08-29
12  */
13 public class ArrayStringRangeAnnotationChecker implements
14         FieldAnnotationChecker {
15 
16     @Override
17     public boolean check(Object value, Field field) {
18         if (null == value) {
19             System.out.println("The value is null or empty!");
20             return true;
21         }
22 
23         ArrayStringRange arrayRange = field
24                 .getAnnotation(ArrayStringRange.class);
25 
26         String[] strArray = arrayRange.valueArray();
27 
28         if (value instanceof String && strArray.length > 0) {
29             for (String strTemp : strArray) {
30                 if (strTemp.equalsIgnoreCase(value.toString())) {
31                     return true;
32                 }
33             }
34             System.out.println("The input value is out of the value range!");
35             return false;
36         }
37 
38         return true;
39     }
40 
41 }
字符串取值范围实现类

3.检测逻辑也完成了,我们是针对每个JAVABEAN中的属性,因此,不可避免的需要一个Util类获取JavaBean中的属性,上代码:

  1 package com.maomq.testannotation;
  2 
  3 import java.lang.annotation.Annotation;
  4 import java.lang.reflect.Field;
  5 import java.util.ArrayList;
  6 import java.util.HashMap;
  7 import java.util.List;
  8 import java.util.Map;
  9 
 10 import com.maomq.testannotation.annotation.ArrayStringRange;
 11 import com.maomq.testannotation.annotation.LengthLimitRange;
 12 import com.maomq.testannotation.annotation.Required;
 13 import com.maomq.testannotation.checker.ArrayStringRangeAnnotationChecker;
 14 import com.maomq.testannotation.checker.FieldAnnotationChecker;
 15 import com.maomq.testannotation.checker.LengthLimitRangeAnnotationChecker;
 16 import com.maomq.testannotation.checker.RequiredAnnotationChecker;
 17 
 18 /**
 19  * 注解检测测试类
 20  * @author maomq
 21  * @since 2013-08-29
 22  */
 23 public class AnnotationCheckerUtil {
 24 
 25     private static Map<Class<?>, FieldAnnotationChecker> holder = new HashMap<Class<?>, FieldAnnotationChecker>();
 26     
 27     static {
 28         holder.put(Required.class, new RequiredAnnotationChecker());
 29         holder.put(LengthLimitRange.class, new LengthLimitRangeAnnotationChecker());
 30         holder.put(ArrayStringRange.class, new ArrayStringRangeAnnotationChecker());
 31     }
 32     
 33     /**
 34      * 获取Bean中所有的属性
 35      * @param clazz
 36      * @param fieldList
 37      */
 38     private static void getAllField(Class<?> clazz, List<Field> fieldList)
 39     {
 40         if (fieldList == null)
 41         {
 42             fieldList = new ArrayList<Field>();
 43         }
 44         
 45         Field[] fieldArray = clazz.getDeclaredFields();        
 46         for (Field fieldTemp : fieldArray)
 47         {
 48             fieldList.add(fieldTemp);
 49         }
 50         
 51         Class<?> superClazz = clazz.getSuperclass();
 52         
 53         if(superClazz != Object.class)
 54         {
 55             getAllField(superClazz, fieldList);
 56         }
 57     }
 58     
 59     /**
 60      * 对传入的JAVABean属性进行检测(使用注解)
 61      * @param objParam
 62      * @return
 63      */
 64     public static boolean checkField(Object objParam)
 65     {
 66         List<Field> fieldList = new ArrayList<Field>();
 67         
 68         getAllField(objParam.getClass(), fieldList);
 69         
 70         if (fieldList == null || fieldList.isEmpty())
 71         {
 72             return true;
 73         }
 74         
 75         for (Field fieldTemp : fieldList)
 76         {
 77             fieldTemp.setAccessible(true);
 78             Object value = null;
 79             try {
 80                 value = fieldTemp.get(objParam);
 81             } catch (IllegalArgumentException e) {
 82                 e.printStackTrace();
 83             } catch (IllegalAccessException e) {
 84                 e.printStackTrace();
 85             }
 86             
 87             Annotation[] fieldAnnotations = fieldTemp.getAnnotations();
 88             
 89             for(Annotation annotation : fieldAnnotations)
 90             {
 91                 FieldAnnotationChecker checker = holder.get(annotation.annotationType());
 92                 
 93                 if (null != checker && !checker.check(value, fieldTemp))
 94                 {
 95                     return false;
 96                 }
 97             }
 98         }
 99         
100         return true;
101     }
102 }

4.上面的工作都已经准备好了,现在可以测试一下了,首先定义一个javabean,并对其中需要检测的项目予以标注。

 1 package com.maomq.testannotation;
 2 
 3 import com.maomq.testannotation.annotation.ArrayStringRange;
 4 import com.maomq.testannotation.annotation.LengthLimitRange;
 5 import com.maomq.testannotation.annotation.Required;
 6 
 7 /**
 8  * 注解检测测试Bean类
 9  * @author maomq
10  * @since 2013-08-29
11  */
12 public class TestAnnotationBean {
13     //必填项检测
14     @Required
15     private String userId;
16     //必填,长度限制
17     @Required
18     @LengthLimitRange(minValue = 1, maxValue = 10)
19     private String userName;
20     //必填,取值范围限制
21     @Required
22     @ArrayStringRange(valueArray = {"football", "basketball", "swimming"})
23     private String habby;
24     
25     @SuppressWarnings(value = { "" })
26     private String description;
27 
28     public String getUserId() {
29         return userId;
30     }
31 
32     public void setUserId(String userId) {
33         this.userId = userId;
34     }
35 
36     public String getUserName() {
37         return userName;
38     }
39 
40     public void setUserName(String userName) {
41         this.userName = userName;
42     }
43 
44     public String getHabby() {
45         return habby;
46     }
47 
48     public void setHabby(String habby) {
49         this.habby = habby;
50     }
51 
52     public String getDescription() {
53         return description;
54     }
55 
56     public void setDescription(String description) {
57         this.description = description;
58     }
59 }

对上面的结果进行验证:

 1 package com.maomq.testannotation;
 2 
 3 /**
 4  * 注解检测测试类
 5  * @author maomq
 6  * @since 2013-08-29
 7  */
 8 public class TestAnnotation {
 9 
10 
11     public static void main(String[] args) {
12         TestAnnotationBean testAnnotationBean =new TestAnnotationBean();
13         
14         testAnnotationBean.setUserId("AAA");
15         testAnnotationBean.setUserName("12345678901");
16         testAnnotationBean.setHabby("walking");
17         testAnnotationBean.setDescription("ggsgsgsggs");
18         
19         if(!AnnotationCheckerUtil.checkField(testAnnotationBean))
20         {
21             System.out.println("Something is wrong!");
22         }
23     }
24 
25 }

输出如我们所料:habby不符合取值范围。

The input value is out of the value limit range!
Something is wrong!

四、小结

通过上面的例子我们可以大致了解注解的功能,如果需要深挖,建议大家学习一下Spring中对java注解功能应用,尤其是涉及事务控制的注解,真的很精髓,有兴趣的同学一定要抽时间学习一下,我这只是抛砖引玉,还望不吝赐教。

转载于:https://www.cnblogs.com/MarvinMao/p/3308514.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值