Nirav Assar is an independent consultant and owner of solutionsfit, a consulting firm based in the Dallas-Fort Worth Area. He has consulted on several projects in various industries, such as financial, real estate, government, and retail. His expertise is based in several Java technologies like Grails, Groovy, Spring, and Seam. Agile philosophy is at the heart of his profession, and he enjoys sharing techniques and tools that help software people excel at their jobs. You may contact him at nirav@solutionsfit.com. View his blog at http://assarconsulting.blogspot.com/. Nirav is a DZone MVB and is not an employee of DZone and has posted 8 posts at DZone. You can read more from them at their website. View Full User Profile

Groovy Closures Do Not Have Access to Private Methods in a Super Class

08.25.2012
| 3059 views |
  • submit to reddit
Recently I came upon a groovy oddity. (At least it is perceived by me to be an oddity). Closures in a groovy class do not have access to a private method if that method is defined in the superclass. This seems odd paired against the fact that regular methods in a super class can access private method defined in the super class

Background

Groovy closures have the same scope access to class member variables and methods as a regular groovy method. In other words, closures are bound to variables in the scope they are defined. See the codehaus link for the official documentation:

http://groovy.codehaus.org/Closures

This implies that a closure will play by the rules of Object Orientation in the Java language. However, I found that closures do not have access to private methods that are defined in a super class.

The best way to demonstrate is through a short example from Grails. I have used TDD for the example. Note this is a dummy case with no business purpose. Later on I will offer a more reasonable scenario in the business context where I encountered this scenario.


Simple Groovy Example

Take a class that has a closure, a public method, and a private method. Then extend that class. Try and invoke the closure. We get an error.
package closure.access

class SendCheckService {

  def calendarService

  /**
   * Closure that invokes a private method
   */
  def closureToSendCheck = {
    sendPersonalCheck()
  }

  def regularMethod() {
    sendPersonalCheck()
  }

  /*
   * Private method that we want to see executed
   */
  private sendPersonalCheck() {
    println "Sending Personal Check"
  }
}

class FooService extends SendCheckService {

}
Here are some tests the demonstrate the error.
package closure.access

import grails.test.*

class SendCheckServiceTests extends GrailsUnitTestCase {

  def sendCheckService

  protected void setUp() {
    super.setUp()
    sendCheckService = new SendCheckService()
  }

  /**
   * Invocation of the closure from the super class prints out the message:
   * "Sending Personal Check"
   */
  void testClosureToSendCheck() {
    sendCheckService.closureToSendCheck()
  }

  /**
   * Invocation of the method from the super class prints out the message:
   * "Sending Personal Check"
   */
  void testRegularMethod() {
    sendCheckService.regularMethod()
  }

  /**
   * Invocation of the the closure from the subclass yields an error:
   * groovy.lang.MissingMethodException: No signature of method: closure.access.FooService.sendPersonalCheck()
   *   is applicable for argument types: () values: []
   * This essentially means it does not exists.
   */
  void testFoo_ClosureToSendCheck() {
    def fooService = new FooService()
    fooService.closureToSendCheck()
  }

  /**
   * Invocation of the method does not yield and error!
   */
  void testFoo_RegularMethod() {
    def fooService = new FooService()
    fooService.regularMethod()
  }
} 
All is Well
  • testClosureToSendCheck() executes fine where the closure can access the private method. This is as expected. It is all well and good because we have not extended class yet.
  • testRegularMethod() just demonstrates regular OO principles. A method is able to invoke private methods.
Not as Expected
  • testFoo_ClosureToSendCheck() invokes a subclass of SendCheckService. It calls the same closure, yet we get served up a MissingMethodException.
  • testFoo_RegularMethod() just contrasts testFoo_ClosureToSendCheck(). I invoked this test to show that we should be able to have closures access private methods because other regular methods can!
Why Even Try to Have a Closure Call A Private Method

This may be a double loop learning question any intelligent developer might ask. It questions why we need to even get into this mess. This is a valid point and should be explained.

It is optimal to use closures in an attempt to reuse existing template logic. Let me give a simple business problem.

Imagine we need to code a system that sends out various types of checks: personal checks and business checks. We have the stipulation that these two events must NEVER be done together. Only send a personal check at one instance, and send a business check at another time. However, they both need to follow the same logic. They must be sent on a business day (no holidays or weekends). Thus, we have a scenario where they need the same calendar logic, but it is needed separately.

Duplicate Logic

We could just code the calendar logic twice. (Remember sending business checks and personal checks together in one request cannot occur!)
package closure.access

class SendCheckService2 {

  def calendarService

  def triggerPersonalCheck () {
    if (calendarService.todayIsBusinessDay()) {
      sendPersonalCheck()  
    } else {
      println "DO NOTHING"
    }
  }

  def triggerBusinessCheck() {
    if (calendarService.todayIsBusinessDay()) {
      sendBusinessCheck()
    } else {
      println "DO NOTHING"
    }
  }

  private sendPersonalCheck() {
    println "Sending Personal Check"
  }

  private sendBusinessCheck() {
    println "Sending Business Check"
  }  
}
Use the DRY Principle

In order to avoid this and follow DRY, we can use closures. Create a method that accepts a closure, and pass it the code snippets to execute in a closure. As a result we have the calendar logic defined once, but executed separately upon a different code snippet.
package closure.access

class SendCheckService3 {

  def calendarService

  def triggerPersonalCheck() {
    checkIfBusinessDayAndExecute(sendBusinessCheck)
  }

  def triggerBusinessCheck() {
    checkIfBusinessDayAndExecute(sendBusinessCheck)
  }

  def checkIfBusinessDayAndExecute(Closure closure) {
    if (calendarService.todayIsBusinessDay()) {
      closure()
    } else {
      println "DO NOTHING"
    }
  }

  /**
   * This is now a closure we can pass around
   */
  def sendPersonalCheck = {
    println "Sending Personal Check"
  }

  /**
   * This is now a closure we can pass around
   */  
  def sendBusinessCheck = {
    println "Sending Business Check"
  }  
}
In my real world scenario where I encountered the closure issue, it happened that my closure was trying to execute a private method in an abstract class. This is where I observed the problem.

JVM Thoughts

I honestly do not know the gory details behind why closures in super classes cannot access private methods, but I have an idea. Groovy creates closures by compiling them as inner classes. Since the subclass extends the superclass and then contains a closure, the inner class does not have access to the super class' methods. The reason why a method has access, is because it is compiled as one instance of the class. The closure implementation is not that way (being a inner class), and thus this is why we see a violation of Object Oriented behavior.

If you have a better explanation or futher knowledge of the details behind this issue, please describe them in the comments. Thanks for taking the time to delve in this area.

Thanks to Scott Risk for helping with examples.
Published at DZone with permission of Nirav Assar, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

André Pankraz replied on Sun, 2012/08/26 - 1:26am

Hi,

I don't use Groovy, but you are right about your JVM thoughts.

I don't think that the Groovy Closures extend the Enclosing Class, but either way...this synthetic Closure Inner Class has no access rights to private fields or methods at bytecode level (or you must use reflection and don't have a SecurityManager activated).

It's the same in the Java world. The Java Bytecode compiler creates so called synthetic bridge methods in the Enclosing Class to enable such operations. (with names like access$0)

The Groovy compiler seems to miss this step.

Best ragards,
André

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.