Одна из часто встречающихся проблем императивных языков программирования это отсутствие выражений для декларативных структур, таких как, к примеру, древовидные разметки или набор правил для обработки данных. В Groovy эта проблема решена с помощью классов типа Builder и мета-программированием на уровне абстрактного синтаксического дерева.
В свою очередь, обработка входных данных — один из неотъемлемых этапов работы клиент-серверных приложений. Этот процесс часто описывается последовательностью из if-oв и соответствующих исключений. При большом количестве параметров такой код становится плохо читаем и делает его анализ на предмет корректности нетривиальной задачей. Так, зачастую логика препроцессинга данных «размазана» по нескольким методам и классам. К тому же при появлении нового параметра легко забыть о его проверке и нормализации (форматировании, экранировании символов и т.д.). В качестве решения этой проблемы была написана Groovy библиотека позволяющая описывать эти правила в декларативном стиле с помощью DSL. Например, следующий скрипт обрабатывает шесть входящих параметров: адрес почты, логин, пол, состояние чекбокса «Согласен с регламентом», вес и дату.
Результатом выполнения скрипта является отчет в виде Java объекта с параметрами, разделенными на пять групп:
В случае с DSL ход валидации находится под управлением библиотеки, что соответственно позволяет выполнять операции на мета-уровне, например собирать статистику по каждому параметру или генерировать клиентский код на Javascript. В Java схожий функционал доступен с помощью аннотаций, но отсутствие доступа к AST и поддержки непримитивных типов данных ограничивает область их применения.
Все что необходимо от разработчика чтобы начать использовать DSL это включить библиотеку в classpath проекта (к примеру через Мaven) и создать Groovy скрипт с суфиксом Grules и описанием правил обработки для всех или некоторых параметров.
«HelloWorld» проект состоит из трех файлов:
HelloGrules.groovy
Test.groovy
build.gradle
Для запуска выполните команду
Детальнее с проектом можно ознакомиться на следующих ресурсах: wiki, онлайн консоль, github, публикация (английский).
В свою очередь, обработка входных данных — один из неотъемлемых этапов работы клиент-серверных приложений. Этот процесс часто описывается последовательностью из 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) && {it.day != 1}
Результатом выполнения скрипта является отчет в виде Java объекта с параметрами, разделенными на пять групп:
- корректные
- не прошедшие валидацию
- отсутствующие во входных данных
- для которых не было найдено соответствующего правила препроцессинга
- с ненайденными или невалидными зависимостями на другие параметры
В случае с DSL ход валидации находится под управлением библиотеки, что соответственно позволяет выполнять операции на мета-уровне, например собирать статистику по каждому параметру или генерировать клиентский код на Javascript. В Java схожий функционал доступен с помощью аннотаций, но отсутствие доступа к AST и поддержки непримитивных типов данных ограничивает область их применения.
Все что необходимо от разработчика чтобы начать использовать DSL это включить библиотеку в classpath проекта (к примеру через Мaven) и создать Groovy скрипт с суфиксом Grules и описанием правил обработки для всех или некоторых параметров.
«HelloWorld» проект состоит из трех файлов:
HelloGrules.groovy
package test
email isEmail ["Invalid email"]
age toPositiveInt ["Invalid age"] >> {it > 18} ["You must be adult"]
Test.groovy
package test
import org.grules.Grules
class Test {
public static void main(String[] s) {
def grules = new Grules()
def result = grules.applyRules(HelloGrules, [email: "megmail.com", age: "35"])
assert result.cleanParameters.age == 35
assert "email" in result.invalidParameters
assert result.invalidParameters.email.errorId == "Invalid email"
println result
}
}
build.gradle
apply plugin: 'application'
apply plugin: 'groovy'
apply plugin: 'maven'
repositories {
mavenCentral()
}
mainClassName = "test.Test"
dependencies {
groovy 'org.codehaus.groovy:groovy:2.0.5' exclude group: 'asm', module: 'asm'
compile 'org.grules:grules:0.2.0.8' exclude group: 'asm', module: 'asm'
}
Для запуска выполните команду
gradle run
в корневой директории.Детальнее с проектом можно ознакомиться на следующих ресурсах: wiki, онлайн консоль, github, публикация (английский).