创建你自己的 Java 注解类 已翻译 100%

oschina 投递于 2014/07/22 06:42 (共 9 段, 翻译完成于 07-23)
阅读 11638
收藏 193
18
加载中

如果你已经在使用Java编程,并且也使用了任何像Spring和Hibernate这样的流行框架,那么你应该对注解的使用非常地熟悉。使用一个现有框架工作的时候,通常使用它的注解就够了。但是,你是不是也有时候有要创建属于你自己的注解的需求呢?

不久之前,我找到了一个自己创建一个注解的理由,那是一个涉及验证存储在多种数据库中的常用数据的项目。

场景描述

该业务有多种数据库都存储着相同的数据,它们有各自不同的保持数据更新的方法. 该业务曾计划把所有这些数据都整合到一个主数据库中,以减轻涉及到多种数据源所带来的问题的复杂性.

LeoXu
翻译于 2014/07/22 08:02
2

不过在项目开始之前,业务还需要知道数据距离可以同步还有多少差距,并做出任何必要的修正来使其可以进行同步. 第一步需要创建一个展示那些数据多种数据库的通用数据的报表,并对其值进行验证, 对那些不符合条件的记录进行高亮显示. 这里有一个对当时需求的简短摘要:

  • 比对多种数据库间公共部分的数据,诸如客户,公司或者目录信息.

  • 默认的值应该根据值的类型匹配所有的数据库.

  • 对于某些字段,我们只想展示其值,而不要进行任何数据比较.

  • 对于某些字段,我们只想要对比其值,并在指定的特定数据源上进行数据验证.

  • 对于某些字段,我们可能想要做一些复杂的数据比较,可能会基于记录内的其它字段.

  • 对于某些字段,我们可能想要用一种特定格式对数据进行格式化,比如钱币数量 使用 $000,000.00 .

  • 报表应该用MS Excel格式的,每一行都包含来自每个数据源的字段值. 任何不匹配数据验证规则的行都应该用黄色高亮显示.

LeoXu
翻译于 2014/07/22 09:02
1

注解

经过一阵子对需求和一些想法的推敲之后,我决定使用注解来驱动对于数据比对和报表处理的配置. 我们需要的东西得是简单,而高度灵活可扩展的. 这些注解将会是字段级别的,而我就喜欢配置不会被隐藏在classpath某个地方的文件中. 如此,你就能够直接查看同一个字段相关联的注解,以便知晓它具体是如何进行处理的.

在最简单的情况下,注解无非就是一个标记,就只是提供信息而不会对代码执行的操作本身有直接影响的元数据. 如果你一直在从事Java编程,那么现在你对它们的使用应该相当的熟悉了, 但是可能你从来没有过创建属于你自己的注解的需求. 为此,你需要创建一个带有Java类型@interface的新类型,它将包含能指定元数据详细信息的要素.

LeoXu
翻译于 2014/07/22 16:19
1

这里有一个来自这个项目的示例:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReconField {

    /**
     * Value indicates whether or not the values from the specified sources should be compared or will be used to display values or reference within a rule.
     *
     * @return The value if sources should be compared, defaults to true.
     */
    boolean compareSources() default true;

    /**
     * Value indicates the format that should be used to display the value in the report.
     *
     * @return The format specified, defaulting to native.
     */
    ReconDisplayFormat displayFormat() default ReconDisplayFormat.NATIVE;

    /**
     * Value indicates the ID value of the field used for matching source values up to the field.
     *
     * @return The ID of the field.
     */
    String id();

    /**
     * Value indicates the label that should be displayed in the report for the field.
     *
     * @return The label value specified, defaults to an empty string.
     */
    String label() default "";

    /**
     * Value that indicates the sources that should be compared for differences.
     *
     * @return The list of sources for comparison.
     */
    ReconSource[] sourcesToCompare() default {};

}

这是驱动数据比对过程如何运作的主要注解. 它包含的基本要素,可以满足不同数据源间数据进行比较的大部分需求. @ReconField 可以处理除更加复杂的比对之外,我们所期望的大多数需求, 而更加复杂的情况我们将会在稍后有所讨论. 这些要素的大多数在代码清单中一对一的注释中都有介绍, 而需要指出的是,在我们的@ReconField上有几个关键的注解.

  • @Target – 这个注解可以让你来指定你的注解应该被用在那个java元素上. 可能的目标类型是 ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER 和 TYPE. 在我们的 @ReconField 注解中他被指定到了 FIELD 级别.

  • @Retention – 它可以让你指定注解在何时生效. 可能的值有 CLASS, RUNTIME 和 SOURCE. 因为我们将会在运行时 RUNTIME 处理这个注解, 所以那就是我们需要设置的值.

LeoXu
翻译于 2014/07/22 16:31
2

这一数据验证过程将会为每一个数据库运行一次查询,并且将结果映射到展示出针对特定业务记录类型所有字段的实体bean中. 映射数据实体的每一个字段上的注解会告诉处理器如何为特定字段及在每个数据库中找到的其值执行数据比对. 因此让我们来看几个示例来了解这些注解是如何被运用于不同的数据比对配置的.

为了验证现有的值并同每个数据源中的只精确匹配,你只需要提供一个字段ID以及将会展示在报表上字段的标记.

@ReconField(id = CUSTOMER_ID, label = "Customer ID")
private String customerId;

为了展示在每个数据源中找到的值,但不做任何数据比对,你可能需要制定 compareSources 元素,并将其值设置为false.

@ReconField(id = NAME, label = "NAME", compareSources = false)
private String name;
LeoXu
翻译于 2014/07/22 16:39
2

为了验证在指定数据源中找到的值,而不是全部,你可能会使用到 elementsourcesToCompare. 使用这个东西会展示所有找到的值,但是只对在元素中列出的数据源中找到的值进行比对. 这样就能处理有些不是在每一个数据源中都会存储的数据场景了. ReconSource 是一个包含了可以用来进行比对的数据源的枚举类型.

@ReconField(id = PRIVATE_PLACEMENT_FLAG, label = "PRIVATE PLACEMENT FLAG", sourcesToCompare ={ ReconSource.LEGACY, ReconSource.PACE })
private String privatePlacementFlag;

现在我们已经满足了我们的基本需求,我们需要解决实现指定字段来进行复杂数据比对能力的问题. 为此,我们将创建第二个注解,来驱动定制规则处理.

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReconCustomRule {

/**
* Value indicates the parameters used to instantiate a custom rule processor, the default value is no parameters.
*
* @return The String[] of parameters to instantiate a custom rule processor.
*/
String[] params() default {};

/**
* Value indicates the class of the custom rule processor to be used in comparing the values from each source.
*
* @return The class of the custom rule processor.
*/
Class<?> processor() default DefaultReconRule.class;

}
LeoXu
翻译于 2014/07/22 16:45
2

同之前的注解非常类似,最大的不同在于 @ReconCustomRule 注解中我们指定了一个类,它可以在重建处理执行时执行数据比对. 你可以只定义将会被用到的类,那样你的处理器就可以实例化并初始化你所指定的类. 在这个注解中指定的类将需要实现一个通用的规则接口,它将会被规则处理器用来执行规则.

现在让我们来看看使用这个注解 的例子.

在本例中,我们使用了一个自定义的规则,它将会检查股票交易所是不是 United States,如果是则跳过这条数据. 为此,这条规则将需要检查同一记录中的 exchange country 字段.

@ReconField(id = STREET_CUSIP, label = "STREET CUSIP", compareSources = false)
@ReconCustomRule(processor = SkipNonUSExchangeComparisonRule.class)
private String streetCusip;
LeoXu
翻译于 2014/07/22 16:52
1

这里的示例我们为自定义规则指定了一个参数,这里它是一个包容量. 对于这种特殊的数据比对,被比较的值不能偏离超过1000.通过使用指定了包容量的参数,我们就可以使用不同的包容量将同一套自定义规则运用到多个字段上. 唯一的缺点就是,由于注解的性质,这些参数都只能是静态的,所以不能动态的修改.

@ReconField(id = USD_MKT_CAP, label = "MARKET CAP USD", displayFormat = ReconDisplayFormat.NUMERIC_WHOLE, sourcesToCompare =
{ ReconSource.LEGACY, ReconSource.PACE, ReconSource.BOB_PRCM })
@ReconCustomRule(processor = ToleranceAmountRule.class, params =  { "10000" })
private BigDecimal usdMktCap;

如你所见,我们只使用了几个简单的注解,就设计出了一个具有相当程度灵活性的面向多数据库场景的数据验证报告功能. 在这个特殊情况下,注解驱动了数据的比对过程,因此我们实际上就是使用了注解在找到的映射数据实体上进行计算并直接使用它们进行处理.

LeoXu
翻译于 2014/07/23 14:00
2

结论

关于Java注解能做什么以及它们的使用规则,已经有了相当多的文章。 本文更多的是聚焦于一个实例,借以说明为什么你需要考虑使用注解,同时也能直观的看看有什么好处。

要记住这只是一个起步,一旦你决定要创建使用注解,你还要想清楚要怎样处理它们才能真正发挥他们的长处。在后面的文章中,我将向你们展示如何使用Java反射来处理注解。在那之前,有一些不错的关于Java注解的资料可以看看:

– Jonny Hackett, asktheteam@keyholesoftware.com

lwei
翻译于 2014/07/22 10:42
2
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(31)

jQer
jQer

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。

引用来自“ylxs90”的评论

逗比真逗

引用来自“jQer”的评论

菜比真菜,玩java的99%都是菜比,连自己用的接口都搞不明白的菜比,没有哪个语言比java更能诞生菜比了!

引用来自“ylxs90”的评论

我只能说,99%的Javaer都说不出如此逗比的话!你赢了

引用来自“jQer”的评论

那是因为你们从来都没接触过操作系统,整天用着一大堆裹满了香蕉猩猩的垃圾框架

引用来自“aynt”的评论

我觉得一门语言存在这么长时间一定有它的道理,还有大神,你是在用机器码编程吗
你连操作系统是用什么语言写的都搞不明白。
aynt
aynt

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。

引用来自“ylxs90”的评论

逗比真逗

引用来自“jQer”的评论

菜比真菜,玩java的99%都是菜比,连自己用的接口都搞不明白的菜比,没有哪个语言比java更能诞生菜比了!

引用来自“ylxs90”的评论

我只能说,99%的Javaer都说不出如此逗比的话!你赢了

引用来自“jQer”的评论

那是因为你们从来都没接触过操作系统,整天用着一大堆裹满了香蕉猩猩的垃圾框架
我觉得一门语言存在这么长时间一定有它的道理,还有大神,你是在用机器码编程吗
杰森斯坦森
杰森斯坦森
本文只是写给有需要的人看的。你看不上java,就滚蛋。别在这秀智商下限。骂来骂去有什么意思?对你工作有帮助?做出来的东西好才是根本的。想挑战就拿着自己做出来的优秀作品展示一下。不然有什么资格说人家xx语言垃圾?有本事你自己写个牛B的语言出来啊
jQer
jQer

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。

引用来自“ylxs90”的评论

逗比真逗

引用来自“jQer”的评论

菜比真菜,玩java的99%都是菜比,连自己用的接口都搞不明白的菜比,没有哪个语言比java更能诞生菜比了!

引用来自“ylxs90”的评论

我只能说,99%的Javaer都说不出如此逗比的话!你赢了
那是因为你们从来都没接触过操作系统,整天用着一大堆裹满了香蕉猩猩的垃圾框架
ylxs90
ylxs90

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。

引用来自“ylxs90”的评论

逗比真逗

引用来自“jQer”的评论

菜比真菜,玩java的99%都是菜比,连自己用的接口都搞不明白的菜比,没有哪个语言比java更能诞生菜比了!
我只能说,99%的Javaer都说不出如此逗比的话!你赢了
jQer
jQer

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。

引用来自“ylxs90”的评论

逗比真逗
菜比真菜,玩java的99%都是菜比,连自己用的接口都搞不明白的菜比,没有哪个语言比java更能诞生菜比了!
ylxs90
ylxs90

引用来自“jQer”的评论

没有微软,java也不会撑到现在。

还真当java是多么优秀的语言。
逗比真逗
ylxs90
ylxs90

引用来自“ylxs90”的评论

自从看过groovy,再也不想用java了

引用来自“谦谦君子”的评论

可以看看scala
看了一点,感觉不如groovy。语法跟Java不兼容
寒情漠漠
寒情漠漠

引用来自“噢哟哪”的评论

不管怎么注解,也解决不了Java罗嗦,冗余,繁琐的现状。

引用来自“地皮鼠”的评论

这不是[静态语言]的通病吗?

引用来自“xesam”的评论

啰嗦就啰嗦啊,好像用不罗嗦的语言就能写出什么牛逼的东西似的。

引用来自“这个世界不真实”的评论

我悄咪咪的说下JVM上200多种语言,比联合国成员国还多,深度兼容java,可以和java互调,嫌java啰嗦不会使用groovy啊,把你们的钛合金狗眼擦亮点,好好看看,java不仅仅是java语言,是真个java生态圈!

引用来自“新人王”的评论

好像不用java的人能做出多大多复杂的系统似的。
不喷怎么显示他厉害呢
吴振宁
吴振宁

引用来自“噢哟哪”的评论

不管怎么注解,也解决不了Java罗嗦,冗余,繁琐的现状。

引用来自“地皮鼠”的评论

这不是[静态语言]的通病吗?

引用来自“xesam”的评论

啰嗦就啰嗦啊,好像用不罗嗦的语言就能写出什么牛逼的东西似的。

引用来自“这个世界不真实”的评论

我悄咪咪的说下JVM上200多种语言,比联合国成员国还多,深度兼容java,可以和java互调,嫌java啰嗦不会使用groovy啊,把你们的钛合金狗眼擦亮点,好好看看,java不仅仅是java语言,是真个java生态圈!

引用来自“新人王”的评论

好像不用java的人能做出多大多复杂的系统似的。

引用来自“千里山南”的评论

总有这么一群人,当你告诉他们你工作中主要使用Java时,他们会很鄙视的瞧上你一眼,而后冷冷说道"Java啊,有点慢!"

引用来自“南湖船老大”的评论

一群做wordpress,discuz,ecshop的小网站的人,说Java太慢太啰嗦。他们选择性无视的是,他们最崇拜的facebook和google,也在大量使用Java技术。
想要方便性能又好的方法太难了java已经很好了,再不然搞脚本语言吧,ROR很方便,如果觉得性能低就别干这一行了,这个世界已经不能适应你了,找一个能适应你的行业吧。
返回顶部
顶部