JavaRush /Java Blog /Random EN /Creating your own annotations in Java
angelina
Level 5

Creating your own annotations in Java

Published in the Random EN group
article by Jonny Hackett July 14, 2014 11:09 am If you program in Java and use any of the popular frameworks such as Spring and Hibernate , then you are already familiar with the use of annotations. When working with an existing framework, internal annotations are quite sufficient. But what if you need to create your own annotations? Not long ago I had a reason to create my own annotations for a project that required confirmation of common information from several databases. Scenario A business had multiple databases that stored the same information and updated the data in different ways. It was planned to combine the data into one master database to eliminate the problems associated with obtaining data from different sources. But before starting the project, it was necessary to find out how out of sync the data was and make the necessary changes. The first step was to create a report that would show the same data in different databases and confirm the values, or highlight those records that did not match, based on established reconciliation rules. Below is an excerpt of the main requirements at the time of the project: • Compare data in several databases to find the same data, such as customer name, company name or directory information. • By default, the value should be exactly the same across all databases based on the data type. • For some fields we only wanted to show that the value was found, but the value was not compared. • For other fields, we only wanted to compare the value with what was found and confirm the data with the data from the specified source. • For the third fields, we wanted to make a complex data comparison that would be based on the value of other fields within the record. • For the fourth field type, we wanted to format the data, for example in the currency format $000,000.00. • The report had to be in MS Excel format, each row should contain a value from a separate source. Any line whose value does not match the data confirmation conditions should be highlighted in yellow. Annotations After we read the requirements and came up with a few different ideas for what was required, I decided to use annotations that would trigger the data comparison configuration and reporting process. We needed a simple, yet flexible and extensible solution. These annotations will be at the field level and I like the fact that the configuration will not be hidden in a file somewhere on the class path. Instead, I'll be able to see the annotations associated with the field so I know exactly how it will be processed. Simply put, an annotation will be nothing more than a marker, metadata that will provide information, but will not directly affect the operation of the code itself. If you've programmed in Java before, you should be familiar with using annotations, but you may have never needed to create your own. To do this, you need to create a new type that uses the Java @interface type , which will contain elements that in turn define the metadata details. Here is an example of a project: 1@Target(ElementType.FIELD) 2@Retention(RetentionPolicy.RUNTIME) 3public @interface ReconField { 4 5 /** 6 * Значение, которое определяет из Howого источника сравниваются данные, or будет использоваться для 7 отображения значения or для ссылки на правило. 8 * 9 * @return Значение, если источники должны быть сравнены, по умолчанию true. 10 */ 11 boolean compareSources() default true; 12 13 /** 14 * Значение показывает формат, который используется для отображения значения в отчете. 15 * 16 * @return Установленный формам, по умолчанию native. 17 */ 18 ReconDisplayFormat displayFormat() default ReconDisplayFormat.NATIVE; 19 20 /** 21 * Значение, показывающее meaning ID используемого поля для одинаковых значений из источника до поля. 22 * 23 * @return ID поля. 24 */ 25 String id(); 26 27 /** 28 * Значение, показывающее ярлык, который будет отображается в отчете для поля. 29 * 30 * @return Значение ярлыка, по умолчанию пустая строка. 31 */ 32 String label() default ""; 33 34 /** 35 * Значение, показывающее источник, который должен быть сравнен на предмет различий. 36 * 37 * @return Список источников для сравнения. 38 */ 39 ReconSource[] sourcesToCompare() default {}; 40 } This is the main annotation with which to start the data comparison process. It contains the basic required elements, as required, for comparing data from different data sources. @ReconField should handle most of what we need, with the exception of more complex data comparisons, which we'll talk about later. Most of these elements are explained by comments in the code. Regardless, a couple of the main annotations in our @ReconField need to be explained separately. • @Target – This annotation will allow you to specify those java elements to which the annotation should be applied. Possible types to use are: ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER and TYPE. In our @ReconField annotation for the FIELD level. • @Retention – This annotation will allow you to specify when the annotation will be available. Possible values ​​are CLASS, RUNTIME and SOURCE. Since we will be processing annotations in RUNTIME, we must set these values. The data validation process will run one query against each database, and then display the results in the overall data, which is all the fields for a particular record type. An annotation for each field in the shared data will tell the processor how to compare the data for that particular field, as well as the value found in each database. Let's look at a few examples of how these annotations can be used for various data comparison configurations. To confirm that a value exists and matches exactly in each data source, you just need to provide a field ID and a label that will appear in the report field. 1 @ReconField(id = CUSTOMER_ID, label = "Customer ID") 2 private String customerId; To display the found values ​​from each data source, but make data comparisons, you need to specify a compareSources element and set the value to false. 1 @ReconField(id = NAME, label = "NAME", compareSources = false) 2 private String name; To confirm that a value is found in a certain data source, but not all, you need to use the sourcesToCompare element . This will display all found values, but any data comparison in the data sources will be done according to the list of elements. This is for the case if some data is not saved in all data sources. ReconSource is an enum in which data sources are available for comparison. 1 @ReconField(id = PRIVATE_PLACEMENT_FLAG, label = "PRIVATE PLACEMENT FLAG", sourcesToCompare ={ 2 ReconSource.LEGACY, ReconSource.PACE }) private String privatePlacementFlag; Now that we've met the basic requirements, we need to perform more complex data comparisons that are field specific. To do this we will create a second annotation that will trigger the rules processing. 1 @Target(ElementType.FIELD) 2 @Retention(RetentionPolicy.RUNTIME) 3 public @interface ReconCustomRule { 4 5 /** 6 * Значение, указывающее используемые параметры, прописанные обработчику правила, meaning по умолчанию - 7 отсутствие параметров. 8 * 9 * @return The String[] параметры, прописанные обработчику правила 10 */ 11 String[] params() default {}; 12 13 /** 14 * Значение, указывающее класс обработчика правила, которое используется для сравнения значений из 15 каждого источника данных. 16 * 17 * @return Класс обработчика правила 18 */ 19 Class processor() default DefaultReconRule.class; 20 } Very similar to the previous annotation, one big difference is that in @ReconCustomRule we specify a class that will run the data comparison when the recon process starts. You can only specify the class that will be used, so that your handler will assign a value and initialize whatever class you specify. The specified class in this annotation will use the rule interface, which in turn will be used by the handler to execute the rule. Let's look at a couple of examples of this annotation. In this example, we are using a rule that will check for non-US currency exchanges and will skip the data comparison in this case. To do this, we need to check the country field in the same record. 1 @ReconField(id = STREET_CUSIP, label = "STREET CUSIP", compareSources = false) 2 @ReconCustomRule(processor = SkipNonUSExchangeComparisonRule.class) 3 private String streetCusip; Here is an example in which we set the parameters of the rule, in this case the tolerance value. To compare our data, the compared value cannot deviate by more than 1,000. Using a parameter to specify a tolerance value will allow us to use the same rules for several fields, with different tolerance values. The only problem is that these parameters are static and cannot be dynamic due to the nature of the annotation. 1 @ReconField(id = USD_MKT_CAP, label = "MARKET CAP USD", displayFormat = 2 ReconDisplayFormat.NUMERIC_WHOLE, sourcesToCompare = 3 { ReconSource.LEGACY, ReconSource.PACE, ReconSource.BOB_PRCM }) 4 @ReconCustomRule(processor = ToleranceAmountRule.class, params = { "10000" }) 5 private BigDecimal usdMktCap; As you can see, we've added some flexibility to the process of comparing data from different databases by using two fairly simple annotations. For this particular case, annotations drive the data comparison process, so that essentially we evaluate the annotations we find in the shared data and use them to guide processing. Conclusion There are many articles on annotations in Java, what they do and what are the rules for using them. In this article I wanted to show, through examples, why you should use them and how you can benefit from it. Please note that this is just the beginning. Once you decide to create annotations, you will have to figure out how to use them in the most effective way. In Part 2, I'll show you how to process annotations using Java reflection. — Jonny Hackett, asktheteam@keyholesoftware.com original article http://www.javacodegeeks.com/2014/07/creating-your-own-java-annotations.html
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION