banner
jzman

jzman

Coding、思考、自觉。
github

Groovy Basics of Gradle

Previous learned the basics of Gradle, which is based on Groovy. Today, let's learn some basic knowledge of Groovy. Groovy is a dynamic language based on the JVM virtual machine, with syntax similar to Java. Groovy is fully compatible with Java, and every Gradle file is a Groovy script file. Gradle files are based on Groovy syntax, and since Groovy is compatible with Java, Java code can be written in Gradle files. On this basis, many new features have been added, such as support for closures, DSL, etc. It can be said that Groovy is a very flexible dynamic scripting language. Let's learn some basic knowledge of Groovy in the context of Gradle.

  1. Strings
  2. Collections
  3. Methods
  4. JavaBeans
  5. About Closures

Strings#

One feature of Groovy is that semicolons are not mandatory. Both single quotes and double quotes define a string constant. The difference is that single quotes are purely string constants and do not evaluate expressions within the string, while string constants defined with double quotes can use valid expressions for related calculations. The test code is as follows:

task stringTest{
	// Use the def keyword to define variables,
	def str1 = "Double quotes"
	def str2 = 'Single quotes'
	
	println "String defined with double quotes:"+str1
	println "String defined with double quotes:"+str1.class
	println "String defined with single quotes:"+str2
	
	// Variable dynamic change
	str1 = true;
	println "String defined with double quotes:"+str1.class
	
	// Use the $ operator
	println "String defined with double quotes:${str1}"
	// When there is only one variable, brackets can be omitted
	println "String defined with double quotes:$str1"
	
	// String defined with single quotes cannot use expressions for calculations
	println 'String defined with single quotes:$str2'
}

Below is the execution result for reference:

PS E:\Gradle\study\Groovy> gradle stringTest

> Configure project :
String defined with double quotes:Double quotes
String defined with double quotes:class java.lang.String
String defined with single quotes:Single quotes
String defined with double quotes:class java.lang.Boolean
String defined with double quotes:true
String defined with double quotes:true
String defined with single quotes:$str2

BUILD SUCCESSFUL in 1s

Collections#

Groovy also has the concept of collections, mainly looking at commonly used List and Map. Below, we will introduce common operations for List and Map.

So how do you define a List in Groovy? The definition of List in Groovy is similar to arrays in Java. The specific operations are as follows:

task list{
	// Define List
	def list = [1,2,3,4,5,6];
	def weekList = ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];
	println "Type of list:"+list.class
	println "Type of weekList:"+weekList.class
	
	// Access elements in the collection
	println 'First element:'+list[0]// Access the first element
	println 'Second element:'+list[1]// Access the second element, and so on
	
	println 'Last element:'+list[-1]// Access the last element
	println 'Second to last element:'+list[-2]// Access the second to last element, and so on
	println 'Elements in a certain range:'+list[2..4]// Access elements in a certain range, and so on
	
	// Use each to iterate over elements in the collection
	weekList.each{
		// Use it as the iteration element variable, do not write it incorrectly
		println it
	}
}

Below is the execution result of the above code for reference:

PS E:\Gradle\study\Groovy\ListMap> gradle list

> Configure project :
Type of list:class java.util.ArrayList
Type of weekList:class java.util.ArrayList
First element:1
Second element:2
Last element:6
Second to last element:5
Elements in a certain range:[3, 4, 5]
Monday
Tuesday
Wednesday
Thursday
Friday
Saturday
Sunday

BUILD SUCCESSFUL in 2s

So how do you define a Map in Groovy? A Map in Groovy is of course a key-value pair. The specific definition and operations are as follows:

task map{
	
	// Define Map
	def map = ['name':'Groovy', 'age':10];
	println "Type of map:"+map.getClass().name;
	
	// Access elements in the Map
	println map.name;
	println map['name'];
	
	// Iterate over elements in the Map
	map.each{
		println "Key:${it.key}, value:${it.value}"
	}
}

Below is the execution result of the above code for reference:

PS E:\Gradle\study\Groovy\ListMap> gradle map

> Configure project :
Type of map:java.util.LinkedHashMap
Groovy
Groovy
Key:name,value:Groovy
Key:age,value:10

BUILD SUCCESSFUL in 2s

That's all for understanding collections in Groovy.

Methods#

Methods in Groovy are similar to those in Java, but the syntax is more flexible. In Groovy, return is not mandatory. When return is not written, Groovy will treat the last line of code as the return value of the method. A code block refers to a section of code enclosed in curly braces, and in Groovy, code blocks can be passed as parameters. You can refer to the previous section on iterating over collections. The reference code is as follows:

task method{
	// Method call
	methodA(1, 2)
	methodA 1, 2 
	
	// Get the result returned by the method
	def a = methodA 10, 20
	println 'Get the result returned by the method:'+a
	
	// Code block passed as a parameter
	def list = [1,2,3,4,5];
	list.each(
		// Closure parameter
		{
		//	println it
		}
	)
	
	// Groovy specifies that if the last parameter of the method is a closure, it can be placed outside the method
	list.each(){
	//	println it
	}
	
	// Shortened form
	list.each{
		println it
	}
}

// Method definition
def methodA(int a, int b){
	println a + b
	// In Groovy, the return statement is not mandatory; it defaults to the result of the last line of code as the return value
	a + b
}

Below is the execution result of the above code for reference:

PS E:\Gradle\study\Groovy\Method> gradle method

> Configure project :
3
3
30
Get the result returned by the method:30
1
2
3
4
5

BUILD SUCCESSFUL in 2s

JavaBean#

JavaBeans in Groovy are more flexible compared to those in Java. You can directly use the javaBean.property method to get and modify the property values of a JavaBean without using the corresponding Getter and Setter methods. Let's look at the code directly:

task javaBean{
	// Define JavaBean in Groovy
	Student student = new Student()
	student.name = "Groovy"
	student.age = 10
	
	student.setName("Gradle")
	println "Name is:"+student.name
	// Cannot call Getter method to get value
//	println "Name is:"+student.getName
	println "Age is:${student.age}"
	println "Score is:"+student.score
}

class Student{
	private String name
	private int age
	// The defined Getter method corresponding to the property can be called directly
	public String getScore(){
		100
	}
	
	// Getter and Setter methods for properties
	public String setName(String name){
		this.name = name
	}
	
	public void getName(){
		name
	}
}

Below is the execution result of the above code:

PS E:\Gradle\study\Groovy\JavaBean> gradle javaBean

> Configure project :
Name is:Gradle
Age is:10
Score is:100

BUILD SUCCESSFUL in 2s

Closures#

Closures are a feature found in most scripting languages, such as JavaScript and Groovy. A closure is a block of code surrounded by curly braces. Let's learn about closures in Groovy, which mainly consists of two parts: closures and closure parameter passing, and closure delegation.

Closures and Parameter Passing#

Let's see how to define a closure and pass related parameters, with the code as follows:

task closure{
	// Custom closure execution
	mEach{
		println it
	}
	
	// Pass parameters to the closure
	mEachWithParams{m,n -> // m,n -> separates closure parameters from the body
		println "${m} is ${n}"
	}
}

// 1. Define a method, parameter closure is used to receive the closure
// 2. The execution of the closure is the execution of the code inside the curly braces
// 3. The parameters received by the closure are the closure parameter i, which defaults to the it variable if there is one parameter
def mEach(closure){
	for(int i in 1..5){
		closure(i)
	}
}

// Pass parameters to the closure
def mEachWithParams(closure){
	def map = ["name":"Groovy","age":10]
	map.each{
		closure(it.key, it.value)
	}
}

The above code defines a closure and how to pass parameters to the closure. When the closure has only one parameter, it defaults to it. When the closure has multiple parameters, the parameters need to be defined. For specific details, refer to the above code. Below is the execution result:

PS E:\Gradle\study\Groovy\Closure> gradle delegate

> Configure project :
1
2
3
4
5
name is Groovy
age is 10

BUILD SUCCESSFUL in 2s

Closure Delegation#

The power of Groovy closures lies in their support for closure method delegation. Groovy closures have three properties: thisObject, owner, and delegate. When a method defined within a closure is called, these three properties determine which object executes the method. By default, owner and delegate are equal, but delegate can be modified. Many features of closures in Gradle are implemented by modifying the delegate. Below is a definition of a closure and a method, with prints to illustrate some differences among these three properties:

// Closure delegation
task delegate{
	new Delegate().test{
		// Three properties of Groovy closures: thisObject, owner, delegate
		println "thisObject:${thisObject.getClass()}"
		println "owner:${owner.getClass()}"
		println "delegate:${delegate.getClass()}"
		
		// Default it in the closure
		println "Default it in the closure:"+it.getClass()
		
		// The defined method is processed using thisObject first
		method()
		// Method in the closure
		it.method()
	}
}

def method(){
	println "method in root:${this.getClass()}"
}

class Delegate{
	def method(){
		println "method in Delegate:${this.getClass()}"
	}
	
	// Closure
	def test(Closure<Delegate> closure){
		closure(this);
	}
}

Below is the execution result of the above code for reference:

PS E:\Gradle\study\Groovy\Closure> gradle delegate

> Configure project :

thisObject:class build_3ajca04o1rprxygcsq0ajvt7i
owner:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
delegate:class build_3ajca04o1rprxygcsq0ajvt7i$_run_closure2
Default it in the closure:class Delegate
method in root:class build_3ajca04o1rprxygcsq0ajvt7i
method in Delegate:class Delegate

BUILD SUCCESSFUL in 2s

When calling the method method() within the closure, it is found that thisObject called the method(), not owner or delegate, indicating that the closure prioritizes using thisObject to handle method execution. It can also be seen that owner and delegate are consistent, but owner has a higher priority than delegate. Therefore, the order of method handling in closures is: thisObject > owner > delegate.

In Gradle, the delegate is generally specified as the current it, allowing us to operate on it through the object specified by the delegate. Below is the test code that specifies the closure's delegate and sets the delegation priority, allowing the specific object of the delegate to execute its methods:

task student{
	configStudent{
		println "Current it:${it}"
		
		name = "Groovy"
		age = 10
		getInfo()
	}
}

class Student{
	String name
	int age
	def getInfo(){
		println "name is ${name}, age is ${age}"
	}
}

def configStudent(Closure<Student> closure){
	Student student = new Student()
	// Set the delegate object to the currently created Student instance
	closure.delegate = student
	// Set the delegation mode priority; if not set, the method handler in the closure is thisObject
	closure.setResolveStrategy(Closure.DELEGATE_FIRST)
	// Set the it variable
	closure(student)
}

Below is the execution result of the above code for reference:

PS E:\Gradle\study\Groovy\Closure> gradle student

> Configure project :

Current it:Student@18f6d755
name is Groovy, age is 10

BUILD SUCCESSFUL in 2s

Summary#

The purpose of learning Groovy is to deepen the understanding of the Gradle build tool. The above has provided a preliminary understanding of Groovy from five aspects. If needed, we can look at advanced usage of Groovy later.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.