JavaRush /Java блог /Random UA /Створення своїх анотацій у Java
angelina
5 рівень

Створення своїх анотацій у Java

Стаття з групи Random UA
стаття Джонні Хакета (Jonny Hackett) 14го Липня, 2014 11:09 Якщо ви програмуєте на Java і використовуєте будь-яку з популярних фреймворків, такі як Spring та Hibernateтоді ви вже знайомі з використанням анотацій. У роботі з існуючою фреймворк - внутрішніх анотацій цілком достатньо. Але що якщо вам знадобиться створити свої власні анотації? Нещодавно в мене з'явилася причина створити свої власні інструкції для проекту, в якому вимагалося підтвердження загальної інформації з кількох баз даних. Сценарій У бізнесу було кілька баз даних, в яких було збережено однакову інформацію, і дані оновлювалися різними способами. Було заплановано поєднати дані в одну основну базу даних, щоб усунути проблеми, пов'язані з отриманням даних із різних джерел. Але перш ніж розпочати проект, слід з'ясувати, наскільки дані були розсинхронізовані і внести необхідні зміни. Першим кроком було створення звіту, який би відображав однакові дані в різних базах даних і підтвердити значення, або виділити записи, які не збігалися, на основі встановлених правил звірки. Нижче наведено витримку основних вимог на момент проекту: • Порівняти дані в декількох базах даних щодо пошуку однакових даних, таких як ім'я клієнта, компанії або інформація в каталозі. • За промовчанням значення має точно співпадати у всіх базах даних, ґрунтуючись на типі даних. • Для деяких полів ми хотіли показати, що значення знайдено, але значення не порівнювалося. • Для інших полів ми хотіли лише порівняти значення зі знайденим та підтвердити дані з даними із зазначеного джерела. • Для третіх полів ми хотіли зробити складно порівняння даних, яке базувалося б на значенні інших полів усередині запису. • Для четвертого типу полів ми хотіли відформатувати дані, наприклад, у грошовий формат $000,000.00. • Звіт повинен бути у форматі MS Excel, кожен рядок повинен містити значення з окремого джерела. Будь-який рядок, значення якого не збігається з умовами підтвердження даних, має бути виділено жовтим. Анотації Після того, як ми прочитали вимоги та озвучабо кілька різних ідей втілення того, що потрібно, я вирішив використати анотації, які запустять конфігурацію порівняння даних та процес звіту. Нам потрібно просто, але гнучке і розширюване рішення. Ці інструкції будуть на рівні поля і мені сподобалося те, що конфігурацію не буде прихована у файлі, десь в дорозі класу. Натомість я зможу бачити анотації асоційовані з полем, щоб точно знати, як воно буде оброблено. Простіше кажучи - інструкція буде нічим іншим як маркером, метаданою яка надаватиме інформацію, але не буде безпосередньо впливати на роботу самого коду. Якщо ви вже програмували на Java, то вам має бути знайоме використання анотація, але можливо вам ніколи не потрібно створювати свої власні. @interface , який міститиме елементи, які в свою чергу визначають деталі метаданих. Ось приклад проекту: 1@Target(ElementType.FIELD) 2@Retention(RetentionPolicy.RUNTIME) 3public @interface ReconField { 4 5 /** 6 * Значение, которое определяет из якого источника сравниваются данные, або будет использоваться для 7 отображения значения або для ссылки на правило. 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 * Значение, показывающее значення 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 } Це основна інструкція, за допомогою якої запуститься процес порівняння даних. Вона містить основні необхідні елементи відповідно до вимог для порівняння даних з різних джерел даних. @ReconField має впоратися з більшістю того, що нам потрібно, за винятком складніших порівнянь даних, про які ми поговоримо пізніше. Більшість цих елементів пояснюються коментарями в коді. Незважаючи на це пара основних анотацій в нашому @ReconField повинні бути пояснені окремо. • @Target– Ця інструкція дозволить вам вказати ті java елементи, до якої анотація має бути застосована. Можливі типи для застосування такі: ANNOTATION_TYPE, CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER та TYPE. У нашій @ReconField інструкція для рівня FIELD. • @Retention– Ця інструкція дозволить вам вказати, коли інструкція буде доступна. Можливі значення: CLASS, RUNTIME та SOURCE. Так як ми будемо обробляти інструкції в RUNTIME, ми повинні встановити ці значення. Процес підтвердження даних буде йти в один запит до кожної бази даних, а потім відобразить результати в загальних даних, які являють собою всі поля для певного типу запису. Анотація для кожного поля в загальних даних повідомить процесору як робити порівняння даних для цього певного поля, а також значення, знайдене в кожній базі даних. Давайте подивимося на кілька прикладів того, як ці інструкції можуть бути використані для різних конфігурацій порівняння даних. Щоб підтвердити, що значення існує і точно відповідає кожному джерелу даних, вам всього лише треба надати ID поля і ярлик, 1 @ReconField(id = CUSTOMER_ID, label = "Customer ID") 2 private String customerId; Щоб відобразити знайдені значення з кожного джерела даних, але робити порівняння даних, потрібно вказати елемент compareSources і поставити значення на false. 1 @ReconField(id = NAME, label = "NAME", compareSources = false) 2 private String name; Щоб підтвердити, що значення знайдено в певному джерелі даних, але не в усіх, вам потрібно використовувати елемент sourcesToCompare . Це відображатиме всі знайдені значення, але порівняння будь-яких даних у джерелах даних відбудеться відповідно до списку елементів. Це для випадку, якщо деякі дані не збережені у всіх джерелах даних. ReconSource - це enum, у якому джерела даних доступні порівняння. 1 @ReconField(id = PRIVATE_PLACEMENT_FLAG, label = "PRIVATE PLACEMENT FLAG", sourcesToCompare ={ 2 ReconSource.LEGACY, ReconSource.PACE }) private String privatePlacementFlag; Тепер, коли ми виконали основні вимоги, нам потрібно виконати порівняння більш складних даних, які є специфічними для поля. Щоб зробити це, ми створимо другу анотацію, яка запустить обробку правил. 1 @Target(ElementType.FIELD) 2 @Retention(RetentionPolicy.RUNTIME) 3 public @interface ReconCustomRule { 4 5 /** 6 * Значение, указывающее используемые параметры, прописанные обработчику правила, значення по умолчанию - 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 } Дуже схоже на попередню анотацію, одна велика різниця в тому, що @ReconCustomRuleми вказуємо клас, який запустить порівняння даних, коли запускається процес recon. Ви можете вказати лише клас, який буде використаний, щоб ваш обробник приписав значення та ініціалізував будь-який клас, який ви вкажете. Зазначений клас у цій інструкції, буде використовувати інтерфейс правила, який у свою чергу буде використаний обробником для виконання правила. Давайте подивимося кілька прикладів цієї інструкції. У цьому прикладі ми використовуємо правило, яке перевірить обмін валюти над США і у разі пропустить порівняння даних. Щоб зробити це, нам треба перевірити поле країни у тому ж записі. 1 @ReconField(id = STREET_CUSIP, label = "STREET CUSIP", compareSources = false) 2 @ReconCustomRule(processor = SkipNonUSExchangeComparisonRule.class) 3 private String streetCusip; Ось приклад, у якому ми задаємо параметри правила, у разі значення допустимого відхилення. Для порівняння наших даних порівнюване значення не може відхилятися більш ніж на 1,000. Використовуючи параметр для вказівки значення відхилення, дозволить нам використовувати те ж правило для декількох полів, з різним значенням допустимого відхилення. Єдина проблема в тому, що ці параметри статичні і не можуть бути динамічними через природу інструкції. 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; Як ви бачите внесли трохи гнучкості в процес порівняння даних з різних баз даних, використовуючи дві досить прості інструкції. Для даного конкретного випадку анотації керують процесом порівняння даних, так що по суті ми оцінюємо анотації, які ми знаходимо у загальних даних та використовуємо їх, щоб спрямовувати обробку. Висновок Є безліч статей з анотаціями в Java, що вони роблять і які правила їх використання. У цій статті я хотіла показати, на основі прикладів, чому вам слід використовувати їх і які вигоди від цього ви можете отримати. Врахуйте, що це лише початок. Як тільки ви вирішите створити анотації, вам доведеться зрозуміти, як їх використовувати найбільш ефективним способом. У другій частині, я покажу вам як обробляти інструкції, використовуючи Java reflection. - Jonny Hackett, asktheteam@keyholesoftware.com оригінал статті http://www.javacodegeeks.com/2014/07/creating-your-own-java-annotations.html
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ