I have scenario like following where there's a World
class with only a private constructor and another class App
.
As shown in code, a new instance of World
can be created inside App
class despite of only private constructor in World
.
It is prohibited in Java and I thought it is prohibited in groovy too, but the App
run without any error.
// World.groovy
class World {
private World() {
}
}
// App.groovy
class App {
static void main(String[] args) {
def world = new World()
println world
}
I couldn't understand how it is possible in groovy. How can another class instantiate a class with only private constructor in groovy?
Groovy doesn't recognize the private access modifier. See this question. There is nothing private in Groovy.
As to how Groovy does it, Groovy is generating the classes for things you write in Groovy. It can write whatever access modifiers it wants in the class files. But you can also use Groovy to inspect the private parts of Java code. Groovy is calling setAccessible
on the constructor as AlexR's answer demonstrates.
The security manager can prevent this kind of thing. In groovysh, the Security manager is org.codehaus.groovy.tools.shell.util.NoExitSecurityManager
, which only checks permissions if its parent is nonnull. In groovysh its parent is null.
Groovy relies on having the 'suppressAccessChecks' permission set in order to function. The groovy.policy file for the core-groovy project has this notice:
/* Notes on the contents of this policy file:
*
* The following methods in groovy have privileged operations wrapping
* setAccessible. If these wrappers are not provided, most codebases below
* must have the following grant:
* permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
* MetaMethod.createMetaMethod
* MetaMethod.invoke(Object Object[])
* ReflectionMetaMethod.invoke(Object Object[])
* DefaultGoovyMethods.dump(Object)
*/
There is a page on Groovy's website of "things you can do but better leave undone", it lists the privacy issue here:
- Disregarding other objects' privacy
When accessing methods, fields, or properties of other classes, make sure that you do not interfere with private or protected members. Currently Groovy doesn't distinguish properly between public, private, and protected members, so watch out yourself.
As Tim Yates says on the linked question, it is not clear if that is a defect or a feature. Given that it could tend to break existing code, it seems unlikely to me that it will get "fixed" any time soon, if ever.
Creating private constructor typically has goal to prevent creating instance of the class from outside. Typically this is done if class provides other methods to create its instance, for example static factory method.
Examples:
java.util.Pattern
can be created using Pattern.compile()
If you however indeed want to work around the compiler's restrictions you can use reflection. I am not familiar enough with Groovy, but here is how you can do this in java.
Constructor c = World.class.getConstructor();
c.setAccessible(true); // This line grants you permission to access even private elements
World w = (World)c.newInstance();
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