You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@groovy.apache.org by "Eric Milles (JIRA)" <ji...@apache.org> on 2018/01/05 16:55:02 UTC

[jira] [Updated] (GROOVY-8433) Anonymous inner class results in cast exception with @Category applied

     [ https://issues.apache.org/jira/browse/GROOVY-8433?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel ]

Eric Milles updated GROOVY-8433:
--------------------------------
    Description: 
In working with a library that required extension of an SAM type to add a function binding, I thought of using {{@Category}} to soften the integration.  What I found is that the implicit {{this}} parameter that is passed to the constructor of an anon. inner class is being transformed from the containing class to the category class due to the application of the {{@Category}} transform.

Below I have boiled it down to the fewest moving parts I can.  {{LibraryContext}} is the type that needs functions bound to it and the interface for doing so is {{LibraryFunction}} which requires constructor params so I cannot use SAM Closure coercion.  My first take was to create {{Factory.Binder}} to get the details out of the way.  That resulted in the cast exception below.  When I converted {{Binder}} to define static methods with a first param of {{LibraryContext}} all is well.

So I thought I would raise the issue that anon. inners and {{@Category}} are not currently compatible.

{code}
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
	at scripts.Factory$Binder.bindStringFunction(CategoryTransform.groovy:18)
	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy:10)
	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy)
	at scripts.Factory.create(CategoryTransform.groovy:9)
	at scripts.Factory$create.call(Unknown Source)
	at scripts.CategoryTransform.run(CategoryTransform.groovy:42)
{code}

{code:java}
package scripts

class Factory {

  private Factory() {}

  static LibraryContext create() {
    LibraryContext context = new LibraryContext()
    use (Binder) {
      context.bindStringFunction('', { String[] strings -> '' })
    }
    return context
  }

  @Category(LibraryContext)
  private static class Binder {
    void bindStringFunction(String name, java.util.function.Function<String[], String> func) {
      def stringFunction = new LibarayFunction(name, 0) { // cast exception here due to implicit first param of "this"
        @Override
        String compute(String... args) {
            func.apply(args)
        }
      }

      this.bind(name, stringFunction)
    }
  }
}

class LibraryContext {
  void bind(String name, Object value) {
  }
}

abstract class LibarayFunction {
  LibarayFunction(String name, int argc) {
  }

  abstract String compute(String... argv);
}

Factory.create()
{code}


  was:
In working with a library that required extension of an SAM type to add a function binding, I thought of using @Category to soften the integration.  What I found is that the implicit "this" parameter that is passed to the constructor of an anon. inner class is being transformed from the containing class to the category class due to the application of the @Category transform.

Below I have boiled it down to the fewest moving parts I can.  {{LibraryContext}} is the type that needs functions bound to it and the interface for doing so is {{LibraryFunction}} which requires constructor params so I cannot use SAM Closure coercion.  My first take was to create {{Factory.Binder}} to get the details out of the way.  That resulted in the cast exception below.  When I converted {{Binder}} to define static methods with a first param of {{LibraryContext}} all is well.

So I thought I would raise the issue that anon. inners and @Category are not currently compatible.

{code}
Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
	at scripts.Factory$Binder.bindStringFunction(CategoryTransform.groovy:18)
	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy:10)
	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy)
	at scripts.Factory.create(CategoryTransform.groovy:9)
	at scripts.Factory$create.call(Unknown Source)
	at scripts.CategoryTransform.run(CategoryTransform.groovy:42)
{code}

{code:java}
package scripts

class Factory {

  private Factory() {}

  static LibraryContext create() {
    LibraryContext context = new LibraryContext()
    use (Binder) {
      context.bindStringFunction('', { String[] strings -> '' })
    }
    return context
  }

  @Category(LibraryContext)
  private static class Binder {
    void bindStringFunction(String name, java.util.function.Function<String[], String> func) {
      def stringFunction = new LibarayFunction(name, 0) {
        @Override
        String compute(String... args) {
            func.apply(args)
        }
      }

      this.bind(name, stringFunction)
    }
  }
}

class LibraryContext {
  void bind(String name, Object value) {
  }
}

abstract class LibarayFunction {
  LibarayFunction(String name, int argc) {
  }

  abstract String compute(String... argv);
}

Factory.create()
{code}



> Anonymous inner class results in cast exception with @Category applied
> ----------------------------------------------------------------------
>
>                 Key: GROOVY-8433
>                 URL: https://issues.apache.org/jira/browse/GROOVY-8433
>             Project: Groovy
>          Issue Type: Bug
>            Reporter: Eric Milles
>
> In working with a library that required extension of an SAM type to add a function binding, I thought of using {{@Category}} to soften the integration.  What I found is that the implicit {{this}} parameter that is passed to the constructor of an anon. inner class is being transformed from the containing class to the category class due to the application of the {{@Category}} transform.
> Below I have boiled it down to the fewest moving parts I can.  {{LibraryContext}} is the type that needs functions bound to it and the interface for doing so is {{LibraryFunction}} which requires constructor params so I cannot use SAM Closure coercion.  My first take was to create {{Factory.Binder}} to get the details out of the way.  That resulted in the cast exception below.  When I converted {{Binder}} to define static methods with a first param of {{LibraryContext}} all is well.
> So I thought I would raise the issue that anon. inners and {{@Category}} are not currently compatible.
> {code}
> Caught: org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
> org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'scripts.LibraryContext@6a28ffa4' with class 'scripts.LibraryContext' to class 'scripts.Factory$Binder'
> 	at scripts.Factory$Binder.bindStringFunction(CategoryTransform.groovy:18)
> 	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy:10)
> 	at scripts.Factory$_create_closure1.doCall(CategoryTransform.groovy)
> 	at scripts.Factory.create(CategoryTransform.groovy:9)
> 	at scripts.Factory$create.call(Unknown Source)
> 	at scripts.CategoryTransform.run(CategoryTransform.groovy:42)
> {code}
> {code:java}
> package scripts
> class Factory {
>   private Factory() {}
>   static LibraryContext create() {
>     LibraryContext context = new LibraryContext()
>     use (Binder) {
>       context.bindStringFunction('', { String[] strings -> '' })
>     }
>     return context
>   }
>   @Category(LibraryContext)
>   private static class Binder {
>     void bindStringFunction(String name, java.util.function.Function<String[], String> func) {
>       def stringFunction = new LibarayFunction(name, 0) { // cast exception here due to implicit first param of "this"
>         @Override
>         String compute(String... args) {
>             func.apply(args)
>         }
>       }
>       this.bind(name, stringFunction)
>     }
>   }
> }
> class LibraryContext {
>   void bind(String name, Object value) {
>   }
> }
> abstract class LibarayFunction {
>   LibarayFunction(String name, int argc) {
>   }
>   abstract String compute(String... argv);
> }
> Factory.create()
> {code}



--
This message was sent by Atlassian JIRA
(v6.4.14#64029)