[转载] Java中的元数据
参考链接: Java中的数据类型
元数据 也可能刚听到元数据你会有点陌生,其实任何一个使用过struts,ejb或者hibernate的开发人员都在不知不觉中使用元数据。所谓的元数据是指用来描述数据的数据,更通俗一点就是描述代码间关系,或者代码与其它资源(例如数据库表)之间内在联系得数据,对Struts来说就是struts-config.xml,对ejb来说就是ejb-jar.xml和厂商自定义的xml文件,对hibernate来说就是hbm文件。
但是现有的所有的以xml或者其它方式存在的元数据文件都有以下一些不便之处,第一,与被描述的文件分离,不利于一致性维护。第二,所有的这些文件都是ascii文件,没有显示的类型支持。基于元数据的广泛应用JDK1.5引入了Annotation的概念来描述元数据。使用过.net的开发人员一定很熟悉元数据的概念,元数据的概念在.net中成为Attribute。
在Java中元数据以标签的形式存在于Java代码中,元数据标签的存在并不影响程序代码的编译和执行,它只是被用来生成其它的文件或针在运行时知道被运行代码的描述信息。
综上所述:
第一, 元数据以标签的形式存在于Java代码中。
第二, 元数据描述的信息是类型安全的,即元数据内部的字段都是有明确类型的。
第三, 元数据需要编译器之外的工具额外的处理用来生成其它的程序部件。
第四, 元数据可以只存在于Java源代码级别,也可以存在于编译之后的Class文件内部。
如何创建元数据类型 像各种类有可以定义不同的类型一样,原数据也可以定义不同的类型。现在为止,Java语言中已经有了四种种的类型:对象类(class),枚举(enum),接口(interface)和元数据(@interface)。其实Java中的元数据的概念即吸收了.Net中Attribute的概念,有吸收了.net中property的概念。
Annotation定义
Annotation定义语法为:
modifiers @interface AnnotationName
{
element declaration1
element declaration2
}
modifiers指:public,protected,private或者默认值(什么也没有)。 一个元素的声明(element declaration)指: type elementName(); 或者 type elementName() default value;
例如下面代码定义了一个Annotation:
public @interface BugReport
{
String assignedTo() default "[none]";
int severity() = 0;
}
而可以通过以下的方式来声明Annotation:
AnnotationName(elementName1=value1, elementName2=value2, . . .)
元数声明的顺序没有关系,有默认值的元素的声明可以不列在初始化表中,此时他们使用默认值。例如,根据上述定义如下的三个Annotation的声明是等价的:
@BugReport(assignedTo="Harry", severity=0)
@BugReport(severity=0, assignedTo="Harry")
@BugReport(assignedTo="Harry")
那些只有一个元素,且元素名字叫value的Annotation可以使用如下的方式声明:
AnnotationName(“somevalue”)
Annotation中元素的类型必须是下述类型,或者这些类型的组合:
基本类型 (int, short, long, byte, char, double, float, or boolean)字符创(String)类(Class (可以是形如 Class<? extends MyClass>)的泛型类)枚举类型(enum)一个Annotation类型(annotation)上述类型构成的数组
如果Annotation的元素是数组,则可以做如下声明: @BugReport(. . ., reportedBy={“Harry”, “Carl”})
如果数组中只有一个元素时可以做如下声明:
@BugReport(. . ., reportedBy=“Joe”) // OK, same as {“Joe”} 如果Annotation元素类型为Annotation时可以做如下声明:
@BugReport(testCase=@TestCase(id=“3352627”), . . .)
可以对如下对象添加Annotation:
PackagesClasses (including enum)Interfaces (including annotation interfaces)MethodsConstructorsInstance fields (including enum constants)Local variablesParameter variables
标准的Annotation
JDK1.5提供了若干的标准Annotation来补充语法定义,或者标记Annotation。标准的Annotation有以下几个:
Annotation使用范围用途Deprecated所有将目标标记为不推荐使用SuppressWarnings除了包和Annotation禁止标记对象发出被标记的警告信息Override方法标记这个方法重写了父类的方法TargetAnnotation标记Annotation的适用范围RetentionAnnotation标记Annotation最终驻留的地方DocumentedAnnotation该Annotation在JavaDoc文档中出现InheritedAnnotation该Annotation默认被使用该Annotation的所有子类继承
下面具体讲解标准Annotation的用法。 常用的Annotation包括以下三个:@Deprecated @SuppressWarnings @Override,他们的用途分别如上表所示。 以下说明的Annotation有一个共同的特点就是他们都只能用在Annotation的声明上。 @Target用来标记Annotation适用的范围,@Target有一些预定义的属性,如下表所示: 类型|适用范围 -|-| ANNOTATION_TYPE|只能用在Annotation的声明中 PACKAGE|用在包上 TYPE|类(包括枚举)或者接口(包括Annotation) METHOD|方法 CONSTRUCTOR|构造方法 FIELD|字段(包含枚举内部的常量) PARAMETER|方法或者构造方法的参数 LOCAL_VARIABLE|本地变量
@Retention用来标记Annotation在那些范围(源代码,类文件或者运行时)内是可用的。@Retention与定义了一些属性,如下表所示:
驻留策略描述SOURCEAnnotation只存在于源代码中,不包括在编译生成Class文件中CLASSAnnotation存在于源代码中,也存在于编译生成的Class文件中,但是在运行时这些Annotation不被JVM装载。RUNTIMEAnnotation存在于源代码中,也存在于编译生成的Class文件中,同时在运行时这些Annotation被装载到JVM内部,可以使用反射的机制在运行时使用。
@Documented用来将Annotation显示在生成的JavaDoc中。 @Inherited只能用来标记用在类上的Annotation,用来说明被标记的Annotation会被该类的所有子类自动的继承。
Annotation应用实例 http://www.onjava.com/pub/a/onjava/2005/01/19/metadata_validation.html by Jacob Hookom
使用Annotation的一个例子就是建立一个简单的用户输入验证框架,使用这个框架最终用户可以以如下的方式来定义字段的校验属性:
@ValidateRequired
@ValidateEmail
public void setEmail(String email) {
this.email = email;
}
@ValidateRequired
@ValidateLength(min=6,max=12)
public void setPassword(String password) {
this.password = password;
}
以上的代码说明,email字段是必须的,且必须满足email的校验要求,同时password字段也是必须的,且长度必须在6~12之间。有了这些定义之后我们能够使用如下的代码达到验证的效果:
Validator.validate(loginBean, "email", "yourname@onjava.com"); //pass
Validator.validate(loginBean, "password", ""); // failure
要能够达到上述的要求,我们必须定义一些Annotation,以下代码是ValidateLength和ValidateExpr的声明:
// Example @ValidateLength(min=6,max=8)
public @interface ValidateLength {
int min() default 0;
int max() default Integer.MAX_VALUE;
}
// Example @ValidateExpr("^(\\w){0,2}$");
public @interface ValidateExpr {
String value();
}
具体开发的过程中我们会遇到一些问题,这主要由于两方面的原意产生第一,Annotation内部不能定义方法,只能定义一些状态。第二,Annotation不允许使用继承(extends或者implements),这意味着我们不能在反射的过程中使用instance of这样的功能。为了识别出于我们定义的校验相关的Annotation我们定义了一个如下的Annotation:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Validate {
Class<? extends ValidateHandler> value();
}
正如你所看到的Validate可以驻留在JVM内部,即它可以在运行时通过反射的方式使用。同时它必须用来标记其他的Annotation,同时他有一个Class类型的value元素,这个类型必须从ValidateHandler继承而来,主要用来处理具体的验证逻辑。
在此设计之下看看我们如何声明一个ValidateExpr的Annotation对象:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Validate(ValidateExprHandler.class)
public @interface ValidateExpr {
String value();
}
ValidateExpr的前两个Annotation不用多讲,主要说说@Validate(ValidateExprHandler.class)的含义,这样解决了我们前边提到的两个问题,第一我们可以看看一个Annotation是否有Validate类型的Annotation来确定这个Annotation是不是我们校验框架内部使用的Annotation。同时我们也提供了一个具体的类ValidateExprHandler来处理校验逻辑。 接下来我们看看ValidateExprHandler的实现:
// 定义了一个ValidateHandler接口,
// 这个接口有一个Annotation类型的模版参数
public interface ValidateHandler<T extends Annotation>
{
public void validate(T settings, Object value)
throws ValidationException;
public Class<T> getSettingsType();
}
// 一个ValidateHandler的实例,用来处理正则表达式的验证,
// 其中的Anotation类型的参数为ValidateExpr
public class ValidateExprHandler implements ValidateHandler<ValidateExpr> {
public void validate(ValidateExpr settings, Object value) throws ValidationException {
String i = (value != null) ? value.toString() : "";
if (!Pattern.matches(settings.value(), i)) {
throw new ValidationException(i
+ " does not match the pattern "
+ settings.value());
}
}
public Class<ValidateExpr> getSettingsType() {
return ValidateExpr.class;
}
}
说明:
我们定义了一个Annotation(Validate)来标记我们所有的校验用Annotation,
同时每一个具体的校验用的Annotation(ValidateExpr)都必须提供一个用来具体处理
校验逻辑的类(ValidateExprHandler)。
Annotation不允许继承,所以我们没有办法适用instance of的方法来识别一个校验框架
使用的Annotation,但是通过对我们使用的校验用的Annotation添加Annotation(Validate)
我们同样可以达到以上的目的。
ValidateHandler接口允许一个校验用的Annotation将具体的校验功能已代理的方式让其它的类来完成。
我们可以使用如下的方式来处理校验的具体过程:
说明:在JDK1.5中Method实现了AnnotatedElement接口,我们可以使用AnnotatedElement来做处理操作
// 对一个方法和将要调用的参数值进行校验
public static void validate(AnnotatedElement element, Object value)
throws ValidationException
{
Validate v;
ValidateHandler vh;
Annotation a;
// 从该方法上返回所有的Annotation
Annotation[] ma = element.getAnnotations();
for (int i = 0; i < ma.length; i++) {
// 如果该Annotation有类型为Validate的Annotation则说明这是我们校验
// 框架所使用的Annotation。
v = ma[i].annotationType().getAnnotation(Validate.class);
if (v != null) {
try {
// 使用Annotation中定义的ValidateHandler类来生成ValidateHandler的实例。
vh = v.value().newInstance();
// 使用创建的ValidateHandler来做校验操作。
// 校验过程中可以抛出ValidationException
vh.validate(ma[i], value);
} catch (InstantiationException ie) {
} catch (IllegalAccessException iae) {
}
}
}
}
转自https://www.cnblogs.com/liuqk/articles/2115778.html
[转载] Java中的元数据相关推荐
- [转载]java中Date,SimpleDateFormat
一.Java中的日期概述: 日期在Java中是一块非常复杂的内容,对于一个日期在不同的语言国别环境中,日期的国际化,日期和时间之间的转换,日期的加减运算,日期的展示格式都是非常复杂的问题. 在Java ...
- [转载] Java中Runtime的使用
参考链接: Java中的JVM的关闭挂钩 1 JDK中Runtime的定义 http://blog.csdn.net/lysnow_oss/archive/2007/05/12/ ...
- [转载]java中try 与catch的使用
留着以后看 原文地址:java中try 与catch的使用作者:碌碌如玉 try{ //代码区 }catch(Exception e){ //异常处理 } 代码区如果有错误,就会返回所写异常的处理. ...
- java枚举类型有什么用_[转载] Java中枚举类型的使用 - enum
本文转载自博客 - Java枚举类型, 博主对原文内容及结构作了一定的修改. 1 枚举类的编译特性 从JDK 5开始, Java中多了一个关键字 -- enum: 可以将一组具有名称的值(包括Stri ...
- [转载] Java中如何引用另一个类里的集合_Java工程师面试题整理
参考链接: 在Java中将预定义的类名用作类或变量名 花了一星期把学过的都整理一遍 尽量易懂,从基础到框架 最新版大厂面经汇总出炉,持续更新中 汇总完了上传网盘,设计到后端架构师的一切知识 如果没更新 ...
- [转载] Java中this和super关键字分别是什么意思
参考链接: Java中的Super关键字 this和super关键字 this是自身的一个对象,代表对象本身可以理解为指代当前的对象,它可以调用当前对象的属性.方法和构造方法,一般情况下可以省略,必须 ...
- [转载] java中的经典问题:传值与传引用
参考链接: 有关Java中数组分配的有趣事实 参数传递的秘密 知道方法参数如何传递吗? 记得刚开始学编程那会儿,老师教导,所谓参数,有形式参数和实际参数之分,参数列表中写的那些东西都叫形式参数,在实际 ...
- [转载] Java中的final变量、final方法和final类
参考链接: Java中的final数组 | Final arrays 1.final变量 final关键字可用于变量声明,一旦该变量被设定,就不可以再改变该变量的值.通常,由final定义的变量为常量 ...
- [转载] java中50个关键字以及各自用法大全
参考链接: Java中的默认数组值 关键字和保留字的区别 正确识别java语言的关键字(keyword)和保留字(reserved word)是十分重要的.Java的关键字对java的编译器有特殊的意 ...
最新文章
- Delphi XE5开发的Android启动时黑屏解决方法
- dev gridcontrol简单的动态设置动态表头
- 为什么要进行字节对齐?
- 基于Mac环境搭建以太坊私有区块链进行挖矿模拟
- 强推!十大顶级大数据可视化工具 | 程序员硬核评测
- SIR模型的应用(2) - Influence maximization in social networks based on TOPSIS(3)
- IntelliJ IDEA+jetty部署Eova
- 计算机网络(王道考研笔记)
- Excel判断身份证号码数据的第17或15位数字的奇偶性决定男女性别
- 牛客网 吉首大学2019年程序设计竞赛(重现赛)A: SARS病毒(矩阵快速幂 + 碰巧降幂)
- 别了dvorak!-----论qwert、dvorak布局优劣
- 大三Web课程设计——悬崖上的波妞(4页) HTML+CSS(可以很好的应付老师的作业)
- ThreadLocal的一些想法
- 视频教程-从理论到实战:在园区网中部属IPv6-网络技术
- Steam如何转换区服(以PES2021日服为例)
- 线性代数[矩阵的秩]
- 2006德国世界杯八分之一决赛大预测
- 数据库操作之插入一行数据
- dpkg -L zabbix-server-mysql
- [复试——大地测量学]第一章节——2022/12/30
热门文章
- pil python 安装_20行Python代码给微信头像戴帽子
- 用ajax替换html代码,替换Ajax响应一个div的内部HTML(Replace inner HTML of a div w
- Vim 重复操作的宏录制
- linux lzo 压缩文件,Linux常用压缩和解压命令
- java arraylist底层实现原理_ArrayList和LinkedList底层原理
- 的控制台主题_【12.11最新版】芯片机/大气层主题软件NXThemesInstaller
- 动态添加input_前端提效必备:动态模版生成
- 【SpringBoot 2】(十)数据库相关
- IntelliJ IDEA最常用的一些快捷键,学会了室友还以为你在祖安对线
- OpenGL阴影添加学习材料及总结