(原创)JAVA注解应用——实现属性的自动检测
一、什么是注解
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
(原创)JAVA注解应用——实现属性的自动检测相关推荐
- java 注解之省略属性名value
注解说明 解释:当使用注解,仅给value属性赋值时,此时value属性可以省略,只写属性值.
- java注解管理_JavaSpring【四、Bean管理注解实现】
前面讲的Bean相关配置全部是使用xml配置文件或实现接口来实现的,接下来将比较常用的用法,使用注解实现bean的注入和管理 内容包括 ClassPath扫描与组件管理 类的自动检测与注册bean c ...
- 深入理解java注解,java的4个元注解,注解三要素——定义、使用及读取执行,深入了解注解的底层本质,通过反射自动、动态获取注解所有属性以及属性值
1. 注解的定义 注解也是一种引用类型,编译后会生成 .class 字节码文件,作用就是为程序进行标识,不同注解能实现不同功能. 2. 注解的使用 3. 注解的读取执行 3.1 得不到注解信息,得到的 ...
- java注释日志打印_java 注解结合 spring aop 实现自动输出日志
auto-log auto-log 是一款为 java 设计的自动日志监控框架. 创作目的 经常会写一些工具,有时候手动加一些日志很麻烦,引入 spring 又过于大材小用. 所以希望从从简到繁实现一 ...
- 【java注解--使用注解封装自动拼接sql 】
java注解全面解析--实例 使用注解封装自动拼接sql 1.定义注解类 TableName: 用来注解 表名 ,拥有一个属性 value 将适用范围定为:TYPE Class, interfac ...
- java注解的开发_使用Java注解开发自动生成SQL
使用注解开发的好处就是减少配置文件的使用.在实际过程中,随着项目越来越复杂,功能越来越多,会产生非常多的配置文件.但是,当配置文件过多,实际维护过程中产生的问题就不容易定位,这样就会徒劳的增加工作量. ...
- java 注解 属性 类型_跟光磊学Java开发-Java注解
注解概述 注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记以后,java编译器.开发工具或者其他的框架就可以通过反射来获取类以及类的成员上的注解,然后通过作相应的处 ...
- java 注解 属性 类型_收藏!你一定要知道的Java8中的注解
全文共3002字,预计学习时长6分钟 海中有大量的注解! JavaSE 1.5中首次引入了注解.Java注解的目的是允许程序员编写关于其程序的元数据.在OracleDocs中,注解的定义是:" ...
- JAVA 类的继承(私有属性、自动转型)(入门级小白一看就懂)
JAVA 类的继承 文章目录 JAVA 类的继承 概述 1. 类的继承 1.1 引言 1.2 继承的定义 1.3 继承的规则 1.4 继承的格式 1.5 类的继承实例分析 2 私有属性 3 自动转型 ...
最新文章
- zipfile java 解压速率,使用java.util.ZipFile在同一层次中解压缩zipfile
- Redis 那些故障转移、高可用方案
- android消息池,回转寿司你一定吃过!——Android消息机制(构造)
- 《Swift 权威指南》——导读
- sqlite insert or replace 和 insert or ignore 用法
- ActiveMQ之消息服务器平台(发邮件)
- 【NOI OpenJudge1789】算24(搜索)
- latex插入参考文献--BibTex格式
- 在cmd指令看计算机位数,如何判断电脑是32位还是64位
- PDF文件如何插入图片?简单的操作方法
- 蜂鸣器音乐代码 天空之城_聆听《天空之城》
- flutter 文字颜色渐变
- 蝉知门户系统迁移到SAE平台-File模块扩展
- vue axios介绍
- golang各数值类型的最大最小值
- NIO效率高的原理之零拷贝与直接内存映射
- 维修iphone无服务器,iphone6P苹果手机无服务 居然被我修好了
- 中级微观经济学:Chap 7 显示偏好
- WiFi 4: 802.11n 白皮书
- php过滤ascii控制字符
热门文章
- Linux下的Memcache安装(含libevent的安装)
- http响应Last-Modified和ETag以及Apache和Nginx中的配置
- 《Effective C#中文版:改善C#程序的50种方法》读书笔记
- ASP.NET 2.0 读取配置文件[INI](示例代码下载)
- Linux下用C获取当前系统时间
- C和C++安全编码笔记:总结
- GitHub/GitLab/Gitee中项目互拷贝后仍保留历史提交记录的方法
- 概率论中均值、方差、标准差介绍及C++/OpenCV/Eigen的三种实现
- 行列式介绍及Eigen/OpenCV/C++的三种实现
- 一维码Codabar简介及其解码实现(zxing-cpp)