创建自定义的Java注解类的方法

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

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

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

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

  • 比对多种数据库间公共部分的数据,诸如客户,公司或者目录信息.
  • 默认的值应该根据值的类型匹配所有的数据库.
  • 对于某些字段,我们只想展示其值,而不要进行任何数据比较.
  • 对于某些字段,我们只想要对比其值,并在指定的特定数据源上进行数据验证.
  • 对于某些字段,我们可能想要做一些复杂的数据比较,可能会基于记录内的其它字段.
  • 对于某些字段,我们可能想要用一种特定格式对数据进行格式化,比如钱币数量 使用 $000,000.00 .
  • 报表应该用MS Excel格式的,每一行都包含来自每个数据源的字段值. 任何不匹配数据验证规则的行都应该用黄色高亮显示.

注解

经过一阵子对需求和一些想法的推敲之后,我决定使用注解来驱动对于数据比对和报表处理的配置. 我们需要的东西得是简单,而高度灵活可扩展的. 这些注解将会是字段级别的,而我就喜欢配置不会被隐藏在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 – 这个注解可以让你来指定你的注解应该被用在那个java元素上. 可能的目标类型是 ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER 和 TYPE. 在我们的 @ReconField 注解中他被指定到了 FIELD 级别.

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

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

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


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

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

@ReconField(id = NAME, label = "NAME", compareSources = false)
private String name;

为了验证在指定数据源中找到的值,而不是全部,你可能会使用到 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;

}

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

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

在本例中,我们使用了一个自定义的规则,它将会检查股票交易所是不是 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;

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

(0)

相关推荐

  • 简单谈谈java自定义注解

    Java在1.5开始引入了注解,目前流行的框架都在用注解,可想而知注解的强大之处. 以下通过自定义注解来深入了解java注解. 一.创建自定义注解 package com.sam.annotation; import java.lang.annotation.*; /** * @author sam * @since 2017/7/13 */ @Target({ElementType.METHOD, ElementType.FIELD}) @Retention(RetentionPolicy.R

  • 基于Java注解(Annotation)的自定义注解入门介绍

    要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法. -------------------------------------------------------------------------------- 元注解: 元注解的作用就是负责注解其他注解.Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明.Java5.0定义的元注解:

  • java自定义注解实现前后台参数校验的实例

    其实是可以通过@Constraint来限定自定义注解的方法. @Constraint(validatedBy = xxxx.class) 下面是我做的 java自定义注解实现前后台参数校验 的代码示例 对这个感兴趣的,请好好看,好好学: package sonn.sonnannotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.anno

  • 详解Java注解教程及自定义注解

    Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如Hibernate.Jersey.Spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注解提供的功能要远远超

  • Java自定义注解实现Redis自动缓存的方法

    在实际开发中,可能经常会有这样的需要:从MySQL中查询一条数据(比如用户信息),此时需要将用户信息保存至Redis. 刚开始我们可能会在查询的业务逻辑之后再写一段Redis相关操作的代码,时间长了后发现这部分代码实际上仅仅做了Redis的写入动作,跟业务逻辑没有实质的联系,那么有没有什么方法能让我们省略这些重复劳动呢? 首先想到用AOP,在查询到某些数据这一切入点(Pointcut)完成我们的切面相关处理(也就是写入Redis).那么,如何知道什么地方需要进行缓存呢,也就是什么地方需要用到AO

  • Java自定义注解的详解

    Java自定义注解 Java注解提供了关于代码的一些信息,但并不直接作用于它所注解的代码内容.在这个教程当中,我们将学习Java的注解,如何定制注解,注解的使用以及如何通过反射解析注解. Java1.5引入了注解,当前许多java框架中大量使用注解,如hibernate.Jersey.spring.注解作为程序的元数据嵌入到程序当中.注解可以被一些解析工具或者是编译工具进行解析.我们也可以声明注解在编译过程或执行时产生作用. 在使用注解之前,程序源数据只是通过java注释和javadoc,但是注

  • 浅谈Java自定义注解和运行时靠反射获取注解

    java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能. 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annotation 包中. 1.元注解 元注解是指注解的注解.包括  @Retention @Target @Document @Inherited四种. 1.1.@Retention: 定义注解的保留策略 @Retention(RetentionPolicy.SOURCE) //注解仅

  • java自定义注解接口实现方案

    java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能. 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annotation 包中. 1.元注解 元注解是指注解的注解.包括 @Retention @Target @Document @Inherited四种. 1.1.@Retention: 定义注解的保留策略 Java代码 复制代码 代码如下: @Retention(RetentionPolicy.SOURCE

  • 创建自定义的Java注解类的方法

    如果你已经在使用Java编程,并且也使用了任何像Spring和Hibernate这样的流行框架,那么你应该对注解的使用非常地熟悉.使用一个现有框架工作的时候,通常使用它的注解就够了.但是,你是不是也有时候有要创建属于你自己的注解的需求呢? 不久之前,我找到了一个自己创建一个注解的理由,那是一个涉及验证存储在多种数据库中的常用数据的项目. 场景描述 该业务有多种数据库都存储着相同的数据,它们有各自不同的保持数据更新的方法. 该业务曾计划把所有这些数据都整合到一个主数据库中,以减轻涉及到多种数据源所

  • 解决Java Calendar类set()方法的陷阱

    在项目中,需要获取指定年份和月份的最后一天.我在网上找到了一个用Calendar类获取的方法,代码如下: import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; public class TestCalendar { public static void main(String[] args) { String s = new SimpleDateFormat("yyyy-MM-dd

  • Java Object类equals方法

    基本概念: Object类位于java.lang包中,java.lang包包含着Java最基础和核心的类,在编译时会自动导入: Object类是所有Java类的祖先.每个类都使用 Object 作为超类.所有对象(包括数组)都实现这个类的方法.可以使用类型为Object的变量指向任意类型的对象 equals()方法:比较两个对象是否同一       如果两个对象具有相同的类型以及相同的属性值,则称这两个对象相等.如果两个引用对象指的是同一个对像,则称这两个变量同一.Object类中定义的equa

  • java教程之java注解annotation使用方法

    1.概述 注解可以定义到方法上,类上,一个注解相当与一个类,就相当于实例了一个对象,加上了注解,就相当于加了一个标志. 常用的注解:@Override:表示重新父类的方法,这个也可以判断是否覆盖的父类方法,在方法前面加上此语句,如果提示的错误,那么你不是覆盖的父类的方法,要是提示的没有错误,那么就是覆盖的父类的方法.@SuppressWarnings("deprecation"):取消编译器的警告(例如你使用的方法过时了)@Deprecated:在方法的最上边也上此语句,表示此方法过时

  • 创建js对象和js类的方法汇总

    代码很简单,就不多废话了. 复制代码 代码如下: //第一种定义方式 var person=new Object(); //创建了一个对象. person.name="tom"; //使用person对象对调用name属性,它的值为tom alert(person.name); //显示name属性值 person.say=function(){ //对person对象添加了一个say函数. alert("person say"); }; person.say();

  • 深入理解Java注解的使用方法

    注解是jdk1.5新增的特性.大家都知道,jdk1.5在java的发展史上有着划时代的意义.而注解的出现,在某种程度上颠覆了框架的设计.比如,spring在注解出现后,改善了原先五大组件的模式,增加了基于注解的实现方式.现在重点讲讲注解的使用. 元注解: jdk1.5定义了4个元注解,元注解的作用是注解其他的注解. 1.@Retention 2.@Target 3.@Documented 4.@Inherited @Retention用于指明该注解存在的时机.参数有三个值可选:Retention

  • Java AtomicInteger类使用方法实例讲解

    1.java.util.concurrent.atomic 的包里有AtomicBoolean, AtomicInteger,AtomicLong,AtomicLongArray, AtomicReference等原子类的类,主要用于在高并发环境下的高效程序处理,来帮助我们简化同步处理. 在Java语言中,++i和i++操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字.而AtomicInteger则通过一种线程安全的加减操作接口. 2.AtomicInteger

  • java system类使用方法示例 获取系统信息

    常用的方法: 复制代码 代码如下: long currentTimeMillis();  获取当前时间的毫秒值 void exit();终止当前正在运行的 Java 虚拟机. 复制代码 代码如下: public static void Method(){     long l = System.currentTimeMillis();     System.out.println(l); System.exit(); } 描述系统属性信息:Properties System.getPropert

  • Java Scanner类及其方法使用图解

    1.导包 java.util:import java.util.Scanner; 2.创建对象 Scanner x=new Scanner(System.in); 3.做事情 int value=x.nextInt(); String value=x.nextLine(); nextInt(nextFloat nextByte) next nextLine 1.读取方式上来讲 大家都以回车符作为结束符号: 除了nextLine以外其余的方法都不读取回车符: 2.读取的返回结果来讲:nextInt

  • 自己写的java日志类和方法代码分享

    复制代码 代码如下: import java.io.*;import java.text.SimpleDateFormat;import java.util.*;import java.util.logging.Logger; public class AndyLogger{    //The defaulted root path of SSLVPN installation     private static String rootPath = "C:\\temp2"; //va

随机推荐