- PVSM.RU - https://www.pvsm.ru -

Validation DSL на Groovy

Одна из часто встречающихся проблем императивных языков программирования это отсутствие выражений для декларативных структур, таких как, к примеру, древовидные разметки или набор правил для обработки данных. В Groovy эта проблема решена с помощью классов типа Builder [1] и мета-программированием [2] на уровне абстрактного синтаксического дерева.

В свою очередь, обработка входных данных — один из неотъемлемых этапов работы клиент-серверных приложений. Этот процесс часто описывается последовательностью из if-oв и соответствующих исключений. При большом количестве параметров такой код становится плохо читаем и делает его анализ на предмет корректности нетривиальной задачей. Так, зачастую логика при обработки данных «размазана» по нескольким методам и классам. К тому же при появлении нового параметра легко забыть о его проверке и нормализации (форматировании, экранировании символов и т.д.). В качестве решения этой проблемы была написана Groovy библиотека позволяющая описывать эти правила в декларативном стиле с помощью DSL. Например, следующий скрипт обрабатывает шесть входящих параметров: адрес почты, логин, пол, состояние чекбокса «Согласен с регламентом», вес и дату.

import org.grules.console.Gender

// isEmail это обычный Java/Groovy метод, принимающий один параметр — email. Для использования собственного метода достаточно импортировать его в скрипт с помощью import static.
email isEmail ["Invalid email"]

// Оператор >> разделяет два последовательных подправила — isAlpha и isUnique. invalidLoginМеssage и dupLoginМеssage это строки сообщений об ошибках. 
login isAlpha [invalidLoginМеssage] >> isUnique [dupLoginМеssage]

// Gender это Java enum. Если входной параметр gender не задан, то ему присваивается строка "MALE". В качестве значения по умолчанию может выступать любой Groovy объект.
gender["MALE"] toEnum(Gender)

// m представляет собой ResourceBundle, соответственно m.agreeToTerms — интернационализированная строка.
termsCondition[""] !isEmpty [m.agreeToTerms]

// Вместо вызoва метода есть возможность использовать замыкания. В этом случае обращение к параметру осуществляется через переменную it.
weight toPositiveBigDecimal [decimalErr] >> {round it / 1000}

// Поддерживаются логические операции &&, || и !. В качестве значения параметра может выступать как строка так и любой другой тип данных.
endDate isAfterNow && isBefore(deadline) &

Результатом выполнения скрипта является отчет в виде Java объекта с параметрами, разделенными на пять групп:

  • корректные
  • не прошедшие валидацию
  • отсутствующие во входных данных
  • для которых не было найдено соответствующего правила препроцессинга
  • с ненайденными или невалидными зависимостями на другие параметры

В случае с DSL ход валидации находится под управлением библиотеки, что соответственно позволяет выполнять операции на мета-уровне, например собирать статистику по каждому параметру или генерировать клиентский код на Javascript. В Java схожий функционал доступен с помощью аннотаций, но отсутствие доступа к AST и поддержки непримитивных типов данных ограничивает область их применения.

Все что необходимо от разработчика чтобы начать использовать DSL это включить библиотеку в classpath проекта (к примеру через Мaven [3]) и создать Groovy скрипт с суфиксом Grules и описанием правил обработки для всех или некорых параметров.

Детальнее с проектом можно ознакомиться на следующих ресурсах: wiki [4], онлайн консоль [5], github [6], публикация [7] (английский).

Автор: zhaber

Источник [8]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/groovy/21620

Ссылки в тексте:

[1] Builder: http://groovy.codehaus.org/Creating+XML+using+Groovy's+MarkupBuilder

[2] мета-программированием: http://groovy.codehaus.org/Compile-time+Metaprogramming+-+AST+Transformations

[3] через Мaven: http://search.maven.org/#artifactdetails%7Corg.grules%7Cgrules%7C0.2.0.8%7Cjar

[4] wiki: https://github.com/zhaber/grules/wiki

[5] онлайн консоль: http://grules-console.appspot.com

[6] github: https://github.com/zhaber/grules

[7] публикация: http://digitalcommons.mcmaster.ca/cgi/viewcontent.cgi?article=8244&context=opendissertations

[8] Источник: http://habrahabr.ru/post/160085/