创建自定义的Java注解类的方法
如果你已经在使用Java编程,并且也使用了任何像Spring和Hibernate这样的流行框架,那么你应该对注解的使用非常地熟悉。使用一个现有框架工作的时候,通常使用它的注解就够了。但是,你是不是也有时候有要创建属于你自己的注解的需求呢? 不久之前,我找到了一个自己创建一个注解的理由,那是一个涉及验证存储在多种数据库中的常用数据的项目。 该业务有多种数据库都存储着相同的数据,它们有各自不同的保持数据更新的方法. 该业务曾计划把所有这些数据都整合到一个主数据库中,以减轻涉及到多种数据源所带来的问题的复杂性.
注解 经过一阵子对需求和一些想法的推敲之后,我决定使用注解来驱动对于数据比对和报表处理的配置. 我们需要的东西得是简单,而高度灵活可扩展的. 这些注解将会是字段级别的,而我就喜欢配置不会被隐藏在classpath某个地方的文件中. 如此,你就能够直接查看同一个字段相关联的注解,以便知晓它具体是如何进行处理的. 在最简单的情况下,注解无非就是一个标记,就只是提供信息而不会对代码执行的操作本身有直接影响的元数据. 如果你一直在从事Java编程,那么现在你对它们的使用应该相当的熟悉了,但是可能你从来没有过创建属于你自己的注解的需求. 为此,你需要创建一个带有Java类型@interface的新类型,它将包含能指定元数据详细信息的要素. 这里有一个来自这个项目的示例: @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 C 这个注解可以让你来指定你的注解应该被用在那个java元素上. 可能的目标类型是 ANNOTATION_TYPE,CONSTRUCTOR,FIELD,LOCAL_VARIABLE,METHOD,PACKAGE,PARAMETER 和 TYPE. 在我们的 @ReconField 注解中他被指定到了 FIELD 级别. @Retention C 它可以让你指定注解在何时生效. 可能的值有 CLASS,RUNTIME 和 SOURCE. 因为我们将会在运行时 RUNTIME 处理这个注解,所以那就是我们需要设置的值.
为了验证现有的值并同每个数据源中的只精确匹配,你只需要提供一个字段ID以及将会展示在报表上字段的标记. @ReconField(id = CUSTOMER_ID,label = "Customer ID") private String customerId; 为了展示在每个数据源中找到的值,但不做任何数据比对,你可能需要制定 compareSources 元素,并将其值设置为false. @ReconField(id = NAME,label = "NAME",compareSources = false) private String name;
@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; }
现在让我们来看看使用这个注解 的例子. 在本例中,我们使用了一个自定义的规则,它将会检查股票交易所是不是 United States,如果是则跳过这条数据. 为此,这条规则将需要检查同一记录中的 exchange country 字段. @ReconField(id = STREET_CUSIP,label = "STREET CUSIP",compareSources = false) @ReconCustomRule(processor = SkipNonUSExchangeComparisonRule.class) private String streetCusip; 这里的示例我们为自定义规则指定了一个参数,这里它是一个包容量. 对于这种特殊的数据比对,被比较的值不能偏离超过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; 如你所见,我们只使用了几个简单的注解,就设计出了一个具有相当程度灵活性的面向多数据库场景的数据验证报告功能. 在这个特殊情况下,注解驱动了数据的比对过程,因此我们实际上就是使用了注解在找到的映射数据实体上进行计算并直接使用它们进行处理. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |