Global constants in Groovy

GroovyGlobal Variables

Groovy Problem Overview


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.

Groovy Solutions


Solution 1 - Groovy

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()

EDIT:

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.

Solution 2 - Groovy

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()

Solution 3 - Groovy

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

Solution 4 - Groovy

I personally wouldn't do it but technically you could do

Object.metaclass.MYCONSTANT = 'foobar'

Then every object has it

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionjustGroovyView Question on Stackoverflow
Solution 1 - GroovyataylorView Answer on Stackoverflow
Solution 2 - GroovybmaupinView Answer on Stackoverflow
Solution 3 - GroovyNitin DhomseView Answer on Stackoverflow
Solution 4 - GroovyAdam TaylorView Answer on Stackoverflow