Upgrading your scripts for Groovy 3 compatibility
Groovy 3 introduces a list of breaking changes that can affect Collibra Groovy workflow scripts. You can consult the full list in the Groovy 3 release notes. There are two breaking changes that can most likely affect Collibra workflows:
- If a Groovy switch statement has a default branch, it must be the last branch.
- Groovy is now more compliant with the JavaBeans specification for one edge case scenario involving any field having a name starting with an uppercase letter (GROOVY-9618).
- Enums cannot have a non-private constructor.
- To use an interface “Function” as a parameter it must be typed, for example:
_methodHandler(Function<Integer, Integer> requiredFunction)
.
You can upgrade the workflows groovy script code to be compatible with these changes before we upgrade Collibra to the version containing Groovy 3.
Change Groovy switch statement
If a Groovy 3 switch statement has a default branch, it must be the last branch. This means that you can no longer place the default branch in any other position except last in the list of branches.
The following does not compile under Groovy 3:
switch(yourVariable) {
default:
// default action
break
case 'a':
// case a action
break
}
To correct the above code, place the default branch last:
switch(yourVariable) {
case 'a':
// case a action
break
default:
// default action
break
}
Your code will behave exactly the same as all the branches have a break
statement, so each branch is isolated and doesn’t affect other branches.
Switch fall-through
As switch fall-through occurs when branches don't have a break
statement, making it possible to execute multiple branches, not only the one that matches.
Example of switch fall-through:
def result = ""
switch(yourVariable) {
default:
result += "default "
// as there is no break statement, "case a" will be executed next
case 'a':
result += "a "
// as there is no break statement, "case b" will be executed next
case 'b':
result += "b"
}
When yourVariable
has the value 'a', the result
variable will equal "a b". When yourVariable
has the value 'b', the result
variable will equal "b". In all other cases, the result
variable will be equal “default a b”.
To make the code compile under Groovy 3, place the default branch last. However, to obtain the same results as the fall-through switch, you must also adjust the rest of the code:
Groovy 3 switch fall-through equivalent:
def result = ""
switch(yourVariable) {
case 'a':
result = "a b"
break
case 'b':
result = "b"
break
default:
result = "default a b"
break
}
Adjusting for Groovy JavaBeans specification compatibility changes
Groovy 3 is more compliant with the JavaBeans specification for one edge case scenario involving any field having a name starting with an uppercase letter. This change has an impact on the handling of properties.
Groovy properties
The definition of properties according to the Groovy public documentation is:
A property is an externally visible feature of a class. Rather than just using a public field to represent such features (which provides a more limited abstraction and would restrict refactoring possibilities), the typical approach in Java is to follow the conventions outlined in the JavaBeans Specification, i.e. represent the property using a combination of a private backing field and getters/setters. Groovy follows these same conventions but provides a simpler way to define the property.
The code sample below will generate the following:
-
A backing
private String name
field, a getName and a setName method. -
A backing
private int age
field, a getAge and a setAge method.
class Person {
String name
int age
}
By convention, Groovy also recognizes properties even if there is no backing field, provided there are getters or setters that follow the Java Beans specification.
class PseudoProperties {
//1. a pseudo property "name"
void setName(String name) {}
String getName() {}
//2. a pseudo read-only property "age"
int getAge() { 42 }
//3. a pseudo write-only property "groovy"
void setGroovy(boolean groovy) { }
}
def p = new PseudoProperties()
p.name = 'Foo' // uses (1)
assert p.age == 42 // uses (2)
p.groovy = true // uses (3)
Groovy 3 breaking change
In Groovy 3 the handling of properties that start with an uppercase letter has changed to be more compliant with the JavaBeans specification.
The way how properties are mapped to the accessor method has changed. In groovy 2 it was possible to access the field instead of the accessor methods in some scenarios as shown below:
Groovy 2
|
Groovy 3
|
A similar situation occurs when you use static properties:
Groovy 2
|
Groovy 3
|
This breaking change doesn’t affect classes where accessor methods are not overwritten.
Recommendation
To make existing workflow scripts compatible with Groovy 3, we recommend using lowercase property names, except in when the property name is all uppercase:
class A {
private String X = 'fieldX'
private String XML = 'fieldXML'
String getX() { 'X' }
String getXML() { 'XML' }
}
new A().with {
assert x == 'X' // instead of using uppercase X property
assert XML == 'XML' // in this case using XML property is the only way
}