4

I have an abstract Java class MyAbstractClass with a private method. There is a concrete implementation MyConcreteClass.

public class MyAbstractClass {
    private void somePrivateMethod();
}

public class MyConcreteClass extends MyAbstractClass {
      // implementation details
}

In my groovy test class I have

class MyAbstractClassTest {

    void myTestMethod() {
        MyAbstractClass mac = new MyConcreteClass()
        mac.somePrivateMethod()
    }
}

I get an error that there is no such method signature for somePrivateMethod. I know groovy can call private methods but I'm guessing the problem is that the private method is in the super class, not MyConcreteClass. Is there a way to invoke a private method in the super class like this (other than using something like PrivateAccessor)?

thanks Jeff

Jeff Storey
  • 56,312
  • 72
  • 233
  • 406

1 Answers1

11

The fact that you can call private methods is a bug in the Groovy language, not a feature. However, I believe this bug was introduced deliberately as a form of compromise when making some changes to the way closures behave.

Even though you can call private methods, you should not, because hopefully one day this bug will be fixed, and if your program relies on calling private methods it will be broken.

If you really insist on (ab)using this undocumented behaviour, you could try using something like ReflectionUtils to call private methods in parent classes.

Another workaround is to provide a method in the concrete class that calls the private method in the parent class. For example, the following code "works", but it still relies on accessing private members, which is bad

class Parent {
  private foo() {println "foo"}
}

class Child extends Parent {
  public bar() {super.foo()}
}

new Child().bar()
Joman68
  • 2,248
  • 3
  • 34
  • 36
Dónal
  • 185,044
  • 174
  • 569
  • 824
  • 2
    Agree 100%. Privates are private for a reason. – Christian Semrau May 14 '10 at 15:20
  • 2
    I see where you're coming from, but if you've ever heard to Neal Ford talk, he actually calls this a feature and that private is a feature of the java language, not the feature of the java platform - though I could see it either way. But regardless of how you look at it, I think it is useful for limited cases in testing. I use it only in places where I would need to call PrivateAccessor (or ReflectionUtils). In this particular case, I want to execute a private readResolve method to make sure transient fields are properly reinitialized. – Jeff Storey May 14 '10 at 15:44
  • 1
    I've never heard of Neal Ford, though I'm very interested to hear how he justifies this stance. I don't think it's reasonable to consider this a feature because it's been accepted as a bug in the Groovy JIRA, and is not mentioned anywhere authorative (the Groovy website, Groovy books, etc.) as the expected behaviour as private. – Dónal May 14 '10 at 15:55
  • 1
    He's a big testing guy (writer of the Productive Programmer and architect at ThoughtWorks). But I do understand it being reported as a bug. But as long as this is not abused, it can really just be used as a shortcut for using the reflection utilities. – Jeff Storey May 14 '10 at 16:02
  • I know it's technically a bug. I just find it difficult that they will be able to successfully fix it without causing all sorts of compatibility problems. Maybe there will be a flag or something to keep it enabled. – Jeff Storey May 14 '10 at 16:19
  • It was suggested that they might wait until the next major release (2.0) because it's such a major change – Dónal May 14 '10 at 16:21
  • Fixing the "bug" would significantly impact the benefits of Spock testing, which is a major use of Groovy in the Java ecosystem. – orbfish Sep 06 '17 at 16:19
  • For an interesting consequence of this bug: https://github.com/nokeedev/gradle-native/issues/490 – Pedro Lamarão Dec 23 '21 at 19:16