It is often desired to declare constants at the top of a script that can be referenced anywhere else in the script. In Groovy, it seems that if you declare a constant using final then it isnot accessible in child scopes. What is the solution for this very basic and common requirement? The workaround I have right now is to create an unbound variable but this is not a constant and is not elegant.
4 Answers
Groovy doesn't really have a global scope. When you have a groovy script that doesn't declare a class, it implicitly gets stuck in a class with the name of the script. So final variables at the top-level scope are really just fields of the implicit class. For example:
// foo.groovy
final MYCONSTANT = "foobar"
println MYCONSTANT
class Helper {
def hello() { println MYCONSTANT } // won't work
}
new Helper().hello()
Is more or less equivalent to:
class foo {
def run() {
final MYCONSTANT = "foobar"
println MYCONSTANT
new Helper().hello()
}
static main(args) {
new foo().run()
}
}
class Helper {
def hello() { println MYCONSTANT } // won't work
}
It's easy to see why it doesn't work expanded out. An easy work around is to declare your "globals" in a dummy class called e.g. Constants, and then just do a static import on it. It even works all in a single script. Example:
import static Constants.*
class Constants {
static final MYCONSTANT = "foobar"
}
println MYCONSTANT
class Helper {
def hello() { println MYCONSTANT } // works!
}
new Helper().hello()
Also, scripts are bit of a special case. If you declare a variable without def
or any modifiers such as final
, (i.e. just use it) it goes into a script-wide binding. So in this case:
CONSTANT = "foobar"
println "foobar"
CONSTANT
is in the script-wide binding, but in:
final CONSTANT = "foobar"
println "foobar"
CONSTANT
is a local variable in the script's run()
method. More information on this can be found at the archived link to some Groovy - Scoping and the Semantics of "def" page.
-
Constants should be enums in the Java 1.5+ world... :) – Esko Feb 01 '11 at 06:51
-
7@Esko every type of constant should be an Enum? Even something like GRAVITY or PI? O_o – tim_yates Feb 01 '11 at 07:34
-
@tim_yates: No, an enum should contain all constants which are related to each other. In your example that'd be something like `CelestialObjectAttributes.GRAVITY` or `MathematicConstants.PI`. These can be imported too so that you don't have to repeat the name of the enum and enums are always VM (*or classloader*) global which makes them the perfect alternative for oldschool global constants. – Esko Feb 01 '11 at 09:04
-
2@Esko I was trying to point out that your initial statement was not true for all constants – tim_yates Feb 01 '11 at 09:12
-
@tim_yates: Why didn't you say so, then? Although, maybe some clarification such as *"Global constants should be expressed as enums..."* would've been nice. – Esko Feb 01 '11 at 11:26
-
@ataylor: In your example you have 2 classes, an implicit one 'foo' and an explicit one 'Helper'. However, what is confusing is that it will not work even if there was no 'Helper' class. Methods/closures in "foo" can't use the constants declared at the top. – justGroovy Feb 01 '11 at 11:36
-
@justGroovy, you're right, the final modifier changes things a bit unexpectedly in scripts. I've updated my answer. – ataylor Feb 01 '11 at 17:43
-
1coming from another language I find the scoping issues here a confusing mess... the thing with `final` changing the scope is something I just encountered and rather surprising. the 'Scoping and semantics' link is currently a 404 – Anentropic Nov 02 '15 at 13:10
-
This just works: `CONSTANT = "foobar"` – ACV Mar 05 '22 at 18:29
In Groovy 1.8+, you can achieve this using the @Field
annotation:
import groovy.transform.Field
@Field final String MY_CONSTANT = 'constant'
def printConstant() { println MY_CONSTANT }
printConstant()

- 14,427
- 5
- 89
- 94
-
5@Anentropic: don't miss the import above "import groovy.transform.Field" – BTakacs Jan 09 '17 at 15:34
The another efficient way to add the global application level constants are declare one interface in suitable package as
interface applicationConstants {
//All constants goes here.
static final float PI = 3.14
String ADMIN_USER = "ADMIN"
Map languages = [
"en": "English",
"hi": "Hindi",
"mr": "Marathi"
]
// Like above you can declare all application level code constants here.
}
Use of constants in any class as below,
import packageNameContainingInterface.applicationConstants // import statement.
def adminUser = applicationConstants.ADMIN_USER
println adminUser

- 2,524
- 1
- 12
- 24
I personally wouldn't do it but technically you could do
Object.metaclass.MYCONSTANT = 'foobar'
Then every object has it

- 56
- 3