Lesson Learned on Groovy
There are some of the key takeaways which I have encountered during the Jenkins pipeline Integration with API.
Join the DZone community and get the full member experience.
Join For FreeThough I have worked on Java for more than a decade, I have not had a chance to work on Groovy. While working for API Integration into Jenkins CI/CD pipeline, I extensively used Groovy to invoke REST API, validate the user input parameters, and business logic for that. After that, I found that Groovy is a fascinating program language for Java developers.
Why Is Groovy Easy for Java Developers?
It allows to use the Java syntax liberally and tries to be as natural as possible for Java developers. It is an object-oriented dynamic programming language for Java Virtual Machine (JVM) and can be integrated smoothly with any Java Program. The groovy syntax is lucid, familiar, and direct that makes to develop projects faster and easier. It demands a shorter learning curve for Java Developer to develop, test, and integrate to make production-ready code in a short span.
What Is Groovy?
Apache Groovy is a powerful, optionally typed, and dynamic language, with static-typing and static compilation capabilities, and immediately delivers an application with powerful features, including scripting capabilities, Domain-Specific Language authoring, runtime and compile-time meta-programming and functional programming.
There are some of the key takeaways which I have encountered during the Jenkins pipeline Integration with API. The key takeaways explained below in the form of questions, answers, program including the output.
1. How To Define the Global Variable in Groovy?
Assign the value to a variable without def to define Global variable.
def comments = 'Emergency build' // It is not accessible inside the display method.
planId = 'IMP2345667' // Since the planId declared without def, hence is considered as a global and accessible inside the display method.
def display() {
println "The Global varible is ${planId}"
}
//call the display method as below
display()
Output:
The Global variable is IMP2345667
2. How To Interpolate String in Groovy?
You can use either single quotes or double quotes to declare String.
For Example, You can declare planId as follows.
def planId='IMP2356790'
def planId="IMP2356790"
When you print the String by single quote, the String interpolation would not happen. The ${} placeholders printed as it is as shown below.
println 'The Implementation planId is ${planId}’
Output:
The Implementation planId is ${planId}
Use double quotes for String Interpolation. Now, the ${} placeholders transformed with planId value as shown below.
println “The Implementation planId is ${planId}”
Output:
The Implementation planId is IMP2356790
3. How To Check Not Null and Not Empty in Groovy?
The minimal code to check not null and not empty in groovy is to apply "?.trim()" on String as follows.
xxxxxxxxxx
def validateString(String inputField) {
if (!inputField ?.trim()) {
println "The value you entered is -${inputField}. Enter Valid Input of not null and not empty."
return
}
}
//Assign Null value to check the validateString
def planId = null
//Call the validateString by passing the pladId to validate the String
validateString(planId)
The output for validateString is as follows.
The value you entered is -null. Enter Valid Input of not null and not empty.
Note:
To check the Not Null for an object, do not use ?.trim() instead use obj !=null. Use ?.trim() only for Strings not for an object.
4. How to Transform Input Params as a JSON String?
Use a JSON data structure with the JsonBuilder class to transform into JSON data. The hierarchy of ImplementationPlan consists of planId, planStatus, and comments and that is converted to JSON String as shown below.
xxxxxxxxxx
{
"ImplemenationPlan":{
"planId":"IMP2345678",
"planStatus":"Work in Progress",
"comments":"Emergency build"
}
}
Look at the Groovy code for the JSON Transformation using JsonBuilder as below.
xxxxxxxxxx
import groovy.json.JsonBuilder
def planId = "IMP2345678"
def planStatus = "Work in Progress"
def comments = "Emergency build"
println transformToJSON(planId, planStatus, comments)
def transformToJSON(String planId, String planStatus, String comments)
def jsonBuilder = new JsonBuilder()
jsonBuilder.ImplemenationPlan(
planId: planId,
planStatus: planStatus,
comments: comments
)
return jsonBuilder.toString()
}
The Output of transformJSON is as follows.
{"ImplemenationPlan":{"planId":"IMP2345678","planStatus":"Work in Progress","comments":"Emergency build"}}
5. How to Convert Object to JSON in Groovy?
Use the JsonBuilder to transform the Object to JSON String in groovy as described below.
xxxxxxxxxx
import groovy.json.JsonBuilder
class ImplementationPlan {
String planId
String planStatus
String createdBy
String dateOfInitiation
String comments
String leadName
String managerName
String implementationDate
String systemForInitiation
ImplementationPlan(String planId,
String planStatus,
String createdBy,
String dateOfInitiation,
String comments,
String leadName,
String managerName,
String implementationDate,
String systemForInitiation) {
this.planId = planId
this.planStatus = planStatus
this.createdBy = createdBy
this.dateOfInitiation = dateOfInitiation
this.comments = comments
this.leadName = leadName
this.managerName = managerName
this.implementationDate = implementationDate
this.systemForInitiation = systemForInitiation
}
}
def implementationPlan = new ImplementationPlan('IMP2345679', 'Work in Progress', 'KevinMatthew', '2020-09-20', 'Emergency Build', 'Benny Benjamin', 'Merryln Fedora', '2020-10-01', 'wsp')
println new JsonBuilder(implementationPlan).toPrettyString()
The Output for the above code would be:
xxxxxxxxxx
{
"leadName": "Benny Benjamin",
"comments": "Emergency Build",
"planStatus": "Work in Progress",
"planId": "IMP2345679",
"dateOfInitiation": "2020-09-20",
"createdBy": "KevinMatthew",
"managerName": "Merryln Fedora",
"implementationDate": "2020-10-01",
"systemForInitiation": "wsp"
}
6. How to Customize JSON Output to Exclude Null and Particular Fields?
Let us say that I do not want to get printed the null values and Fields such as leadName,managerName, and createdBy. To achieve this, use JsonGenerator to excludeNulls and excludeFieldsByName as described below code.
xxxxxxxxxx
import groovy.json.JsonGenerator
import groovy.json.JsonGenerator.Converter
class ImplementationPlan {
String planId
String planStatus
String createdBy
String dateOfInitiation
String comments
String leadName
String managerName
String implementationDate
String systemForInitiation
ImplementationPlan(String planId,
String planStatus,
String createdBy,
String dateOfInitiation,
String comments,
String leadName,
String managerName,
String implementationDate,
String systemForInitiation) {
this.planId = planId
this.planStatus = planStatus
this.createdBy = createdBy
this.dateOfInitiation = dateOfInitiation
this.comments = comments
this.leadName = leadName
this.managerName = managerName
this.implementationDate = implementationDate
this.systemForInitiation = systemForInitiation
}
}
def implementationPlan = new ImplementationPlan('IMP2345679', 'Work in Progress', 'KevinMatthew', '2020-09-20', null, 'Benny Benjamin', 'Merryln Fedora', '2020-10-01', null)
def jsonOutputDefault = new JsonGenerator.Options().build()
xxxxxxxxxx
// Print all by default
def jsonResult = jsonOutputDefault.toJson(implementationPlan)
println "Default JSON output include null and all Fields - ${jsonResult }"
// Exlude null ,leadName,managerName, and createdBy
def jsonOutput =
new JsonGenerator.Options()
.excludeNulls().excludeFieldsByName('leadName').excludeFieldsByName('managerName').excludeFieldsByName('createdBy').build()
def jsonCustomizedResult = jsonOutput.toJson(implementationPlan)
println "The customizing output after exclude null and fields - ${jsonCustomizedResult}"
The output for the above Groovy code would be
Default JSON output include null and all Fields –
xxxxxxxxxx
{"leadName":"Benny Benjamin","comments":null,"planStatus":"Work in Progress","planId":"IMP2345679","dateOfInitiation":"2020-09-20","createdBy":"KevinMatthew","managerName":"Merryln Fedora","implementationDate":"2020-10-01","systemForInitiation":null}
The customizing output after exclude null and fields - {"planStatus":"Work in Progress","planId":"IMP2345679","dateOfInitiation":"2020-09-20","implementationDate":"2020-10-01"}
7. How to Parse the String and Convert Into Corresponding Objects?
When you make a REST API call, you will get the JSON text as an output. Let say you that want to retrieve the specific field from the JSON text, you no longer needed to search from the JSON response to fetch from it. Groovy comes to rescue for JSON text parsing by JsonSlurper andJsonSlurperClassic that parses JSON text or reader content and recursively converts into objects(Such as maps, lists, and object of class type).
For Example, you have JSON text of planId, planStatus, createdBy, and more fields, but response populated with planId, and planStatus. So, use JsonSlurper andJsonSlurperClassic to parse JSON text , convert them into an object, and fetch the particular field from that object.
Note: It is prudent to use JsonSlurperClassic rather than JsonSlurper to come out from Jenkins pipeline Error -"NotSerializableException: groovy.json.internal.LazyMap"
xxxxxxxxxx
import groovy.json.JsonBuilder
import groovy.json.JsonSlurperClassic
public class ImplementationPlan {
String planId
String planStatus
String createdBy
String dateOfInitiation
String comments
String leadName
String managerName
String implementationDate
String systemForInitiation
ImplementationPlan() {}
ImplementationPlan(String planId,
String planStatus,
String createdBy,
String dateOfInitiation,
String comments,
String leadName,
String managerName,
String implementationDate,
String systemForInitiation) {
this.planId = planId
this.planStatus = planStatus
this.createdBy = createdBy
this.dateOfInitiation = dateOfInitiation
this.comments = comments
this.leadName = leadName
this.managerName = managerName
this.implementationDate = implementationDate
this.systemForInitiation = systemForInitiation
}
}
//JSON slurper that parses text and convert into corresponding Object type
def parseJSON(String planData) {
def slurper = new JsonSlurperClassic()
def obj = slurper.parseText(planData)
return obj
}
def implementationPlan = new ImplementationPlan('IMP2345679', 'Work in Progress', 'KevinMatthew', '2020-09-20', 'Emergency Build', 'Benny Benjamin', 'Merryln Fedora', '2020-10-01', 'wsp')
String planData = new JsonBuilder(implementationPlan).toString()
ImplementationPlan result = parseJSON(planData)
println "planId is ${result.planId } planStatus is ${result.planStatus}"
The output of above code would be
planId is IMP2345679 planStatus is Work in Progress
8. Why Should You Annotate @NonCPS for Groovy Methods?
When you use JsonObject, JsonSlurper, and JsonSlurperClassic into Jenkins pipeline, you will come across "org.jenkinsci.plugins.scriptsecurity.sandbox.RejectedAccessException"
When you run the pipeline scripts, the scripts are executed in sandbox security by default.
The sandbox security executes the scripts with the Common Serializable Types(Such as All primitive types, Strings, ArrayLists and normal Groovy Lists, Sets: HashSet, Maps: normal Groovy Map, HashMap, TreeMap..etc) without any RejectedAccessException.
When your scripts consist of Common non-Serializable Types such as Regex Matchers or JsonObject, JsonSlurper, and JsonSlurperClassic, always annotate your method with @NonCPS to come out of RejectedAccessException Error.
For Example, annotate your method with @NonCPS as follows.
xxxxxxxxxx
import groovy.json.JsonSlurperClassic
import com.cloudbees.groovy.cps.NonCPS
def parsePayLoad(String planStatus) {
def slurper = new JsonSlurperClassic()
def obj = slurper.parseText(planStatus)
return obj
}
Note:
Continuation-passing(CPS) style is code execution in the form of a continuation that allows executing Serializable types without blocking to pass control onto a continuation.
9. Points to Ponder
Groovy statements need not be terminated with a semicolon.
If you want to return any data type or object, declare the Method with "def" that means it can return anything-regardless of the data type you return for a Method. The below processRecharge Method will return either a string or boolean depends on the parameter passed as below.
xxxxxxxxxx
def processRecharge(String status) {
if (status?.trim() && status.equalsIgnoreCase('success')) {
return "Your Mobile Number is eligible for recharge "
} else {
return false
}
}
println processRecharge('success') //This returns the String value
println processRecharge() //This returns boolean
If you do not know the data type, define with "def ". The keyword " def " defines an untyped variable or a function in Groovy, as it is an optionally-typed language.
When writing your beans in Groovy, often called POGOs (Plain Old Groovy Objects), you don’t have to create the field and getter/setter yourself, but let the Groovy compiler do it for you.
By default, Groovy considers classes and methods public. So you don’t have to use the public modifier everywhere something is public. Only if it’s not public, you should put a visibility modifier.
10. Conclusion
Groovy is a scripting language with Java-like syntax for the Java platform. You can play around the Groovy scripts with online web consoles such as https://groovyconsole.appspot.com/ and https://www.tutorialspoint.com/execute_groovy_online.php. Please refer to the Groovy code to explore more from GitHub — https://github.com/ebinezargnan/Groovy-Code.git.
Opinions expressed by DZone contributors are their own.
Comments