Groovy Goodness: Defining Public Accessible Constant Fields
There is a catch when we define a constant field in Groovy. Rob Fletcher blogged about this in the post Groovy the public keyword a while ago. When we omit the public
keyword for a method then the method is still accessible as public method, because Groovy makes the method public when the class is compiled. When we leave out the public
keyword for fields Groovy creates a getter and setter method for the field at compile time and turns it into a property that applies to the Java Bean specification. This is also true if the field is static. So if we define a constant value as static final
we must keep in mind that Groovy will generate a getter method so the constant value is a read only property according to Java Bean specification.
Let's create a simple class with a constant field DEFAULT
, a property message
and a message
method. We leave out any public
keyword:
// File: sample.groovy
// Groovy makes class public.
class Sample {
// Groovy adds getDEFAULT and no setDEFAULT.
static final String DEFAULT = 'default'
// Groovy adds setMessage/getMessage
String message
// Groovy makes method public.
void message(final String newMessage) {
this.message = message
}
}
If we compile this class we get the following methods and fields (using javap
to inspect the class):
$ javap -p -constants Sample
Compiled from "sample.groovy"
public class Sample implements groovy.lang.GroovyObject {
private static final java.lang.String DEFAULT = "default";
private java.lang.String message;
...
public void message(java.lang.String);
...
public static final java.lang.String getDEFAULT();
public java.lang.String getMessage();
public void setMessage(java.lang.String);
}
If we want to access the constant field in Groovy we can still use Sample.DEFAULT
, but from Java code this doesn't work. You can see in the generated class file we should invoke getDEFAULT()
, because this method is public. To overcome this we simply add public
to our constant field definition. This way Groovy will leave the field unchanged and in the generated class file it is still public. Then from Java we can use Sample.DEFAULT
to access the constant value. Let's see the output of javap
when we make the DEFAULT
field public:
$ javap -p -constants Sample
Compiled from "sample.groovy"
public class Sample implements groovy.lang.GroovyObject {
public static final java.lang.String DEFAULT = "default";
private java.lang.String message;
...
public void message(java.lang.String);
...
public java.lang.String getMessage();
public void setMessage(java.lang.String);
}
This also helps an IDE, like IntelliJ IDEA, to do a proper import static
based on the constant field.
Written with Groovy 2.4.4.