5.12. Справочник по Groovy
Справочник по Groovy
1. Типы данных
Простые типы
null— отсутствие значения.boolean— логическое значение:true,false.char— одиночный символ в одинарных кавычках:'A'.int,long,BigInteger— целочисленные типы.float,double,BigDecimal— числа с плавающей точкой.
Строки
- GString (
"...") — интерполируемая строка, поддерживает выражения${выражение}. - String (
'...') — обычная строка без интерполяции. - Triple-quoted string (
'''...''') — многострочная строка без интерполяции. - Slashy string (
/.../) — удобна для регулярных выражений, не требует экранирования слешей. - Dollar-slashy string (
$/.../$) — многострочная строка с интерполяцией и минимальным экранированием.
Коллекции
- List — упорядоченный список, изменяемый по умолчанию:
def list = [1, 2, 3] - Set — множество уникальных элементов:
def set = [1, 2, 3] as Set - Map — ассоциативный массив:
def map = [name: 'Alice', age: 30]
Диапазоны (Ranges)
- Используются для перебора значений:
def range = 1..5 // включительно
def exclusive = 1..<5 // исключительно
Файлы и ресурсы
- Объект
Fileиспользуется напрямую из Java. - Groovy добавляет методы вроде
eachLine,splitEachLine,withReader.
2. Операторы
Арифметические
+,-,*,/,%,**(возведение в степень)
Логические
&&,||,!
Побитовые
&,|,^,~,<<,>>,>>>
Операторы сравнения
==,!=,<,<=,>,>=- Groovy переопределяет
==как вызов.equals(), а не сравнение ссылок.
Операторы присваивания
=,+=,-=,*=,/=,%=,**=,&=,|=,^=,<<=,>>=,>>>=
Операторы безопасной навигации
?.— вызов метода или доступ к свойству только если объект не null:person?.address?.city
Оператор Elvis
?:— возвращает левый операнд, если он не null и не false; иначе — правый:name = providedName ?: 'Anonymous'
Оператор распространения (Spread operator)
*.— применяет метод ко всем элементам коллекции:names*.toUpperCase()
Оператор объединения списков
+— объединяет списки или карты.-— удаляет элементы из списка или ключи из карты.
Оператор индексации
[]— доступ к элементу по индексу или ключу:list[0], map['key'], map.key
Оператор диапазона
..,..<
Оператор замыкания
{ параметры -> тело }
3. Управляющие конструкции
Условные операторы
if / else if / elseswitch / case— поддерживает сопоставление с любыми типами, включая классы, регулярные выражения, замыкания.
Циклы
for (i in collection)— итерация по коллекции, диапазону, массиву.while (condition) { ... }loop.each { item -> ... }— функциональный стиль через замыкания.
Обработка исключений
try / catch / finally— стандартный механизм Java, полностью поддерживается.
4. Методы и функции
Объявление
- Методы объявляются с помощью ключевого слова
defили явного типа возврата:def greet(name) { "Hello, $name!" }
String greet(String name) { "Hello, $name!" }
Необязательные параметры
- Поддерживаются значения по умолчанию:
def log(message, level = 'INFO') { ... }
Переменное число аргументов
- Используется оператор
...:def sum(int... numbers) { numbers.sum() }
Явный возврат
- Последнее выражение в методе автоматически возвращается, но можно использовать
return.
5. Классы и объекты
Объявление класса
class Person {
String name
int age
String toString() { "$name ($age)" }
}
Автоматические геттеры и сеттеры
- Все поля получают геттеры и сеттеры по соглашению.
Конструкторы
- Конструктор по умолчанию принимает
Map:def p = new Person(name: 'Bob', age: 25)
Наследование
- Поддерживается через
extends.
Интерфейсы и трейты
- Интерфейсы работают как в Java.
- Traits — мощный механизм повторного использования кода:
trait Flyable { void fly() { println "Flying!" } }
class Bird implements Flyable { }
Аннотации
- Поддерживаются все Java-аннотации.
- Groovy предоставляет собственные аннотации:
@CompileStatic,@TypeChecked,@Delegate,@Lazy,@Immutable,@Sortable,@Canonical, и другие.
6. Замыкания (Closures)
Синтаксис
{ param1, param2 -> body }
Неявные параметры
it— имя по умолчанию для единственного параметра:[1, 2, 3].each { println it }
Делегирование
- Замыкание может иметь
delegate, который определяет контекст выполнения:closure.delegate = someObject
closure.resolveStrategy = Closure.DELEGATE_FIRST
Полезные методы для замыканий
call(),curry(),rcurry(),memoize(),trampoline()
7. Коллекции и их методы
List
size(),isEmpty(),get(index),putAt(index, value)each,collect,findAll,any,every,groupBy,sort,reverse,unique,flatten,sum,min,max
Map
keySet(),values(),entrySet()each,collectEntries,findAll,any,every,groupBy,subMap
String
eachMatch(regex),tokenize(),padLeft(),padRight(),toInteger(),toDouble(),replaceAll(),eachLine()
8. Метапрограммирование
Runtime metaprogramming
- Добавление методов и свойств во время выполнения:
Person.metaClass.greet = { -> "Hi from $name" }
ExpandoMetaClass
- Включается глобально или для конкретного класса.
methodMissing / propertyMissing
- Перехват вызовов несуществующих методов или свойств.
invokeMethod
- Перехват всех вызовов методов объекта.
Categories
- Временное расширение поведения классов в блоке
use.
AST Transformations (compile-time)
- Изменяют дерево абстрактного синтаксиса на этапе компиляции.
- Примеры:
@ToString,@EqualsAndHashCode,@TupleConstructor,@Bindable,@ListenerList
9. Компиляция и настройки
Режимы компиляции
- Dynamic — поведение по умолчанию, проверка типов во время выполнения.
- Static compilation — через
@CompileStatic, обеспечивает производительность как у Java. - Type checking — через
@TypeChecked, проверяет типы, но оставляет динамическое поведение.
Параметры компилятора Groovy
indy— использование invokedynamic (JDK 7+).encoding— кодировка исходного файла.targetBytecode— версия байткода (например,1.8,11,17).parameters— сохранение имён параметров в байткоде.previewFeatures— включение preview-функций JDK.
Конфигурация через groovyOptions
В Gradle:
compileGroovy {
groovyOptions.optimizationOptions.indy = true
groovyOptions.configurationScript = file('config.groovy')
}
10. Интеграция с Java
- Любой Java-класс доступен напрямую.
- Groovy-классы компилируются в байткод JVM и могут использоваться из Java.
- Совместимость с Java Collections API, Streams, Optional и другими конструкциями.
11. DSL и скриптование
GroovyShell
- Выполнение строк как кода:
new GroovyShell().evaluate('2 + 3')
GroovyScriptEngine
- Загрузка и выполнение скриптов из файлов.
Builder-паттерн
- Встроенные
MarkupBuilder,JsonBuilder,StreamingJsonBuilder,ObjectGraphBuilder.
Пример:
def builder = new MarkupBuilder()
builder.person {
name 'Alice'
age 30
}
12. Распространённые утилиты и расширения
Расширения для чисел
times { ... }— повторить действие N раз.upto(to) { ... },downto(to) { ... }
Расширения для файлов
eachFile,eachDir,deleteDir(),getText(),write(text)
Расширения для потоков
withStream { ... },withWriter { ... }
Расширения для дат
Date.plus(days),Date.minus(days),parse(format, string)
13. Безопасность и ограничения
- При выполнении внешних скриптов используйте
SecureASTCustomizerдля ограничения доступа к опасным API. - Отключите возможность создания новых классов, вызова
System.exit, доступа к файловой системе и т.п.
Пример:
def secure = new SecureASTCustomizer()
secure.closuresAllowed = false
secure.methodDefinitionAllowed = false
14. AST-трансформации (Compile-time Metaprogramming)
Groovy позволяет изменять структуру кода на этапе компиляции через аннотации, которые преобразуют абстрактное синтаксическое дерево (AST). Это мощный механизм для генерации кода без рантайм-накладных расходов.
Встроенные AST-трансформации
@Canonical
Объединяет @ToString, @EqualsAndHashCode, @TupleConstructor:
@Canonical
class Person {
String name
int age
}
@ToString
Генерирует метод toString():
@ToString(includeNames = true, includePackage = false)
class Point { int x, y }
// Результат: Point(x:10, y:20)
Параметры:
includeNames— добавлять имена полей.includePackage— включать имя пакета.excludes— исключить поля.includes— включить только указанные поля.
@EqualsAndHashCode
Генерирует equals() и hashCode().
@TupleConstructor
Создаёт конструктор на основе полей:
@TupleConstructor
class Point { int x, y }
def p = new Point(1, 2)
@Immutable
Делает класс неизменяемым:
- Все поля становятся
final. - Генерируются геттеры.
- Коллекции оборачиваются в неизменяемые обёртки.
- Класс объявляется
final.
@Sortable
Добавляет реализацию Comparable и статические методы comparatorBy*.
@Delegate
Делегирует вызовы методов другому объекту:
class Engine {
void start() { println "Engine started" }
}
class Car {
@Delegate Engine engine = new Engine()
}
new Car().start() // вызывает engine.start()
@Lazy
Ленивая инициализация поля:
class Heavy {
@Lazy def resource = { /* expensive init */ }()
}
@Synchronized
Автоматически оборачивает метод в synchronized.
@Field
Превращает переменную в поле класса (в скриптах):
@Field String name = 'Alice'
@PackageScope
Делает член класса доступным только в пределах пакета.
@Bindable и @Vetoable
Используются в GUI-приложениях для поддержки property change listeners.
15. Расширенное метапрограммирование
ExpandoMetaClass
Позволяет динамически добавлять методы, свойства, статические методы:
String.metaClass.shout = { -> delegate.toUpperCase() + '!' }
println "hello".shout() // HELLO!
Включение глобально:
ExpandoMetaClass.enableGlobally()
methodMissing и propertyMissing
Перехват несуществующих вызовов:
class Dynamic {
def methodMissing(String name, args) {
return "Called $name with ${args.join(', ')}"
}
}
invokeMethod
Перехват всех вызовов методов (включая существующие, если metaClass.invokeMethod переопределён).
getProperty / setProperty
Контроль доступа к свойствам.
Categories
Временное расширение поведения:
class NumberUtils {
static double square(Number n) { n * n }
}
use(NumberUtils) {
println 5.square() // 25.0
}
16. Работа с данными
JSON
Чтение
def json = new JsonSlurper().parseText('{"name":"Alice"}')
println json.name
Запись
def builder = new JsonBuilder()
builder.person {
name 'Alice'
age 30
}
println builder.toPrettyString()
StreamingJsonBuilder
Для больших объёмов данных:
def writer = new StringWriter()
def builder = new StreamingJsonBuilder(writer)
builder.people {
person { name 'Alice' }
}
XML
Parsing
def xml = '''
<books>
<book title="Groovy Guide"/>
</books>
'''
def data = new XmlSlurper().parseText(xml)
println data.book[0].@title
Построение
def builder = new MarkupBuilder()
builder.books {
book(title: 'Groovy Guide')
}
XPath-подобные запросы
data.book.findAll { it.@year.toInteger() > 2020 }
17. Шаблоны
SimpleTemplateEngine
Поддерживает ${выражения}:
def engine = new SimpleTemplateEngine()
def template = engine.createTemplate('Hello, $name!')
def result = template.make(name: 'Alice')
GStringTemplateEngine
Более мощный, поддерживает логику внутри шаблона.
XmlTemplateEngine
Для генерации XML с логикой.
18. Интеграция с Gradle
Groovy — основной язык написания скриптов сборки в Gradle (до появления Kotlin DSL).
Пример build.gradle:
plugins {
id 'groovy'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.codehaus.groovy:groovy-all:4.0.15'
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
}
Кастомные задачи на Groovy
task hello {
doLast {
println "Hello from Groovy in Gradle!"
}
}
Конфигурация компилятора
compileGroovy {
groovyOptions.optimizationOptions.indy = true
groovyOptions.targetBytecode = '17'
}
19. Тестирование: Spock Framework
Spock — BDD-фреймворк на Groovy, сочетающий выразительность и мощь.
Структура спецификации
class MathSpec extends Specification {
def "sum of two numbers"() {
expect:
a + b == c
where:
a | b || c
1 | 2 || 3
4 | 5 || 9
}
}
Блоки
given— подготовкаwhen— действиеthen— проверкаexpect— комбинация when/thenwhere— параметризацияcleanup— завершениеsetup— аналог@Before
Моки и спайки
def service = Mock(Service)
service.process(_) >> "OK"
20. Производительность и оптимизация
Статическая компиляция
Используйте @CompileStatic для критичных к производительности участков:
@CompileStatic
int factorial(int n) {
n <= 1 ? 1 : n * factorial(n - 1)
}
Избегайте динамических вызовов в циклах
Кэшируйте методы или используйте интерфейсы.
Используйте @TypeChecked для поиска ошибок
Проверяет типы, но сохраняет динамические возможности при необходимости.
invokedynamic (indy)
Включите флаг -indy при компиляции для ускорения вызовов замыканий и динамических методов (требует JDK 7+).
Профилирование
Используйте VisualVM, JProfiler или async-profiler для анализа узких мест.
21. Практическое применение Groovy
Скрипты автоматизации
- Обработка логов
- Генерация конфигураций
- Миграции данных
DSL для конфигурации
server {
port 8080
host 'localhost'
ssl enabled: true
}
Jenkins Pipelines
Declarative и Scripted Pipelines на Groovy.
Тестовые фреймворки
- Spock
- Geb (для UI-тестов)
Встраивание в Java-приложения
- Через
GroovyShell - Через
GroovyScriptEngineдля горячей замены логики
22. Версии и совместимость
- Groovy 2.x — поддержка JDK 6–8, начало AST-трансформаций.
- Groovy 3.x — поддержка Java 8+, новые операторы (
!in,!instanceof), улучшенная совместимость с Java. - Groovy 4.x — поддержка JDK 17, улучшенная статическая компиляция, модульность, Jakarta EE.
Рекомендуется использовать Groovy 4.0+ для новых проектов.
23. Ограничения и предостережения
- Динамическая природа снижает производительность по сравнению с Java.
- Отладка динамического кода сложнее.
- Некоторые IDE хуже поддерживают Groovy, чем Java.
- При смешивании с Java возможны неочевидные ошибки из-за различий в семантике
==,in,[].
24. Встроенные методы расширений (GDK — Groovy Development Kit)
Groovy автоматически добавляет сотни полезных методов к стандартным классам Java через механизм метаклассов. Эти методы определены в классах:
DefaultGroovyMethods— для большинства объектовDefaultGroovyStaticMethods— статические методыStringGroovyMethods,FileGroovyMethods,IOGroovyMethods,SqlGroovyMethodsи др.
Эти методы доступны везде, без импорта.
Общие методы для коллекций
each
[1, 2, 3].each { println it }
collect
Преобразует каждый элемент:
[1, 2, 3].collect { it * 2 } // [2, 4, 6]
findAll / grep
Фильтрация:
[1, 2, 3, 4].findAll { it % 2 == 0 } // [2, 4]
['a1', 'b2', 'c3'].grep(~/\d$/) // строки, оканчивающиеся цифрой
any / every
Проверка условий:
[1, 2, 3].any { it > 2 } // true
[1, 2, 3].every { it > 0 } // true
groupBy
Группировка:
['apple', 'banana', 'cherry'].groupBy { it[0] }
// [a:['apple'], b:['banana'], c:['cherry']]
sum, min, max
[1, 2, 3].sum() // 6
[1, 2, 3].max() // 3
inject (аналог reduce)
[1, 2, 3].inject(0) { acc, val -> acc + val } // 6
flatten
Разворачивает вложенные коллекции:
[[1, 2], [3, 4]].flatten() // [1, 2, 3, 4]
unique
Удаляет дубликаты:
[1, 2, 2, 3].unique() // [1, 2, 3]
sort
Сортировка:
[3, 1, 2].sort() // [1, 2, 3]
people.sort { it.age }
reverse
Инверсия порядка.
pop, push, shift, unshift
Для работы как со стеком или очередью:
def stack = [1, 2, 3]
stack.push(4) // [1, 2, 3, 4]
stack.pop() // 4
Примечание:
push/popработают с концом списка,shift/unshift— с началом.
Методы для строк
toInteger(), toDouble(), toBoolean()
Безопасное преобразование:
'123'.toInteger() // 123
'false'.toBoolean() // false
padLeft(), padRight()
'5'.padLeft(3, '0') // '005'
tokenize()
Разделение без регулярных выражений:
'a,b,c'.tokenize(',') // ['a', 'b', 'c']
eachMatch(regex)
Итерация по совпадениям:
'abc123def456'.eachMatch(/\d+/) { match -> println match[0] }
// 123
// 456
contains(), startsWith(), endsWith() — уже есть в Java, но Groovy делает их null-safe.
Методы для файлов и потоков
eachLine
new File('data.txt').eachLine { line -> println line }
splitEachLine
file.splitEachLine(/\t/) { parts -> println parts[0] }
withReader, withWriter, withInputStream, withOutputStream
Автоматическое закрытие ресурсов:
file.withReader { reader -> ... }
getText(), write(text), append(text)
def content = file.getText('UTF-8')
file.write('Hello', 'UTF-8')
eachFile, eachDir, traverse
Рекурсивный обход:
dir.traverse { file -> if (file.name.endsWith('.groovy')) println file }
deleteDir()
Рекурсивное удаление каталога.
Методы для чисел
times
5.times { println 'Hello' }
upto, downto
1.upto(3) { println it } // 1, 2, 3
5.downto(3) { println it } // 5, 4, 3
step
0.step(10, 2) { println it } // 0, 2, 4, 6, 8
Методы для карт (Map)
get(key, defaultValue)
map.get('name', 'Unknown')
subMap(keys)
map.subMap(['name', 'age'])
collectEntries
Преобразование в новую карту:
[1, 2, 3].collectEntries { [it, it * it] } // [1:1, 2:4, 3:9]
each, eachWithIndex
map.each { key, value -> println "$key = $value" }
25. Регулярные выражения
Groovy упрощает работу с регулярками.
Создание
- Используйте slashy strings (
/.../) — не нужно экранировать\:def pattern = /\d{3}-\d{2}-\d{4}/
Сопоставление
- Оператор
==~— полное совпадение:'123-45-6789' ==~ /\d{3}-\d{2}-\d{4}/ // true - Оператор
=~— частичное совпадение, возвращаетjava.util.regex.Matcher:def matcher = 'ID: 123' =~ /(\d+)/
if (matcher) {
println matcher[0][1] // '123'
}
Замена
'Price: $100'.replaceFirst(/\$(\d+)/) { all, amount -> "€${amount}" }
// Price: €100
Группы
def m = 'John Doe' =~ /(\w+) (\w+)/
if (m) {
def (full, first, last) = m[0]
println "First: $first, Last: $last"
}
26. Многопоточность и параллелизм
GPars (Groovy Parallel Systems)
Хотя GPars больше не активно развивается, его идеи повлияли на современные подходы. В Groovy 4+ рекомендуется использовать Java concurrency utilities, но с Groovy-синтаксисом.
Пример с ExecutorService
def service = Executors.newFixedThreadPool(4)
def futures = (1..10).collect {
service.submit { it * it }
}
futures*.get().each { println it }
service.shutdown()
Параллельная обработка коллекций
def results = [1, 2, 3, 4].parallelStream().map { it * 2 }.toList()
Groovy не добавляет собственных примитивов для async/await, но легко интегрируется с CompletableFuture:
def future = CompletableFuture.supplyAsync { 42 }
future.thenAccept { println it }.join()
27. Управление ресурсами и замыкания
Groovy поощряет использование замыканий для управления жизненным циклом:
new File('input.txt').withReader { reader ->
new File('output.txt').withWriter { writer ->
reader.eachLine { line ->
writer.println line.toUpperCase()
}
}
}
Аналогично для:
- Баз данных (
Sql.withInstance) - HTTP-соединений
- ZIP-архивов
- Сокетов
Это гарантирует вызов close(), даже при исключении.
28. Практические паттерны использования
1. Конфигурационные файлы
config.groovy:
server {
port = 8080
ssl = true
hosts = ['localhost', '127.0.0.1']
}
Загрузка:
def config = new ConfigSlurper().parse(new File('config.groovy').toURL())
println config.server.port
2. ETL-скрипты
new File('input.csv').splitEachLine(',') { fields ->
def record = [id: fields[0], name: fields[1]]
if (record.name) db.insert(record)
}
3. Генерация кода
def template = '''
class ${className} {
${fields.collect { "String $it" }.join('\n ')}
}
'''
def engine = new SimpleTemplateEngine()
println engine.createTemplate(template).make(className: 'User', fields: ['name', 'email'])
4. Административные скрипты
- Очистка логов
- Архивирование
- Мониторинг
5. Jenkins Shared Libraries
DSL на Groovy для стандартизации CI/CD.
29. Инструменты и экосистема
| Инструмент | Назначение |
|---|---|
| Groovy Console | Интерактивная среда выполнения |
| GroovyShell | REPL для экспериментов |
| Gradle | Сборка и управление зависимостями |
| Spock | Тестирование |
| Geb | UI-тестирование (Selenium + jQuery-подобный синтаксис) |
| Ratpack | Лёгкий фреймворк для веб-API |
| Grails | Full-stack веб-фреймворк (на базе Spring Boot) |
30. Советы по стилю и читаемости
- Используйте
defтолько когда тип не важен или выводится. - Предпочитайте
@CompileStaticв производственном коде. - Избегайте глобального метапрограммирования в больших проектах.
- Используйте
ConfigSlurperвместо Properties. - Пишите DSL с
Closure.DELEGATE_FIRST. - Для скриптов — минимум зависимостей, максимум автономности.
31. Структура типичного Groovy-проекта
Groovy не навязывает жёсткой структуры, но следует общепринятым соглашениям JVM-экосистемы, особенно если используется Gradle или Maven.
Минимальная структура (скриптовый проект)
my-groovy-project/
├── scripts/
│ ├── deploy.groovy
│ └── backup.groovy
├── lib/
│ └── helpers.groovy
├── config/
│ └── app.groovy
└── README.md
Стандартная структура (Gradle-проект)
src/
├── main/
│ ├── groovy/ # основной код
│ └── resources/ # конфиги, шаблоны, данные
└── test/
├── groovy/ # тесты (Spock, JUnit)
└── resources/ # тестовые ресурсы
build.gradle
gradle.properties
settings.gradle
Модульный проект (несколько подпроектов)
project-root/
├── core/ # ядро: DSL, утилиты
├── cli/ # командная оболочка
├── web/ # веб-интерфейс (Ratpack/Grails)
├── scripts/ # автономные скрипты
└── build.gradle # корневой билд-файл
Важно: Groovy-файлы могут содержать как классы, так и свободные выражения (скрипты). Файл с
classкомпилируется в.class, файл без — в наследникаgroovy.lang.Script.
32. Организация кода
Классы vs Скрипты
- Классы — для переиспользуемой логики, библиотек, компонентов.
- Скрипты — для автоматизации, одноразовых задач, точек входа.
Пример скрипта (hello.groovy):
println "Hello from script!"
def name = args[0] ?: 'World'
println "Hi, $name!"
Запуск:
groovy hello.groovy Alice
Пакеты и импорты
- Используются так же, как в Java.
- Groovy позволяет опускать
packageв скриптах, но рекомендуется указывать в библиотеках.
Разделение ответственности
- DSL-слои — декларативное описание.
- Интерпретаторы — преобразование DSL в действия.
- Инфраструктурные утилиты — работа с файлами, сетью, БД.
33. Управление зависимостями
Через Gradle
dependencies {
implementation 'org.codehaus.groovy:groovy-all:4.0.15'
implementation 'org.apache.commons:commons-text:1.10.0'
testImplementation 'org.spockframework:spock-core:2.3-groovy-4.0'
}
Через @Grab (в скриптах)
@Grab('org.apache.commons:commons-text:1.10.0')
import org.apache.commons.text.WordUtils
println WordUtils.capitalize('hello world')
Предупреждение:
@Grabиспользует Ivy под капотом, может быть медленным и ненадёжным в изолированных средах. В продакшене предпочтительнее Gradle/Maven.
34. Конфигурация приложения
ConfigSlurper
Читает .groovy-файлы как конфигурацию:
// config/app.groovy
environments {
development {
db.url = 'jdbc:h2:mem:dev'
}
production {
db.url = 'jdbc:postgresql://prod/db'
}
}
Загрузка:
def env = System.getenv('ENV') ?: 'development'
def config = new ConfigSlurper(env).parse(new File('config/app.groovy').toURL())
println config.db.url
Поддержка иерархии
- Возможны вложенные блоки.
- Поддержка
includeчерезConfigObject.merge().
Альтернативы
- JSON/YAML через
JsonSlurper/YamlSlurper(из SnakeYAML). - Properties — через
Properties.
35. Настройка компилятора Groovy
Параметры компиляции (через CLI)
groovyc -j -indy -targetBytecode 17 src/*.groovy
Флаги:
-j— совместная компиляция Java + Groovy-indy— использоватьinvokedynamic-targetBytecode— версия JVM-encoding UTF-8
Через Gradle
compileGroovy {
groovyOptions.optimizationOptions.indy = true
groovyOptions.encoding = 'UTF-8'
groovyOptions.targetBytecode = '17'
}
Custom Compilation Configuration
Можно создать groovyCompiler.groovy:
withConfig(configuration) {
ast(groovy.transform.CompileStatic)
}
И подключить:
compileGroovy {
groovyOptions.configurationScript = file('groovyCompiler.groovy')
}
36. Обработка ошибок и логирование
Исключения
- Используются стандартные Java-механизмы.
- Groovy не требует объявления
throws.
Логирование
Рекомендуется SLF4J:
@Grab('org.slf4j:slf4j-simple:2.0.7')
import org.slf4j.LoggerFactory
def log = LoggerFactory.getLogger(this.class)
log.info("Processing item")
Или встроенное логирование через java.util.logging:
def logger = java.util.logging.Logger.getLogger('MyApp')
logger.info('Started')
37. Тестирование и проверка качества
Spock — основной выбор
- Человекочитаемые спецификации.
- Встроенные моки.
- Параметризованные тесты.
Покрытие кода
- JaCoCo через Gradle:
plugins { id 'jacoco' }
jacocoTestReport {
reports {
html.required = true
xml.required = false
}
}
Статический анализ
- CodeNarc — линтер для Groovy:
plugins { id 'codenarc' }
codenarcMain {
configFile = file('config/codenarc.groovy')
}
Пример codenarc.groovy:
ruleset {
ruleset('rulesets/basic.xml')
ruleset('rulesets/braces.xml')
ruleset('rulesets/naming.xml')
}
38. Запуск и развёртывание
Самодостаточный JAR (fat jar)
jar {
manifest {
attributes 'Main-Class': 'MyApp'
}
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
from { configurations.runtimeClasspath.collect { it.isDirectory() ? it : zipTree(it) } }
}
Скрипты как исполняемые файлы (Unix)
#!/usr/bin/env groovy
println "Running as script"
Убедитесь, что
groovyв PATH.
Docker-образ
FROM openjdk:17-jdk-slim
COPY build/libs/app.jar /app.jar
CMD ["java", "-jar", "/app.jar"]
39. Безопасность при выполнении скриптов
Если вы выполняете внешние Groovy-скрипты (например, от пользователей), обязательно ограничьте окружение:
SecureASTCustomizer
def secure = new SecureASTCustomizer()
secure.closuresAllowed = false
secure.methodDefinitionAllowed = false
secure.importsWhitelist = ['java.lang.String']
secure.starImportsWhitelist = []
secure.staticImportsWhitelist = []
secure.tokensBlacklist = [TokenConstants.ASSIGN, TokenConstants.PLUS_PLUS]
def compiler = new CompilerConfiguration()
compiler.addCompilationCustomizers(secure)
def shell = new GroovyShell(this.class.classLoader, new Binding(), compiler)
shell.evaluate(untrustedCode)
Ограничение доступа к файловой системе, сети, рефлексии.
40. Профилирование и отладка
Отладка в IDE
- IntelliJ IDEA и Eclipse имеют отличную поддержку Groovy.
- Точки останова работают в динамическом и статическом режимах.
Логирование состояния
- Используйте
dump()для быстрого инспектирования объекта:println person.dump()
Мониторинг производительности
- VisualVM показывает вызовы Groovy-методов как обычные JVM-методы.
- При использовании
indy— убедитесь, что JIT работает эффективно.
41. Обновление и миграция
Groovy 2 → 3 → 4
Основные изменения:
- Groovy 3: новые операторы (
!in,!instanceof), поддержка Java 13+ синтаксиса. - Groovy 4: Jakarta EE вместо javax, улучшенная поддержка модулей, JDK 17+.
Проверка совместимости
- Запустите тесты с новой версией.
- Используйте
@CompileStaticдля выявления скрытых ошибок.
42. Когда использовать Groovy — и когда нет
Использовать Groovy, если:
- Нужен выразительный DSL.
- Требуется быстрая автоматизация.
- Интеграция с существующим Java-кодом.
- Пишутся тесты (Spock).
- Создаётся конфигурационная система.
Рассмотреть альтернативы (Kotlin, Java), если:
- Производительность критична на каждом этапе.
- Команда не знакома с динамическими языками.
- Требуется строгая типизация на этапе компиляции.
- Проект масштабируется до сотен тысяч строк.