元数据

原创 2005年05月30日 15:18:00

元数据

也可能刚听到元数据你会有点陌生,其实任何一个使用过strutsejb或者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中的元数据的概念即吸收了.NetAttribute的概念,有吸收了.netproperty的概念。

Annotation定义

Annotation定义语法为:

modifiers @interface AnnotationName

{

   element declaration1

   element declaration2

   . . .

}

modifiers指:publicprotectedprivate或者默认值(什么也没有)。

一个元素的声明(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")

那些只有一个元素,且元素名字叫valueAnnotation可以使用如下的方式声明:

AnnotationName(“somevalue”)

 

Annotation中元素的类型必须是下述类型,或者这些类型的组合:

l         基本类型 (int, short, long, byte, char, double, float, or boolean)

l         字符创(String

l         类(Class (可以是形如 Class<? extends MyClass>)的泛型类)

l         枚举类型(enum

l         一个Annotation类型(annotation

l         上述类型构成的数组

如果Annotation的元素是数组,则可以做如下声明:

@BugReport(. . ., reportedBy={"Harry", "Carl"})

如果数组中只有一个元素时可以做如下声明:

如果Annotation元素类型为Annotation时可以做如下声明:

 

可以对如下对象添加Annotation

l         Packages

l         Classes (including enum)

l         Interfaces (including annotation interfaces)

l         Methods

l         Constructors

l         Instance fields (including enum constants)

l         Local variables

l         Parameter variables

标准的Annotation

JDK1.5提供了若干的标准Annotation来补充语法定义,或者标记Annotation。标准的Annotation有以下几个:

Annotation

使用范围

用途

Deprecated

所有

将目标标记为不推荐使用

SuppressWarnings

除了包和Annotation

禁止标记对象发出被标记的警告信息

Override

方法

标记这个方法重写了父类的方法

Target

Annotation

标记Annotation的适用范围

Retention

Annotation

标记Annotation最终驻留的地方

Documented

Annotation

AnnotationJavaDoc文档中出现

Inherited

Annotation

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与定义了一些属性,如下表所示:

驻留策略

描述

SOURCE

Annotation只存在于源代码中,不包括在编译生成Class文件中

CLASS

Annotation存在于源代码中,也存在于编译生成的Class文件中,但是在运行时这些Annotation不被JVM装载。

RUNTIME

Annotation存在于源代码中,也存在于编译生成的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,以下代码是ValidateLengthValidateExpr的声明:

// 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继承而来,主要用来处理具体的验证逻辑。

 

在此设计之下看看我们如何声明一个ValidateExprAnnotation对象:

@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;

   }

}

 

说明:

1. 我们定义了一个AnnotationValidate)来标记我们所有的校验用Annotation

同时每一个具体的校验用的AnnotationValidateExpr)都必须提供一个用来具体处理

校验逻辑的类(ValidateExprHandler)。

2. Annotation不允许继承,所以我们没有办法适用instance of的方法来识别一个校验框架

使用的Annotation,但是通过对我们使用的校验用的Annotation添加AnnotationValidate

我们同样可以达到以上的目的。

3. ValidateHandler接口允许一个校验用的Annotation将具体的校验功能已代理的方式让其它的类来完成。

我们可以使用如下的方式来处理校验的具体过程:

说明:在JDK1.5Method实现了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有类型为ValidateAnnotation则说明这是我们校验

      // 框架所使用的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) {

         }

      }

   }

}

SQL总结之数据库元数据(MSSQL)

数据库元数据就是指定义数据库各类对象结构的数据。 常见的数据库对象,包括:数据库表、触发器,索引,视图,存储过程,函数。 掌握数据库元数据,就需要深入地理解数据库的结构组成。 那么掌握数据库元数据...
  • gezhonglei2007
  • gezhonglei2007
  • 2016年09月17日 11:57
  • 2830

元数据的例子

很多开发人员一直都在抱怨,除了java代码,他们还要管理众多的XML配置文件。有了最近增加到java的元数据,通过使用标注(注解),框架里的普通详细配置信息现在都可以嵌入java文件里了。Sun的文章...
  • ZF0216
  • ZF0216
  • 2007年07月12日 10:02
  • 4883

元数据管理

在分布式存储架构中,
  • xiaming564
  • xiaming564
  • 2014年04月11日 10:15
  • 1482

元数据 and 元数据标准

一般银行内的系统建设环境分为三个:开发环境、测试环境与生产环境,每一个系统建设的周期都需要经过前两个环境才能正式进入生产环境。然而在系统的设计、开发、测试、上线过程中,无论是需求变更还是BUG修改都避...
  • gnicky
  • gnicky
  • 2017年02月22日 17:42
  • 681

元数据设计

什么是好的元数据方案?元数据方案是信息系统对其所管理的信息对象的各类属性所进行的规定,通常反映为数据库表的字段结构、关系、类型及取值限定。本来是信息系统设计中的一个技术性很强的工作,通常由系统设计(详...
  • liwuqing7758
  • liwuqing7758
  • 2010年06月23日 11:31
  • 1191

数据字典与元数据

数据字典数据字典是指对数据的数据项、数据结构、数据流、数据存储、处理逻辑、外部实体等进行定义和描述,其目的是对数据流程图中的各个元素做出详细的说明 1. 在传统的软件工程方法中,数据字典...
  • mlljava1111
  • mlljava1111
  • 2016年08月31日 09:50
  • 2463

编写基于XML的配置元数据

这在bean跨域多个XML文件的定义里面很有用。通常,在你的架构里一个独立的XML配置文件就代表一个逻辑层或是模型。        你可以使用应用上下文的构造函数从所有的XML片段中加载 bean ...
  • shenya2
  • shenya2
  • 2015年05月06日 16:59
  • 563

元数据在实际项目的应用

元数据在实际项目的应用         最早接触元数据概念是在学习数据仓库相关知识时,其描述数据仓库内数据的结构和建立方法的数据。其实元数据在OLTP系统中也非常重要,利用元数据可以让系统功能更灵活...
  • neweastsun
  • neweastsun
  • 2016年11月27日 23:01
  • 1301

元数据质量梳理

任一特定领域开发,如果没有梳理好元数据,则随着一个个项目,会出现各种非标准的表达,最后导致开发成本越来越高,越容易出错,并且本身数据模型的沉淀也是一种技术资产。原来老东家有专门的元数据平台,可惜没有和...
  • codewar
  • codewar
  • 2016年04月11日 20:59
  • 481

文档元数据

元数据是描述数据的信息,元数据不会显示在页面上,但是对于机器是可读的。如果说一篇HTML文档包含数据以及描述数据元数据,那么元数据就是head元素里的元素,数据就是放在body元素里面的。 head...
  • levinhax
  • levinhax
  • 2016年09月24日 22:07
  • 646
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:元数据
举报原因:
原因补充:

(最多只允许输入30个字)