If you are already using Java programming and have used any popular framework like spring and hibernate, you should be very familiar with the use of annotations. When working with an existing framework, it is usually sufficient to use its annotations. But do you sometimes have the need to create your own annotations?
Not long ago, I found a reason to create an annotation of my own, a project that involves validating commonly used data stored in multiple databases.
Scene Description
The business has a variety of databases that store the same data, and they have different ways of keeping the data updated. The business had planned to consolidate all this data into one master database to mitigate the complexity of the problems associated with multiple data sources.
Before the project begins, however, the business also needs to know how far the data distance can be synchronized, and make any necessary corrections to make it available for synchronization. The first step is to create a report that displays common data for multiple databases of that data, validate its values, and highlight those records that do not meet the criteria. Here's a short summary of what was needed at the time:
- Data that is common to a variety of databases, such as customers, companies, or directory information.
- The default value should match all databases based on the type of value.
- For some fields, we want to show only their values, not any data comparisons.
- For some fields, we just want to compare the values and validate the data on the specific data source specified.
- For some fields, we might want to do some complex data comparisons that might be based on other fields within the record.
- For some fields, we might want to format the data in a particular format, such as the number of coins using $000,000.00.
- The report should be in MS Excel format, with each row containing the field values from each data source. Any rows that do not match data validation rules should be highlighted in yellow.
Annotations
After a while about requirements and some ideas, I decided to use annotations to drive the configuration of data alignment and report processing. What we need is simple and highly flexible and scalable. These annotations will be field-level, and I prefer that the configuration is not hidden in a file somewhere in classpath. In this way, you can see the annotations associated with the same field directly in order to know how it is handled.
In the simplest case, the annotation is nothing more than a tag, just a metadata that provides information without directly affecting the operation that the code performs. If you've been working on Java programming, you should be pretty familiar with their use now, but maybe you've never had the need to create your own annotations. To do this, you need to create a new type with Java type @interface, which will contain elements that specify metadata details.
Here's an example from this project:
@Target (Elementtype.field) @Retention (retentionpolicy.runtime) public @interface Reconfield {/** * Value indicate s whether or not is the values from the specified sources should is compared or'll be used to display values or reference W
Ithin a rule.
* * @return The value if sources should be compared, defaults to true.
*/Boolean comparesources () default true;
/** * value indicates the format that should is used to display the value in the.
* * @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 is displayed in the To the field.
* * @return The label value specified, defaults to a empty string.
*/String label () default ""; /** * ValUE that indicates the sources that should is compared for differences.
* * @return The list of sources for comparison.
*/reconsource[] Sourcestocompare () default {};
}
This is the main annotation that drives the data compared to how the process works. It contains the basic elements that satisfy most of the requirements for comparing data between different data sources. @ReconField can handle most of the requirements that we expect in addition to more complex ratios, and more complex situations we will discuss later. Most of these elements are covered in a one-to-one comment in the code list, and it is important to note that there are several key annotations on our @reconfield.
@Target – This annotation allows you to specify that your annotations should be used on that Java element. Possible target types are annotation_type, constructor, FIELD, Local_variable, method, PACKAGE, PARAMETER, and type. He was assigned to the FIELD level in our @ReconField annotations.
@Retention – it allows you to specify when the annotation will take effect. The possible values are CLASS, RUNTIME, and SOURCE. Because we're going to RUNTIME this annotation at runtime, so that's the value we need to set.
This data validation process runs a query for each database and maps the results to an entity bean that shows all fields for a particular business record type. The annotations on each field of the mapping data entity tell the processor how to perform data alignment for specific fields and their values found in each database. So let's take a look at a few examples to see how these annotations are applied to different data-alignment configurations.
To validate existing values and match only exactly in each data source, you only need to provide a field ID and a tag that will be displayed on the report field.
@ReconField (id = customer_id, label = "CUSTOMER id")
private String customerId;
In order to show the values found in each data source, but without any data alignment, you might want to set the Comparesources element, setting its value to false.
@ReconField (id = name, label = "Name", Comparesources = False)
private String NAME;
To verify the values found in the specified data source, not all of them, you may be using the elementsourcestocompare. Using this will show all found values, but only the values found in the data sources listed in the element are compared. This allows you to handle some data scenarios that are not stored in every data source. Reconsource is an enumerated type that contains a data source that can be used for comparison.
@ReconField (id = private_placement_flag, label = "PRIVATE placement FLAG", Sourcestocompare ={reconsource.legacy, recons Ource. PACE})
private String Privateplacementflag;
Now that we have met our basic needs, we need to solve the problem of implementing the specified field to perform complex data-compare capabilities. To do this, we will create a second annotation to drive custom rule processing.
@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 is used in comparing the values from each SOURCE.
*
* @return The class of the custom rule processor.
* *
class<?> processor () default defaultreconrule.class;
}
Similar to previous annotations, the biggest difference is that @ReconCustomRule annotations we specify a class that can perform data alignment when the rebuild process executes. You can just define the classes that will be used, so that your processor can instantiate and initialize the classes you specify. The class specified in this note will need to implement a generic rule interface that will be used by the rule handler to execute the rule.
Now let's take a look at the example of using this annotation.
In this case, we use a custom rule that will check whether the stock Exchange is United States and skip this data if it is. To do this, this rule will need to check the Exchange Country field in the same record.
@ReconField (id = street_cusip, label = "Street Cusip", comparesources = False)
@ReconCustomRule (processor = Skipnonus Exchangecomparisonrule.class)
private String Streetcusip;
Here's an example where we specify a parameter for a custom rule, where it is a package capacity. For this particular data alignment, the value being compared cannot deviate more than 1000. By using parameters that specify the package capacity, we can apply the same set of custom rules to multiple fields using different containment quantities. The only drawback is that, due to the nature of the annotations, these parameters can only be static, so can not be dynamically modified.
@ReconField (id = usd_mkt_cap, label = "MARKET CAP USD", DisplayFormat = Recondisplayformat.numeric_whole, Sourcestocompar E =
{reconsource.legacy, reconsource.pace, RECONSOURCE.BOB_PRCM})
@ReconCustomRule (processor = Toleranceamountrule.class, params = {"10000"})
private BigDecimal usdmktcap;
As you can see, we've only used a few simple annotations to design a data validation report with a considerable degree of flexibility for multiple-database scenarios. In this particular case, the annotation drives the data alignment process, so we actually use annotations to compute on the mapped data entities found and use them directly for processing.