Trying to make a method in groovy protected
:
package com.foo
class Foo {
protected def getSomething(){
}
}
This doesn't work since groovy by default makes pretty much everything visible, so I tried using @PackageScope
package com.foo
import groovy.transform.PackageScope
@PacakgeScope
class Foo {
def getSomething(){
}
}
This sort of works, but only if the caller uses @CompileStatic
...
package com.bar
class Bar {
@CompileStatic
static void main(args){
def f = new Foo()
println f.getSomething()
}
The above throws IllegalAccessError
, that's nice, but without @CompileStatic
, no error is generated; not so nice. I can't force users to compile statically, so is there any alternative to enforce protected
methods?
Protected in Groovy has the same meaning as protected in Java, i.e. you can have friends in the same package and derived classes can also see protected members.
Ok, if protected
has the same meaning in Groovy but isn't enforced as such, doesn't that erode its meaning? Maybe I'm missing something,
Short answer: Groovy does not enforce visibility checks.
Longer answer Protected has a meaning in Java, that you surely know. I mention it only for the interested reader: http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6.2
It is not that Groovy does not set the same modifier. So seen from Java the member will be protected just as in Java itself. It is more that Groovy does not perform the visibility check at runtime (or compile time) and might even use reflection to force accessibility. Groovy has to do so, because in general in Groovy the class accessing the member is one of the runtime. That means Groovy would have to emulate visibility checks at runtime, but for this some kind of "origin of call" is required, but not always available in Groovy due to the meta object protocol lacking the ability to properly transfer it.
Using @CompileStatic things are different. Here a direct access to the member is produced. Only it should have failed compilation already and not fail at runtime with IllegalAccessError.
This is quite head-scratching. I just did a search on "groovy information hiding". There's hardly anything out there!
There may be techniques involving closures to obtain information-hiding in Groovy. But I just did a few experiments and found a way, hopefully, of imposing @CompileStatic
which might be of some use. It involves the use of an inner class combined with subclassing from an abstract
class, and throwing an exception if an illegal attempt is made to bypass the factory method. It was quite a hack, in fact.
More to the point, on closer examination I found that even this didn't work.
The only way I've found so far is such an uber-hack I feel ashamed to even mention it: technique involving examination of the stack trace.
On checking back with Groovy In Action 2nd Ed. it's clear to me that in fact @CompileStatic
is much more about enforcement of type checking than anything to do with information-hiding: it is covered in such a way that it comes across as a rather more powerful version of the annotation @TypeChecked
.
In Python there is a convention, I assume still used, of giving fields which are meant to be "treated as private" a special naming convention, namely making the name start with double-underscore. But I've seen nothing along these lines in Groovy.
Bloch, in his excellent book Effective Java, gives lots of sound reasons why information-hiding is very important. Of course it is well known by now that even in Java all this is flimsy and can be cracked by reflection techniques. But I'd like to hear from a Groovy uber-geek their view on the issue raised by your question...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With